Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6: (235 commits)
  [NETFILTER]: Add H.323 conntrack/NAT helper
  [TG3]: Don't mark tg3_test_registers() as returning const.
  [IPV6]: Cleanups for net/ipv6/addrconf.c (kzalloc, early exit) v2
  [IPV6]: Nearly complete kzalloc cleanup for net/ipv6
  [IPV6]: Cleanup of net/ipv6/reassambly.c
  [BRIDGE]: Remove duplicate const from is_link_local() argument type.
  [DECNET]: net/decnet/dn_route.c: fix inconsequent NULL checking
  [TG3]: make drivers/net/tg3.c:tg3_request_irq() static
  [BRIDGE]: use LLC to send STP
  [LLC]: llc_mac_hdr_init const arguments
  [BRIDGE]: allow show/store of group multicast address
  [BRIDGE]: use llc for receiving STP packets
  [BRIDGE]: stp timer to jiffies cleanup
  [BRIDGE]: forwarding remove unneeded preempt and bh diasables
  [BRIDGE]: netfilter inline cleanup
  [BRIDGE]: netfilter VLAN macro cleanup
  [BRIDGE]: netfilter dont use __constant_htons
  [BRIDGE]: netfilter whitespace
  [BRIDGE]: optimize frame pass up
  [BRIDGE]: use kzalloc
  ...
diff --git a/.gitignore b/.gitignore
index 3f8fb68..53e53f2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,3 +30,5 @@
 include/linux/compile.h
 include/linux/version.h
 
+# stgit generated dirs
+patches-*
diff --git a/CREDITS b/CREDITS
index 1f171f1..af70678 100644
--- a/CREDITS
+++ b/CREDITS
@@ -2813,6 +2813,8 @@
 P: 1024D/FCE635A4 88E8 F32F 7244 68BA 3958  5D40 99DA 5D2A FCE6 35A4
 D: V4L driver for W996[87]CF JPEG USB Dual Mode Camera Chips
 D: V4L2 driver for SN9C10x PC Camera Controllers
+D: V4L2 driver for ET61X151 and ET61X251 PC Camera Controllers
+D: V4L2 driver for ZC0301 Image Processor and Control Chip
 S: Via Liberta' 41/A
 S: Osio Sotto, 24046, Bergamo
 S: Italy
diff --git a/Documentation/Changes b/Documentation/Changes
index fe5ae0f..b02f476 100644
--- a/Documentation/Changes
+++ b/Documentation/Changes
@@ -15,24 +15,6 @@
 Axel Boldt, Alessandro Sigala, and countless other users all over the
 'net).
 
-The latest revision of this document, in various formats, can always
-be found at <http://cyberbuzz.gatech.edu/kaboom/linux/Changes-2.4/>.
-
-Feel free to translate this document.  If you do so, please send me a
-URL to your translation for inclusion in future revisions of this
-document.
-
-Smotrite file <http://oblom.rnc.ru/linux/kernel/Changes.ru>, yavlyaushisya
-russkim perevodom dannogo documenta.
-
-Visite <http://www2.adi.uam.es/~ender/tecnico/> para obtener la traducción
-al español de este documento en varios formatos.
-
-Eine deutsche Version dieser Datei finden Sie unter
-<http://www.stefan-winter.de/Changes-2.4.0.txt>.
-
-Chris Ricker (kaboom@gatech.edu or chris.ricker@genetics.utah.edu).
-
 Current Minimal Requirements
 ============================
 
diff --git a/Documentation/dvb/avermedia.txt b/Documentation/dvb/avermedia.txt
index 068070f..8bab846 100644
--- a/Documentation/dvb/avermedia.txt
+++ b/Documentation/dvb/avermedia.txt
@@ -1,4 +1,3 @@
-
 HOWTO: Get An Avermedia DVB-T working under Linux
 	   ______________________________________________
 
@@ -137,11 +136,8 @@
    To  power  up  the  card,  load  the  following modules in the
    following order:
 
-     * insmod dvb-core.o
-     * modprobe bttv.o
-     * insmod bt878.o
-     * insmod dvb-bt8xx.o
-     * insmod sp887x.o
+     * modprobe bttv (normally loaded automatically)
+     * modprobe dvb-bt8xx (or place dvb-bt8xx in /etc/modules)
 
    Insertion  of  these  modules  into  the  running  kernel will
    activate the appropriate DVB device nodes. It is then possible
@@ -302,4 +298,4 @@
    Many  thanks to Nigel Pearson for the updates to this document
    since the recent revision of the driver.
 
-   January 29th 2004
+   February 14th 2006
diff --git a/Documentation/dvb/bt8xx.txt b/Documentation/dvb/bt8xx.txt
index 52ed462..4e7614e 100644
--- a/Documentation/dvb/bt8xx.txt
+++ b/Documentation/dvb/bt8xx.txt
@@ -1,118 +1,78 @@
-How to get the Nebula, PCTV, FusionHDTV Lite and Twinhan DST cards working
-==========================================================================
+How to get the bt8xx cards working
+==================================
 
-This class of cards has a bt878a as the PCI interface, and
-require the bttv driver.
+1) General information
+======================
 
-Please pay close attention to the warning about the bttv module
-options below for the DST card.
+This class of cards has a bt878a as the PCI interface, and require the bttv driver
+for accessing the i2c bus and the gpio pins of the bt8xx chipset.
+Please see Documentation/dvb/cards.txt => o Cards based on the Conexant Bt8xx PCI bridge:
 
-1) General informations
-=======================
-
-These drivers require the bttv driver to provide the means to access
-the i2c bus and the gpio pins of the bt8xx chipset.
-
-Because of this, you need to enable
-"Device drivers" => "Multimedia devices"
-  => "Video For Linux" => "BT848 Video For Linux"
-
-Furthermore you need to enable
-"Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices"
-  => "DVB for Linux" "DVB Core Support" "BT8xx based PCI cards"
+Compiling kernel please enable:
+a.)"Device drivers" => "Multimedia devices" => "Video For Linux" => "BT848 Video For Linux"
+b.)"Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices"
+ => "DVB for Linux" "DVB Core Support" "Bt8xx based PCI Cards"
 
 2) Loading Modules
 ==================
 
-In general you need to load the bttv driver, which will handle the gpio and
-i2c communication for us, plus the common dvb-bt8xx device driver.
-The frontends for Nebula (nxt6000), Pinnacle PCTV (cx24110), TwinHan (dst),
-FusionHDTV DVB-T Lite (mt352) and FusionHDTV5 Lite (lgdt330x) are loaded
-automatically by the dvb-bt8xx device driver.
+In default cases bttv is loaded automatically.
+To load the backend either place dvb-bt8xx in etc/modules, or apply manually:
 
-3a) Nebula / Pinnacle PCTV / FusionHDTV Lite
----------------------------------------------
+	$ modprobe dvb-bt8xx
 
-   $ modprobe bttv (normally bttv is being loaded automatically by kmod)
-   $ modprobe dvb-bt8xx
+All frontends will be loaded automatically.
+People running udev please see Documentation/dvb/udev.txt.
 
-(or just place dvb-bt8xx in /etc/modules for automatic loading)
+In the following cases overriding the PCI type detection for dvb-bt8xx might be necessary:
 
+2a) Running TwinHan and Clones
+------------------------------
 
-3b) TwinHan and Clones
+	$ modprobe bttv card=113
+	$ modprobe dvb-bt8xx
+	$ modprobe dst
+
+Useful parameters for verbosity level and debugging the dst module:
+
+verbose=0:		messages are disabled
+	1:		only error messages are displayed
+	2:		notifications are displayed
+	3:		other useful messages are displayed
+	4:		debug setting
+dst_addons=0:		card is a free to air (FTA) card only
+	   0x20:	card has a conditional access slot for scrambled channels
+
+The autodetected values are determined by the cards' "response string".
+In your logs see f. ex.: dst_get_device_id: Recognize [DSTMCI].
+For bug reports please send in a complete log with verbose=4 activated.
+Please also see Documentation/dvb/ci.txt.
+
+2b) Running multiple cards
 --------------------------
 
-   $ modprobe bttv card=0x71
-   $ modprobe dvb-bt8xx
-   $ modprobe dst
+Examples of card ID's:
 
-The value 0x71 will override the PCI type detection for dvb-bt8xx,
-which  is necessary for TwinHan cards. Omission of this parameter might result
-in a system lockup.
+Pinnacle PCTV Sat:		 94
+Nebula Electronics Digi TV:	104
+pcHDTV HD-2000 TV:		112
+Twinhan DST and clones:		113
+Avermedia AverTV DVB-T 771:	123
+Avermedia AverTV DVB-T 761:	124
+DViCO FusionHDTV DVB-T Lite:	128
+DViCO FusionHDTV 5 Lite:	135
 
-If you're having an older card (blue color PCB) and card=0x71 locks up
-your machine, try using 0x68, too. If that does not work, ask on the
-mailing list.
-
-The DST module takes a couple of useful parameters.
-
-verbose takes values 0 to 4. These values control the verbosity level,
-and can be used to debug also.
-
-verbose=0 means complete disabling of messages
-	1 only error messages are displayed
-	2 notifications are also displayed
-	3 informational messages are also displayed
-	4 debug setting
-
-dst_addons takes values 0 and 0x20. A value of 0 means it is a FTA card.
-0x20 means it has a Conditional Access slot.
-
-The autodetected values are determined by the cards 'response string'
-which you can see in your logs e.g.
-
-dst_get_device_id: Recognise [DSTMCI]
-
-If you need to sent in bug reports on the dst, please do send in a complete
-log with the verbose=4 module parameter. For general usage, the default setting
-of verbose=1 is ideal.
-
-
-4) Multiple cards
---------------------------
-
-If you happen to be running multiple cards, it would be advisable to load
-the bttv module with the card id. This would help to solve any module loading
-problems that you might face.
-
-For example, if you have a Twinhan and Clones card along with a FusionHDTV5 Lite
-
-	$ modprobe bttv card=0x71 card=0x87
-
-Here the order of the card id is important and should be the same as that of the
-physical order of the cards. Here card=0x71 represents the Twinhan and clones
-and card=0x87 represents Fusion HDTV5 Lite. These arguments can also be
-specified in decimal, rather than hex:
-
+Notice: The order of the card ID should be uprising:
+Example:
 	$ modprobe bttv card=113 card=135
+	$ modprobe dvb-bt8xx
 
-Some examples of card-id's
+For a full list of card ID's please see Documentation/video4linux/CARDLIST.bttv.
+In case of further problems send questions to the mailing list: www.linuxdvb.org.
 
-Pinnacle Sat		0x5e  (94)
-Nebula Digi TV		0x68  (104)
-PC HDTV			0x70  (112)
-Twinhan			0x71  (113)
-FusionHDTV DVB-T Lite	0x80  (128)
-FusionHDTV5 Lite	0x87  (135)
-
-For a full list of card-id's, see the V4L Documentation within the kernel
-source:  linux/Documentation/video4linux/CARDLIST.bttv
-
-If you have problems with this please do ask on the mailing list.
-
---
 Authors: Richard Walker,
 	 Jamie Honan,
 	 Michael Hunold,
 	 Manu Abraham,
+	 Uwe Bugla,
 	 Michael Krufky
diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware
index 75c28a1..bb55f49 100644
--- a/Documentation/dvb/get_dvb_firmware
+++ b/Documentation/dvb/get_dvb_firmware
@@ -21,8 +21,9 @@
 use File::Temp qw/ tempdir /;
 use IO::Handle;
 
-@components = ( "sp8870", "sp887x", "tda10045", "tda10046", "av7110", "dec2000t",
-		"dec2540t", "dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004",
+@components = ( "sp8870", "sp887x", "tda10045", "tda10046",
+		"tda10046lifeview", "av7110", "dec2000t", "dec2540t",
+		"dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004",
 		"or51211", "or51132_qam", "or51132_vsb", "bluebird");
 
 # Check args
@@ -126,6 +127,24 @@
     $outfile;
 }
 
+sub tda10046lifeview {
+    my $sourcefile = "Drv_2.11.02.zip";
+    my $url = "http://www.lifeview.com.tw/drivers/pci_card/FlyDVB-T/$sourcefile";
+    my $hash = "1ea24dee4eea8fe971686981f34fd2e0";
+    my $outfile = "dvb-fe-tda10046.fw";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+
+    checkstandard();
+
+    wgetfile($sourcefile, $url);
+    unzip($sourcefile, $tmpdir);
+    extract("$tmpdir/LVHybrid.sys", 0x8b088, 24602, "$tmpdir/fwtmp");
+    verify("$tmpdir/fwtmp", $hash);
+    copy("$tmpdir/fwtmp", $outfile);
+
+    $outfile;
+}
+
 sub av7110 {
     my $sourcefile = "dvb-ttpci-01.fw-261d";
     my $url = "http://www.linuxtv.org/downloads/firmware/$sourcefile";
diff --git a/Documentation/dvb/readme.txt b/Documentation/dvb/readme.txt
index f5c50b2..0b0380c 100644
--- a/Documentation/dvb/readme.txt
+++ b/Documentation/dvb/readme.txt
@@ -20,11 +20,23 @@
 
 What's inside this directory:
 
+"avermedia.txt"
+contains detailed information about the
+Avermedia DVB-T cards. See also "bt8xx.txt".
+
+"bt8xx.txt"
+contains detailed information about the
+various bt8xx based "budget" DVB cards.
+
 "cards.txt"
 contains a list of supported hardware.
 
+"ci.txt"
+contains detailed information about the
+CI module as part from TwinHan cards and Clones.
+
 "contributors.txt"
-is the who-is-who of DVB development
+is the who-is-who of DVB development.
 
 "faq.txt"
 contains frequently asked questions and their answers.
@@ -34,19 +46,17 @@
 that require it.
 
 "ttusb-dec.txt"
-contains detailed informations about the
+contains detailed information about the
 TT DEC2000/DEC3000 USB DVB hardware.
 
-"bt8xx.txt"
-contains detailed installation instructions for the
-various bt8xx based "budget" DVB cards
-(Nebula, Pinnacle PCTV, Twinhan DST)
-
-"README.dibusb"
-contains detailed information about adapters
-based on DiBcom reference design.
-
 "udev.txt"
 how to get DVB and udev up and running.
 
+"README.dvb-usb"
+contains detailed information about the DVB USB cards.
+
+"README.flexcop"
+contains detailed information about the
+Technisat- and Flexcop B2C2 drivers.
+
 Good luck and have fun!
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 28a31c5e..afeaf62 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -196,3 +196,21 @@
 	users have complained indicating there is no more need for these
 	boards.  This should really be considered a last call.
 Who:	Ralf Baechle <ralf@linux-mips.org>
+
+---------------------------
+
+What:	USB driver API moves to EXPORT_SYMBOL_GPL
+When:	Febuary 2008
+Files:	include/linux/usb.h, drivers/usb/core/driver.c
+Why:	The USB subsystem has changed a lot over time, and it has been
+	possible to create userspace USB drivers using usbfs/libusb/gadgetfs
+	that operate as fast as the USB bus allows.  Because of this, the USB
+	subsystem will not be allowing closed source kernel drivers to
+	register with it, after this grace period is over.  If anyone needs
+	any help in converting their closed source drivers over to use the
+	userspace filesystems, please contact the
+	linux-usb-devel@lists.sourceforge.net mailing list, and the developers
+	there will be glad to help you out.
+Who:	Greg Kroah-Hartman <gregkh@suse.de>
+
+---------------------------
diff --git a/Documentation/usb/et61x251.txt b/Documentation/usb/et61x251.txt
index b44dda4..2934028 100644
--- a/Documentation/usb/et61x251.txt
+++ b/Documentation/usb/et61x251.txt
@@ -176,6 +176,14 @@
                 1 = force memory unmapping (save memory)
 Default:        0
 -------------------------------------------------------------------------------
+Name:           frame_timeout
+Type:           uint array (min = 0, max = 64)
+Syntax:         <n[,...]>
+Description:    Timeout for a video frame in seconds. This parameter is
+                specific for each detected camera. This parameter can be
+                changed at runtime thanks to the /sys filesystem interface.
+Default:        2
+-------------------------------------------------------------------------------
 Name:           debug
 Type:           ushort
 Syntax:         <n>
@@ -266,7 +274,7 @@
 
 
 10. Notes for V4L2 application developers
-========================================
+=========================================
 This driver follows the V4L2 API specifications. In particular, it enforces two
 rules:
 
diff --git a/Documentation/usb/sn9c102.txt b/Documentation/usb/sn9c102.txt
index c6b7641..b957bea 100644
--- a/Documentation/usb/sn9c102.txt
+++ b/Documentation/usb/sn9c102.txt
@@ -196,6 +196,14 @@
                 1 = force memory unmapping (save memory)
 Default:        0
 -------------------------------------------------------------------------------
+Name:           frame_timeout
+Type:           uint array (min = 0, max = 64)
+Syntax:         <n[,...]>
+Description:    Timeout for a video frame in seconds. This parameter is
+                specific for each detected camera. This parameter can be
+                changed at runtime thanks to the /sys filesystem interface.
+Default:        2
+-------------------------------------------------------------------------------
 Name:           debug
 Type:           ushort
 Syntax:         <n> 
@@ -321,6 +329,7 @@
 ---------  ----------
 0x0c45     0x6001
 0x0c45     0x6005
+0x0c45     0x6007
 0x0c45     0x6009
 0x0c45     0x600d
 0x0c45     0x6024
@@ -370,6 +379,7 @@
 MI-0343     Micron Technology, Inc.
 OV7630      OmniVision Technologies, Inc.
 PAS106B     PixArt Imaging, Inc.
+PAS202BCA   PixArt Imaging, Inc.
 PAS202BCB   PixArt Imaging, Inc.
 TAS5110C1B  Taiwan Advanced Sensor Corporation
 TAS5130D1B  Taiwan Advanced Sensor Corporation
@@ -493,6 +503,7 @@
 order):
 
 - Luca Capello for the donation of a webcam;
+- Philippe Coval for having helped testing the PAS202BCA image sensor;
 - Joao Rodrigo Fuzaro, Joao Limirio, Claudio Filho and Caio Begotti for the
   donation of a webcam;
 - Jon Hollstrom for the donation of a webcam;
diff --git a/Documentation/usb/zc0301.txt b/Documentation/usb/zc0301.txt
new file mode 100644
index 0000000..f55262c
--- /dev/null
+++ b/Documentation/usb/zc0301.txt
@@ -0,0 +1,254 @@
+
+                    ZC0301 Image Processor and Control Chip
+                                Driver for Linux
+                    =======================================
+
+                               - Documentation -
+
+
+Index
+=====
+1.  Copyright
+2.  Disclaimer
+3.  License
+4.  Overview and features
+5.  Module dependencies
+6.  Module loading
+7.  Module parameters
+8.  Supported devices
+9.  Notes for V4L2 application developers
+10. Contact information
+11. Credits
+
+
+1. Copyright
+============
+Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>
+
+
+2. Disclaimer
+=============
+This software is not developed or sponsored by Z-Star Microelectronics Corp.
+Trademarks are property of their respective owner.
+
+
+3. License
+==========
+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.
+
+
+4. Overview and features
+========================
+This driver supports the video interface of the devices mounting the ZC0301
+Image Processor and Control Chip.
+
+The driver relies on the Video4Linux2 and USB core modules. It has been
+designed to run properly on SMP systems as well.
+
+The latest version of the ZC0301 driver can be found at the following URL:
+http://www.linux-projects.org/
+
+Some of the features of the driver are:
+
+- full compliance with the Video4Linux2 API (see also "Notes for V4L2
+  application developers" paragraph);
+- available mmap or read/poll methods for video streaming through isochronous
+  data transfers;
+- automatic detection of image sensor;
+- video format is standard JPEG;
+- dynamic driver control thanks to various module parameters (see "Module
+  parameters" paragraph);
+- up to 64 cameras can be handled at the same time; they can be connected and
+  disconnected from the host many times without turning off the computer, if
+  the system supports hotplugging;
+
+
+5. Module dependencies
+======================
+For it to work properly, the driver needs kernel support for Video4Linux and
+USB.
+
+The following options of the kernel configuration file must be enabled and
+corresponding modules must be compiled:
+
+	# Multimedia devices
+	#
+	CONFIG_VIDEO_DEV=m
+
+	# USB support
+	#
+	CONFIG_USB=m
+
+In addition, depending on the hardware being used, the modules below are
+necessary:
+
+	# USB Host Controller Drivers
+	#
+	CONFIG_USB_EHCI_HCD=m
+	CONFIG_USB_UHCI_HCD=m
+	CONFIG_USB_OHCI_HCD=m
+
+The ZC0301 controller also provides a built-in microphone interface. It is
+supported by the USB Audio driver thanks to the ALSA API:
+
+	# Sound
+	#
+	CONFIG_SOUND=y
+
+	# Advanced Linux Sound Architecture
+	#
+	CONFIG_SND=m
+
+	# USB devices
+	#
+	CONFIG_SND_USB_AUDIO=m
+
+And finally:
+
+	# USB Multimedia devices
+	#
+	CONFIG_USB_ZC0301=m
+
+
+6. Module loading
+=================
+To use the driver, it is necessary to load the "zc0301" module into memory
+after every other module required: "videodev", "usbcore" and, depending on
+the USB host controller you have, "ehci-hcd", "uhci-hcd" or "ohci-hcd".
+
+Loading can be done as shown below:
+
+	[root@localhost home]# modprobe zc0301
+
+At this point the devices should be recognized. You can invoke "dmesg" to
+analyze kernel messages and verify that the loading process has gone well:
+
+	[user@localhost home]$ dmesg
+
+
+7. Module parameters
+====================
+Module parameters are listed below:
+-------------------------------------------------------------------------------
+Name:           video_nr
+Type:           short array (min = 0, max = 64)
+Syntax:         <-1|n[,...]>
+Description:    Specify V4L2 minor mode number:
+                -1 = use next available
+                 n = use minor number n
+                You can specify up to 64 cameras this way.
+                For example:
+                video_nr=-1,2,-1 would assign minor number 2 to the second
+                registered camera and use auto for the first one and for every
+                other camera.
+Default:        -1
+-------------------------------------------------------------------------------
+Name:           force_munmap
+Type:           bool array (min = 0, max = 64)
+Syntax:         <0|1[,...]>
+Description:    Force the application to unmap previously mapped buffer memory
+                before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
+                all the applications support this feature. This parameter is
+                specific for each detected camera.
+                0 = do not force memory unmapping
+                1 = force memory unmapping (save memory)
+Default:        0
+-------------------------------------------------------------------------------
+Name:           frame_timeout
+Type:           uint array (min = 0, max = 64)
+Syntax:         <n[,...]>
+Description:    Timeout for a video frame in seconds. This parameter is
+                specific for each detected camera. This parameter can be
+                changed at runtime thanks to the /sys filesystem interface.
+Default:        2
+-------------------------------------------------------------------------------
+Name:           debug
+Type:           ushort
+Syntax:         <n>
+Description:    Debugging information level, from 0 to 3:
+                0 = none (use carefully)
+                1 = critical errors
+                2 = significant informations
+                3 = more verbose messages
+                Level 3 is useful for testing only, when only one device
+                is used at the same time. It also shows some more informations
+                about the hardware being detected. This module parameter can be
+                changed at runtime thanks to the /sys filesystem interface.
+Default:        2
+-------------------------------------------------------------------------------
+
+
+8. Supported devices
+====================
+None of the names of the companies as well as their products will be mentioned
+here. They have never collaborated with the author, so no advertising.
+
+From the point of view of a driver, what unambiguously identify a device are
+its vendor and product USB identifiers. Below is a list of known identifiers of
+devices mounting the ZC0301 Image Processor and Control Chips:
+
+Vendor ID  Product ID
+---------  ----------
+0x041e     0x4017
+0x041e     0x401c
+0x041e     0x401e
+0x041e     0x4034
+0x041e     0x4035
+0x046d     0x08ae
+0x0ac8     0x0301
+0x10fd     0x8050
+
+The list above does not imply that all those devices work with this driver: up
+until now only the ones that mount the following image sensors are supported;
+kernel messages will always tell you whether this is the case:
+
+Model       Manufacturer
+-----       ------------
+PAS202BCB   PixArt Imaging, Inc.
+
+
+9. Notes for V4L2 application developers
+========================================
+This driver follows the V4L2 API specifications. In particular, it enforces two
+rules:
+
+- exactly one I/O method, either "mmap" or "read", is associated with each
+file descriptor. Once it is selected, the application must close and reopen the
+device to switch to the other I/O method;
+
+- although it is not mandatory, previously mapped buffer memory should always
+be unmapped before calling any "VIDIOC_S_CROP" or "VIDIOC_S_FMT" ioctl's.
+The same number of buffers as before will be allocated again to match the size
+of the new video frames, so you have to map the buffers again before any I/O
+attempts on them.
+
+
+10. Contact information
+=======================
+The author may be contacted by e-mail at <luca.risolia@studio.unibo.it>.
+
+GPG/PGP encrypted e-mail's are accepted. The GPG key ID of the author is
+'FCE635A4'; the public 1024-bit key should be available at any keyserver;
+the fingerprint is: '88E8 F32F 7244 68BA 3958  5D40 99DA 5D2A FCE6 35A4'.
+
+
+11. Credits
+===========
+- Informations about the chip internals needed to enable the I2C protocol have
+  been taken from the documentation of the ZC030x Video4Linux1 driver written
+  by Andrew Birkett <andy@nobugs.org>;
+- The initialization values of the ZC0301 controller connected to the PAS202BCB
+  image sensor have been taken from the SPCA5XX driver maintained by
+  Michel Xhaard <mxhaard@magic.fr>.
diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88
index 8bea3fb..3b39a91 100644
--- a/Documentation/video4linux/CARDLIST.cx88
+++ b/Documentation/video4linux/CARDLIST.cx88
@@ -43,3 +43,5 @@
  42 -> digitalnow DNTV Live! DVB-T Pro                     [1822:0025]
  43 -> KWorld/VStream XPert DVB-T with cx22702             [17de:08a1]
  44 -> DViCO FusionHDTV DVB-T Dual Digital                 [18ac:db50,18ac:db54]
+ 45 -> KWorld HardwareMpegTV XPert                         [17de:0840]
+ 46 -> DViCO FusionHDTV DVB-T Hybrid                       [18ac:db40,18ac:db44]
diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx
index a0c7cad..a302668 100644
--- a/Documentation/video4linux/CARDLIST.em28xx
+++ b/Documentation/video4linux/CARDLIST.em28xx
@@ -8,3 +8,4 @@
   7 -> Leadtek Winfast USB II                   (em2800)
   8 -> Kworld USB2800                           (em2800)
   9 -> Pinnacle Dazzle DVC 90                   (em2820/em2840) [2304:0207]
+ 12 -> Kworld PVR TV 2800 RF                    (em2820/em2840)
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
index da4fb89..8c71954 100644
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -83,3 +83,12 @@
  82 -> MSI TV@Anywhere plus                     [1462:6231]
  83 -> Terratec Cinergy 250 PCI TV              [153b:1160]
  84 -> LifeView FlyDVB Trio                     [5168:0319]
+ 85 -> AverTV DVB-T 777                         [1461:2c05]
+ 86 -> LifeView FlyDVB-T                        [5168:0301]
+ 87 -> ADS Instant TV Duo Cardbus PTV331        [0331:1421]
+ 88 -> Tevion/KWorld DVB-T 220RF                [17de:7201]
+ 89 -> ELSA EX-VISION 700TV                     [1048:226c]
+ 90 -> Kworld ATSC110                           [17de:7350]
+ 91 -> AVerMedia A169 B                         [1461:7360]
+ 92 -> AVerMedia A169 B1                        [1461:6360]
+ 93 -> Medion 7134 Bridge #2                    [16be:0005]
diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner
index f6d0cf7..1bcdac6 100644
--- a/Documentation/video4linux/CARDLIST.tuner
+++ b/Documentation/video4linux/CARDLIST.tuner
@@ -64,8 +64,10 @@
 tuner=63 - Philips FMD1216ME MK3 Hybrid Tuner
 tuner=64 - LG TDVS-H062F/TUA6034
 tuner=65 - Ymec TVF66T5-B/DFF
-tuner=66 - LG NTSC (TALN mini series)
+tuner=66 - LG TALN series
 tuner=67 - Philips TD1316 Hybrid Tuner
 tuner=68 - Philips TUV1236D ATSC/NTSC dual in
-tuner=69 - Tena TNF 5335 MF
+tuner=69 - Tena TNF 5335 and similar models
 tuner=70 - Samsung TCPN 2121P30A
+tuner=71 - Xceive xc3028
+tuner=72 - Thomson FE6600
diff --git a/Documentation/video4linux/README.cpia2 b/Documentation/video4linux/README.cpia2
new file mode 100644
index 0000000..ce8213d
--- /dev/null
+++ b/Documentation/video4linux/README.cpia2
@@ -0,0 +1,130 @@
+$Id: README,v 1.7 2005/08/29 23:39:57 sbertin Exp $
+
+1. Introduction
+
+	This is a driver for STMicroelectronics's CPiA2 (second generation
+Colour Processor Interface ASIC) based cameras. This camera outputs an MJPEG
+stream at up to vga size. It implements the Video4Linux interface as much as
+possible.  Since the V4L interface does not support compressed formats, only
+an mjpeg enabled application can be used with the camera. We have modified the
+gqcam application to view this stream.
+
+	The driver is implemented as two kernel modules. The cpia2 module
+contains the camera functions and the V4L interface.  The cpia2_usb module
+contains usb specific functions.  The main reason for this was the size of the
+module was getting out of hand, so I separted them.  It is not likely that
+there will be a parallel port version.
+
+FEATURES:
+   - Supports cameras with the Vision stv6410 (CIF) and stv6500 (VGA) cmos
+     sensors. I only have the vga sensor, so can't test the other.
+   - Image formats: VGA, QVGA, CIF, QCIF, and a number of sizes in between.
+     VGA and QVGA are the native image sizes for the VGA camera. CIF is done
+     in the coprocessor by scaling QVGA.  All other sizes are done by clipping.
+   - Palette: YCrCb, compressed with MJPEG.
+   - Some compression parameters are settable.
+   - Sensor framerate is adjustable (up to 30 fps CIF, 15 fps VGA).
+   - Adjust brightness, color, contrast while streaming.
+   - Flicker control settable for 50 or 60 Hz mains frequency.
+
+2. Making and installing the stv672 driver modules:
+
+	Requirements:
+	-------------
+	This should work with 2.4 (2.4.23 and later) and 2.6 kernels, but has
+only been tested on 2.6.  Video4Linux must be either compiled into the kernel or
+available as a module.  Video4Linux2 is automatically detected and made
+available at compile time.
+
+	Compiling:
+	----------
+	As root, do a make install.  This will compile and install the modules
+into the media/video directory in the module tree. For 2.4 kernels, use
+Makefile_2.4 (aka do make -f Makefile_2.4 install).
+
+	Setup:
+	------
+	Use 'modprobe cpia2' to load and 'modprobe -r cpia2' to unload. This
+may be done automatically by your distribution.
+
+3. Driver options
+
+	Option		Description
+	------		-----------
+	video_nr	video device to register (0=/dev/video0, etc)
+			range -1 to 64.  default is -1 (first available)
+			If you have more than 1 camera, this MUST be -1.
+	buffer_size	Size for each frame buffer in bytes (default 68k)
+	num_buffers	Number of frame buffers (1-32, default 3)
+	alternate	USB Alternate (2-7, default 7)
+	flicker_freq	Frequency for flicker reduction(50 or 60, default 60)
+	flicker_mode	0 to disable, or 1 to enable flicker reduction.
+			(default 0). This is only effective if the camera
+			uses a stv0672 coprocessor.
+
+	Setting the options:
+	--------------------
+	If you are using modules, edit /etc/modules.conf and add an options
+line like this:
+	options cpia2 num_buffers=3 buffer_size=65535
+
+	If the driver is compiled into the kernel, at boot time specify them
+like this:
+	cpia2.num_buffers=3 cpia2.buffer_size=65535
+
+	What buffer size should I use?
+	------------------------------
+	The maximum image size depends on the alternate you choose, and the
+frame rate achieved by the camera.  If the compression engine is able to
+keep up with the frame rate, the maximum image size is given by the table
+below.
+	The compression engine starts out at maximum compression, and will
+increase image quality until it is close to the size in the table.  As long
+as the compression engine can keep up with the frame rate, after a short time
+the images will all be about the size in the table, regardless of resolution.
+	At low alternate settings, the compression engine may not be able to
+compress the image enough and will reduce the frame rate by producing larger
+images.
+	The default of 68k should be good for most users.  This will handle
+any alternate at frame rates down to 15fps.  For lower frame rates, it may
+be necessary to increase the buffer size to avoid having frames dropped due
+to insufficient space.
+
+			     Image size(bytes)
+	Alternate  bytes/ms   15fps    30fps
+	    2         128      8533     4267
+	    3         384     25600    12800
+	    4         640     42667    21333
+	    5         768     51200    25600
+	    6         896     59733    29867
+	    7        1023     68200    34100
+
+	How many buffers should I use?
+	------------------------------
+	For normal streaming, 3 should give the best results.  With only 2,
+it is possible for the camera to finish sending one image just after a
+program has started reading the other.  If this happens, the driver must drop
+a frame.  The exception to this is if you have a heavily loaded machine.  In
+this case use 2 buffers.  You are probably not reading at the full frame rate.
+If the camera can send multiple images before a read finishes, it could
+overwrite the third buffer before the read finishes, leading to a corrupt
+image.  Single and double buffering have extra checks to avoid overwriting.
+
+4. Using the camera
+
+	We are providing a modified gqcam application to view the output. In
+order to avoid confusion, here it is called mview.  There is also the qx5view
+program which can also control the lights on the qx5 microscope. MJPEG Tools
+(http://mjpeg.sourceforge.net) can also be used to record from the camera.
+
+5. Notes to developers:
+
+   - This is a driver version stripped of the 2.4 back compatibility
+     and old MJPEG ioctl API. See cpia2.sf.net for 2.4 support.
+
+6. Thanks:
+
+   - Peter Pregler <Peter_Pregler@email.com>,
+     Scott J. Bertin <scottbertin@yahoo.com>, and
+     Jarl Totland <Jarl.Totland@bdc.no> for the original cpia driver, which
+     this one was modelled from.
diff --git a/Documentation/video4linux/cpia2_overview.txt b/Documentation/video4linux/cpia2_overview.txt
new file mode 100644
index 0000000..a6e5366
--- /dev/null
+++ b/Documentation/video4linux/cpia2_overview.txt
@@ -0,0 +1,38 @@
+			Programmer's View of Cpia2
+
+Cpia2 is the second generation video coprocessor from VLSI Vision Ltd (now a
+division of ST Microelectronics).  There are two versions.  The first is the
+STV0672, which is capable of up to 30 frames per second (fps) in frame sizes
+up to CIF, and 15 fps for VGA frames.  The STV0676 is an improved version,
+which can handle up to 30 fps VGA.  Both coprocessors can be attached to two
+CMOS sensors - the vvl6410 CIF sensor and the vvl6500 VGA sensor.  These will
+be referred to as the 410 and the 500 sensors, or the CIF and VGA sensors.
+
+The two chipsets operate almost identically.  The core is an 8051 processor,
+running two different versions of firmware.  The 672 runs the VP4 video
+processor code, the 676 runs VP5.  There are a few differences in register
+mappings for the two chips.  In these cases, the symbols defined in the
+header files are marked with VP4 or VP5 as part of the symbol name.
+
+The cameras appear externally as three sets of registers. Setting register
+values is the only way to control the camera.  Some settings are
+interdependant, such as the sequence required to power up the camera. I will
+try to make note of all of these cases.
+
+The register sets are called blocks.  Block 0 is the system block.  This
+section is always powered on when the camera is plugged in.  It contains
+registers that control housekeeping functions such as powering up the video
+processor.  The video processor is the VP block.  These registers control
+how the video from the sensor is processed.  Examples are timing registers,
+user mode (vga, qvga), scaling, cropping, framerates, and so on.  The last
+block is the video compressor (VC).  The video stream sent from the camera is
+compressed as Motion JPEG (JPEGA).  The VC controls all of the compression
+parameters.  Looking at the file cpia2_registers.h, you can get a full view
+of these registers and the possible values for most of them.
+
+One or more registers can be set or read by sending a usb control message to
+the camera.  There are three modes for this.  Block mode requests a number
+of contiguous registers.  Random mode reads or writes random registers with
+a tuple structure containing address/value pairs.  The repeat mode is only
+used by VP4 to load a firmware patch.  It contains a starting address and
+a sequence of bytes to be written into a gpio port.
\ No newline at end of file
diff --git a/MAINTAINERS b/MAINTAINERS
index 8db5c33..7a1cbda 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1524,12 +1524,6 @@
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
-LANMEDIA WAN CARD DRIVER
-P:	Andrew Stanley-Jones
-M:	asj@lanmedia.com
-W:	http://www.lanmedia.com/
-S:	Supported
- 
 LAPB module
 P:	Henner Eisen
 M:	eis@baty.hanse.de
@@ -2902,6 +2896,14 @@
 W:	http://www.linux-projects.org
 S:	Maintained
 
+USB ZC0301 DRIVER
+P:	Luca Risolia
+M:	luca.risolia@studio.unibo.it
+L:	linux-usb-devel@lists.sourceforge.net
+L:	video4linux-list@redhat.com
+W:	http://www.linux-projects.org
+S:	Maintained
+
 USB ZD1201 DRIVER
 P:	Jeroen Vreeken
 M:	pe1rxq@amsat.org
diff --git a/README b/README
index 0d318ab..05e0555 100644
--- a/README
+++ b/README
@@ -74,7 +74,7 @@
    whatever the kernel-du-jour happens to be.
 
  - You can also upgrade between 2.6.xx releases by patching.  Patches are
-   distributed in the traditional gzip and the new bzip2 format.  To
+   distributed in the traditional gzip and the newer bzip2 format.  To
    install by patching, get all the newer patch files, enter the
    top level directory of the kernel source (linux-2.6.xx) and execute:
 
diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c
index d31b1cb..2360940 100644
--- a/arch/arm/common/locomo.c
+++ b/arch/arm/common/locomo.c
@@ -788,6 +788,8 @@
 	if (!mem)
 		return -EINVAL;
 	irq = platform_get_irq(dev, 0);
+	if (irq < 0)
+		return -ENXIO;
 
 	return __locomo_probe(&dev->dev, mem, irq);
 }
diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index 1475089..93352f6 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -943,6 +943,8 @@
 	if (!mem)
 		return -EINVAL;
 	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return -ENXIO;
 
 	return __sa1111_probe(&pdev->dev, mem, irq);
 }
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
index 4303d98..d13270c 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -202,11 +202,6 @@
 /*
  * CLCD support.
  */
-#define SYS_CLCD_MODE_MASK	(3 << 0)
-#define SYS_CLCD_MODE_888	(0 << 0)
-#define SYS_CLCD_MODE_5551	(1 << 0)
-#define SYS_CLCD_MODE_565_RLSB	(2 << 0)
-#define SYS_CLCD_MODE_565_BLSB	(3 << 0)
 #define SYS_CLCD_NLCDIOON	(1 << 2)
 #define SYS_CLCD_VDDPOSSWITCH	(1 << 3)
 #define SYS_CLCD_PWR3V5SWITCH	(1 << 4)
@@ -360,29 +355,10 @@
 	void __iomem *sys_clcd = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_CLCD_OFFSET;
 	u32 val;
 
+	/*
+	 * Enable the PSUs
+	 */
 	val = readl(sys_clcd);
-	val &= ~SYS_CLCD_MODE_MASK;
-
-	switch (fb->fb.var.green.length) {
-	case 5:
-		val |= SYS_CLCD_MODE_5551;
-		break;
-	case 6:
-		val |= SYS_CLCD_MODE_565_RLSB;
-		break;
-	case 8:
-		val |= SYS_CLCD_MODE_888;
-		break;
-	}
-
-	/*
-	 * Set the MUX
-	 */
-	writel(val, sys_clcd);
-
-	/*
-	 * And now enable the PSUs
-	 */
 	val |= SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH;
 	writel(val, sys_clcd);
 }
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index 3cbe6e9..1629c3a 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -1,49 +1,87 @@
 #
 # Automatically generated make config: don't edit
 #
+CONFIG_X86_32=y
+CONFIG_SEMAPHORE_SLEEPERS=y
 CONFIG_X86=y
 CONFIG_MMU=y
-CONFIG_UID16=y
 CONFIG_GENERIC_ISA_DMA=y
+CONFIG_GENERIC_IOMAP=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_DMI=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
+# CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
-CONFIG_AUDIT=y
-CONFIG_AUDITSYSCALL=y
-CONFIG_LOG_BUF_SHIFT=15
-CONFIG_HOTPLUG=y
-# CONFIG_IKCONFIG is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_UID16=y
+CONFIG_VM86=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
 #
 CONFIG_MODULES=y
-# CONFIG_MODULE_UNLOAD is not set
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
 CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# Block layer
+#
+# CONFIG_LBD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
 
 #
 # Processor type and features
@@ -66,43 +104,50 @@
 # CONFIG_MPENTIUMII is not set
 # CONFIG_MPENTIUMIII is not set
 # CONFIG_MPENTIUMM is not set
-CONFIG_MPENTIUM4=y
+# CONFIG_MPENTIUM4 is not set
 # CONFIG_MK6 is not set
-# CONFIG_MK7 is not set
+CONFIG_MK7=y
 # CONFIG_MK8 is not set
 # CONFIG_MCRUSOE is not set
 # CONFIG_MEFFICEON is not set
 # CONFIG_MWINCHIPC6 is not set
 # CONFIG_MWINCHIP2 is not set
 # CONFIG_MWINCHIP3D is not set
+# CONFIG_MGEODEGX1 is not set
+# CONFIG_MGEODE_LX is not set
 # CONFIG_MCYRIXIII is not set
 # CONFIG_MVIAC3_2 is not set
 # CONFIG_X86_GENERIC is not set
 CONFIG_X86_CMPXCHG=y
 CONFIG_X86_XADD=y
-CONFIG_X86_L1_CACHE_SHIFT=7
+CONFIG_X86_L1_CACHE_SHIFT=6
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_X86_WP_WORKS_OK=y
 CONFIG_X86_INVLPG=y
 CONFIG_X86_BSWAP=y
 CONFIG_X86_POPAD_OK=y
+CONFIG_X86_CMPXCHG64=y
 CONFIG_X86_GOOD_APIC=y
 CONFIG_X86_INTEL_USERCOPY=y
 CONFIG_X86_USE_PPRO_CHECKSUM=y
+CONFIG_X86_USE_3DNOW=y
+CONFIG_X86_TSC=y
 # CONFIG_HPET_TIMER is not set
-# CONFIG_HPET_EMULATE_RTC is not set
-CONFIG_SMP=y
-CONFIG_NR_CPUS=8
-CONFIG_SCHED_SMT=y
-CONFIG_PREEMPT=y
+# CONFIG_SMP is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_X86_UP_APIC=y
+CONFIG_X86_UP_IOAPIC=y
 CONFIG_X86_LOCAL_APIC=y
 CONFIG_X86_IO_APIC=y
-CONFIG_X86_TSC=y
 CONFIG_X86_MCE=y
 CONFIG_X86_MCE_NONFATAL=y
-CONFIG_X86_MCE_P4THERMAL=y
+# CONFIG_X86_MCE_P4THERMAL is not set
 # CONFIG_TOSHIBA is not set
 # CONFIG_I8K is not set
+# CONFIG_X86_REBOOTFIXUPS is not set
 # CONFIG_MICROCODE is not set
 # CONFIG_X86_MSR is not set
 # CONFIG_X86_CPUID is not set
@@ -111,41 +156,71 @@
 # Firmware Drivers
 #
 # CONFIG_EDD is not set
+# CONFIG_DELL_RBU is not set
+# CONFIG_DCDBAS is not set
 CONFIG_NOHIGHMEM=y
 # CONFIG_HIGHMEM4G is not set
 # CONFIG_HIGHMEM64G is not set
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_3G_OPT is not set
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_SPARSEMEM_STATIC=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
 # CONFIG_MATH_EMULATION is not set
 CONFIG_MTRR=y
 # CONFIG_EFI is not set
-CONFIG_IRQBALANCE=y
-CONFIG_HAVE_DEC_LOCK=y
-# CONFIG_REGPARM is not set
+CONFIG_REGPARM=y
+# CONFIG_SECCOMP is not set
+CONFIG_HZ_100=y
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=100
+# CONFIG_KEXEC is not set
+CONFIG_PHYSICAL_START=0x100000
+CONFIG_DOUBLEFAULT=y
 
 #
 # Power management options (ACPI, APM)
 #
 CONFIG_PM=y
+# CONFIG_PM_LEGACY is not set
+# CONFIG_PM_DEBUG is not set
 CONFIG_SOFTWARE_SUSPEND=y
+CONFIG_PM_STD_PARTITION="/dev/hda2"
 
 #
 # ACPI (Advanced Configuration and Power Interface) Support
 #
 CONFIG_ACPI=y
-CONFIG_ACPI_SLEEP=y
-CONFIG_ACPI_SLEEP_PROC_FS=y
-CONFIG_ACPI_AC=y
-CONFIG_ACPI_BATTERY=y
-CONFIG_ACPI_BUTTON=y
-CONFIG_ACPI_FAN=y
-CONFIG_ACPI_PROCESSOR=y
-CONFIG_ACPI_THERMAL=y
+# CONFIG_ACPI_SLEEP is not set
+# CONFIG_ACPI_AC is not set
+# CONFIG_ACPI_BATTERY is not set
+# CONFIG_ACPI_BUTTON is not set
+# CONFIG_ACPI_VIDEO is not set
+# CONFIG_ACPI_HOTKEY is not set
+# CONFIG_ACPI_FAN is not set
+# CONFIG_ACPI_PROCESSOR is not set
 # CONFIG_ACPI_ASUS is not set
+# CONFIG_ACPI_IBM is not set
 # CONFIG_ACPI_TOSHIBA is not set
+CONFIG_ACPI_BLACKLIST_YEAR=0
 # CONFIG_ACPI_DEBUG is not set
 CONFIG_ACPI_EC=y
 CONFIG_ACPI_POWER=y
 CONFIG_ACPI_SYSTEM=y
 # CONFIG_X86_PM_TIMER is not set
+# CONFIG_ACPI_CONTAINER is not set
 
 #
 # APM (Advanced Power Management) BIOS Support
@@ -168,19 +243,18 @@
 CONFIG_PCI_BIOS=y
 CONFIG_PCI_DIRECT=y
 CONFIG_PCI_MMCONFIG=y
-# CONFIG_PCI_USE_VECTOR is not set
-CONFIG_PCI_LEGACY_PROC=y
-CONFIG_PCI_NAMES=y
-CONFIG_ISA=y
-# CONFIG_EISA is not set
+# CONFIG_PCIEPORTBUS is not set
+# CONFIG_PCI_MSI is not set
+# CONFIG_PCI_LEGACY_PROC is not set
+CONFIG_ISA_DMA_API=y
+# CONFIG_ISA is not set
 # CONFIG_MCA is not set
 # CONFIG_SCx200 is not set
 
 #
-# PCMCIA/CardBus support
+# PCCARD (PCMCIA/CardBus) support
 #
-# CONFIG_PCMCIA is not set
-CONFIG_PCMCIA_PROBE=y
+# CONFIG_PCCARD is not set
 
 #
 # PCI Hotplug Support
@@ -191,8 +265,147 @@
 # Executable file formats
 #
 CONFIG_BINFMT_ELF=y
-CONFIG_BINFMT_AOUT=y
-CONFIG_BINFMT_MISC=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK is not set
+CONFIG_NETFILTER_XTABLES=y
+# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
+# CONFIG_NETFILTER_XT_TARGET_MARK is not set
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+# CONFIG_NETFILTER_XT_MATCH_HELPER is not set
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=y
+# CONFIG_IP_NF_CT_ACCT is not set
+# CONFIG_IP_NF_CONNTRACK_MARK is not set
+# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=y
+# CONFIG_IP_NF_IRC is not set
+# CONFIG_IP_NF_NETBIOS_NS is not set
+# CONFIG_IP_NF_TFTP is not set
+# CONFIG_IP_NF_AMANDA is not set
+# CONFIG_IP_NF_PPTP is not set
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=y
+# CONFIG_IP_NF_MATCH_IPRANGE is not set
+# CONFIG_IP_NF_MATCH_MULTIPORT is not set
+# CONFIG_IP_NF_MATCH_TOS is not set
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_DSCP is not set
+# CONFIG_IP_NF_MATCH_AH_ESP is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+# CONFIG_IP_NF_MATCH_OWNER is not set
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+# CONFIG_IP_NF_MATCH_HASHLIMIT is not set
+CONFIG_IP_NF_FILTER=y
+# CONFIG_IP_NF_TARGET_REJECT is not set
+CONFIG_IP_NF_TARGET_LOG=y
+# CONFIG_IP_NF_TARGET_ULOG is not set
+# CONFIG_IP_NF_TARGET_TCPMSS is not set
+# CONFIG_IP_NF_NAT is not set
+# CONFIG_IP_NF_MANGLE is not set
+# CONFIG_IP_NF_RAW is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
 
 #
 # Device Drivers
@@ -201,7 +414,14 @@
 #
 # Generic Driver Options
 #
-CONFIG_FW_LOADER=m
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -213,40 +433,36 @@
 #
 CONFIG_PARPORT=y
 CONFIG_PARPORT_PC=y
-CONFIG_PARPORT_PC_CML1=y
 # CONFIG_PARPORT_SERIAL is not set
 # CONFIG_PARPORT_PC_FIFO is not set
 # CONFIG_PARPORT_PC_SUPERIO is not set
-# CONFIG_PARPORT_OTHER is not set
-# CONFIG_PARPORT_1284 is not set
+# CONFIG_PARPORT_GSC is not set
+CONFIG_PARPORT_1284=y
 
 #
 # Plug and Play support
 #
-CONFIG_PNP=y
-# CONFIG_PNP_DEBUG is not set
-
-#
-# Protocols
-#
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
+# CONFIG_PNP is not set
 
 #
 # Block devices
 #
-CONFIG_BLK_DEV_FD=y
-# CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_FD is not set
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
-# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_CARMEL is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
 # CONFIG_BLK_DEV_RAM is not set
-CONFIG_LBD=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -257,34 +473,31 @@
 #
 # Please see Documentation/ide.txt for help/info on IDE drives
 #
+# CONFIG_BLK_DEV_IDE_SATA is not set
 # CONFIG_BLK_DEV_HD_IDE is not set
 CONFIG_BLK_DEV_IDEDISK=y
-CONFIG_IDEDISK_MULTI_MODE=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
 # CONFIG_IDE_TASK_IOCTL is not set
-CONFIG_IDE_TASKFILE_IO=y
 
 #
 # IDE chipset support/bugfixes
 #
-CONFIG_IDE_GENERIC=y
-CONFIG_BLK_DEV_CMD640=y
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_IDEPNP is not set
+# CONFIG_IDE_GENERIC is not set
+# CONFIG_BLK_DEV_CMD640 is not set
 CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_IDEPCI_SHARE_IRQ=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
-CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_GENERIC is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
-CONFIG_BLK_DEV_RZ1000=y
+# CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_IDEDMA_FORCED is not set
 CONFIG_IDEDMA_PCI_AUTO=y
 # CONFIG_IDEDMA_ONLYDISK is not set
-CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
@@ -294,10 +507,12 @@
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5520 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_CS5535 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_BLK_DEV_HPT366 is not set
 # CONFIG_BLK_DEV_SC1200 is not set
-CONFIG_BLK_DEV_PIIX=y
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT821X is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_PDC202XX_OLD is not set
 # CONFIG_BLK_DEV_PDC202XX_NEW is not set
@@ -306,9 +521,8 @@
 # CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
+CONFIG_BLK_DEV_VIA82CXXX=y
 # CONFIG_IDE_ARM is not set
-# CONFIG_IDE_CHIPSETS is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
 CONFIG_IDEDMA_AUTO=y
@@ -317,8 +531,9 @@
 #
 # SCSI device support
 #
+# CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
-CONFIG_SCSI_PROC_FS=y
+# CONFIG_SCSI_PROC_FS is not set
 
 #
 # SCSI support type (disk, tape, CD-ROM)
@@ -327,7 +542,8 @@
 # CONFIG_CHR_DEV_ST is not set
 # CONFIG_CHR_DEV_OSST is not set
 # CONFIG_BLK_DEV_SR is not set
-CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
 
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
@@ -341,79 +557,47 @@
 #
 # CONFIG_SCSI_SPI_ATTRS is not set
 # CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
 
 #
 # SCSI low-level drivers
 #
+# CONFIG_ISCSI_TCP is not set
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_3W_9XXX is not set
 # CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AHA152X is not set
-# CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AACRAID is not set
 # CONFIG_SCSI_AIC7XXX is not set
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_AIC79XX is not set
-CONFIG_SCSI_DPT_I2O=m
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_MEGARAID is not set
-CONFIG_SCSI_SATA=y
-# CONFIG_SCSI_SATA_SVW is not set
-CONFIG_SCSI_ATA_PIIX=y
-# CONFIG_SCSI_SATA_PROMISE is not set
-CONFIG_SCSI_SATA_SX4=m
-# CONFIG_SCSI_SATA_SIL is not set
-CONFIG_SCSI_SATA_SIS=m
-# CONFIG_SCSI_SATA_VIA is not set
-# CONFIG_SCSI_SATA_VITESSE is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_SATA is not set
 # CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS is not set
 # CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_DTC3280 is not set
 # CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_PIO is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
 # CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
 # CONFIG_SCSI_PPA is not set
 # CONFIG_SCSI_IMM is not set
-# CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_SYM53C8XX_2 is not set
-CONFIG_SCSI_IPR=m
-# CONFIG_SCSI_IPR_TRACE is not set
-# CONFIG_SCSI_IPR_DUMP is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_IPR is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA6322 is not set
-# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_ULTRASTOR is not set
 # CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 
 #
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
 # Multi-device support (RAID and LVM)
 #
 # CONFIG_MD is not set
@@ -422,37 +606,14 @@
 # Fusion MPT device support
 #
 # CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
 
 #
 # IEEE 1394 (FireWire) support
 #
-CONFIG_IEEE1394=y
-
-#
-# Subsystem Options
-#
-# CONFIG_IEEE1394_VERBOSEDEBUG is not set
-# CONFIG_IEEE1394_OUI_DB is not set
-# CONFIG_IEEE1394_EXTRA_CONFIG_ROMS is not set
-
-#
-# Device Drivers
-#
-
-#
-# Texas Instruments PCILynx requires I2C
-#
-CONFIG_IEEE1394_OHCI1394=y
-
-#
-# Protocol Drivers
-#
-# CONFIG_IEEE1394_VIDEO1394 is not set
-# CONFIG_IEEE1394_SBP2 is not set
-# CONFIG_IEEE1394_ETH1394 is not set
-# CONFIG_IEEE1394_DV1394 is not set
-CONFIG_IEEE1394_RAWIO=y
-# CONFIG_IEEE1394_CMP is not set
+# CONFIG_IEEE1394 is not set
 
 #
 # I2O device support
@@ -460,130 +621,13 @@
 # CONFIG_I2O is not set
 
 #
-# Networking support
+# Network device support
 #
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-
-#
-# IP: Virtual Server Configuration
-#
-# CONFIG_IP_VS is not set
-# CONFIG_IPV6 is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
-
-#
-# IP: Netfilter Configuration
-#
-CONFIG_IP_NF_CONNTRACK=y
-# CONFIG_IP_NF_FTP is not set
-# CONFIG_IP_NF_IRC is not set
-# CONFIG_IP_NF_TFTP is not set
-# CONFIG_IP_NF_AMANDA is not set
-CONFIG_IP_NF_QUEUE=y
-CONFIG_IP_NF_IPTABLES=y
-CONFIG_IP_NF_MATCH_LIMIT=y
-CONFIG_IP_NF_MATCH_IPRANGE=y
-CONFIG_IP_NF_MATCH_MAC=y
-CONFIG_IP_NF_MATCH_PKTTYPE=y
-CONFIG_IP_NF_MATCH_MARK=y
-CONFIG_IP_NF_MATCH_MULTIPORT=y
-CONFIG_IP_NF_MATCH_TOS=y
-CONFIG_IP_NF_MATCH_RECENT=y
-CONFIG_IP_NF_MATCH_ECN=y
-CONFIG_IP_NF_MATCH_DSCP=y
-CONFIG_IP_NF_MATCH_AH_ESP=y
-CONFIG_IP_NF_MATCH_LENGTH=y
-CONFIG_IP_NF_MATCH_TTL=y
-CONFIG_IP_NF_MATCH_TCPMSS=y
-CONFIG_IP_NF_MATCH_HELPER=y
-CONFIG_IP_NF_MATCH_STATE=y
-CONFIG_IP_NF_MATCH_CONNTRACK=y
-CONFIG_IP_NF_MATCH_OWNER=y
-CONFIG_IP_NF_FILTER=y
-CONFIG_IP_NF_TARGET_REJECT=y
-CONFIG_IP_NF_NAT=y
-CONFIG_IP_NF_NAT_NEEDED=y
-CONFIG_IP_NF_TARGET_MASQUERADE=y
-CONFIG_IP_NF_TARGET_REDIRECT=y
-CONFIG_IP_NF_TARGET_NETMAP=y
-CONFIG_IP_NF_TARGET_SAME=y
-# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
-CONFIG_IP_NF_MANGLE=y
-CONFIG_IP_NF_TARGET_TOS=y
-CONFIG_IP_NF_TARGET_ECN=y
-CONFIG_IP_NF_TARGET_DSCP=y
-CONFIG_IP_NF_TARGET_MARK=y
-CONFIG_IP_NF_TARGET_CLASSIFY=y
-CONFIG_IP_NF_TARGET_LOG=y
-CONFIG_IP_NF_TARGET_ULOG=y
-CONFIG_IP_NF_TARGET_TCPMSS=y
-CONFIG_IP_NF_ARPTABLES=y
-CONFIG_IP_NF_ARPFILTER=y
-CONFIG_IP_NF_ARP_MANGLE=y
-CONFIG_IP_NF_TARGET_NOTRACK=m
-CONFIG_IP_NF_RAW=m
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_FASTROUTE is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
 CONFIG_NETDEVICES=y
-CONFIG_DUMMY=m
+# CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
-# CONFIG_NET_SB1000 is not set
 
 #
 # ARCnet devices
@@ -591,46 +635,39 @@
 # CONFIG_ARCNET is not set
 
 #
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
-# CONFIG_LANCE is not set
-# CONFIG_NET_VENDOR_SMC is not set
-# CONFIG_NET_VENDOR_RACAL is not set
 
 #
 # Tulip family network device support
 #
 # CONFIG_NET_TULIP is not set
-# CONFIG_AT1700 is not set
-# CONFIG_DEPCA is not set
 # CONFIG_HP100 is not set
-# CONFIG_NET_ISA is not set
 CONFIG_NET_PCI=y
 # CONFIG_PCNET32 is not set
 # CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_AC3200 is not set
-# CONFIG_APRICOT is not set
 # CONFIG_B44 is not set
 # CONFIG_FORCEDETH is not set
-# CONFIG_CS89x0 is not set
 # CONFIG_DGRS is not set
 # CONFIG_EEPRO100 is not set
-# CONFIG_E100 is not set
+CONFIG_E100=y
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
 # CONFIG_NE2K_PCI is not set
 # CONFIG_8139CP is not set
-CONFIG_8139TOO=y
-CONFIG_8139TOO_PIO=y
-# CONFIG_8139TOO_TUNE_TWISTER is not set
-# CONFIG_8139TOO_8129 is not set
-# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_8139TOO is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
@@ -644,21 +681,24 @@
 # CONFIG_ACENIC is not set
 # CONFIG_DL2K is not set
 # CONFIG_E1000 is not set
-# CONFIG_E1000_NAPI is not set
-# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
 
 #
 # Ethernet (10000 Mbit)
 #
+# CONFIG_CHELSIO_T1 is not set
 # CONFIG_IXGB is not set
-CONFIG_S2IO=m
-# CONFIG_S2IO_NAPI is not set
+# CONFIG_S2IO is not set
 
 #
 # Token Ring devices
@@ -682,6 +722,8 @@
 # CONFIG_NET_FC is not set
 # CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
 
 #
 # ISDN subsystem
@@ -703,26 +745,14 @@
 #
 CONFIG_INPUT_MOUSEDEV=y
 CONFIG_INPUT_MOUSEDEV_PSAUX=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1280
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=1024
 # CONFIG_INPUT_JOYDEV is not set
 # CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_EVDEV is not set
+CONFIG_INPUT_EVDEV=y
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PARKBD is not set
-# CONFIG_SERIO_PCIPS2 is not set
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
@@ -734,15 +764,25 @@
 CONFIG_INPUT_MOUSE=y
 CONFIG_MOUSE_PS2=y
 # CONFIG_MOUSE_SERIAL is not set
-# CONFIG_MOUSE_INPORT is not set
-# CONFIG_MOUSE_LOGIBM is not set
-# CONFIG_MOUSE_PC110PAD is not set
 # CONFIG_MOUSE_VSXXXAA is not set
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -757,12 +797,14 @@
 # CONFIG_SERIAL_8250_CONSOLE is not set
 # CONFIG_SERIAL_8250_ACPI is not set
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
 # Non-8250 serial port support
 #
 CONFIG_SERIAL_CORE=y
+# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -770,7 +812,6 @@
 # CONFIG_LP_CONSOLE is not set
 # CONFIG_PPDEV is not set
 # CONFIG_TIPAR is not set
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -782,9 +823,8 @@
 #
 # CONFIG_WATCHDOG is not set
 # CONFIG_HW_RANDOM is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_GEN_RTC is not set
+CONFIG_NVRAM=y
+CONFIG_RTC=y
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -793,34 +833,149 @@
 #
 # Ftape, the floppy tape device driver
 #
+# CONFIG_FTAPE is not set
 CONFIG_AGP=y
 # CONFIG_AGP_ALI is not set
 # CONFIG_AGP_ATI is not set
 # CONFIG_AGP_AMD is not set
 # CONFIG_AGP_AMD64 is not set
-CONFIG_AGP_INTEL=y
+# CONFIG_AGP_INTEL is not set
 # CONFIG_AGP_NVIDIA is not set
 # CONFIG_AGP_SIS is not set
 # CONFIG_AGP_SWORKS is not set
-# CONFIG_AGP_VIA is not set
+CONFIG_AGP_VIA=y
 # CONFIG_AGP_EFFICEON is not set
 CONFIG_DRM=y
 # CONFIG_DRM_TDFX is not set
-# CONFIG_DRM_GAMMA is not set
 # CONFIG_DRM_R128 is not set
-# CONFIG_DRM_RADEON is not set
-# CONFIG_DRM_I810 is not set
-CONFIG_DRM_I830=y
+CONFIG_DRM_RADEON=y
 # CONFIG_DRM_MGA is not set
 # CONFIG_DRM_SIS is not set
+# CONFIG_DRM_VIA is not set
+# CONFIG_DRM_SAVAGE is not set
 # CONFIG_MWAVE is not set
+# CONFIG_CS5535_GPIO is not set
 # CONFIG_RAW_DRIVER is not set
+# CONFIG_HPET is not set
 # CONFIG_HANGCHECK_TIMER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
 # I2C support
 #
-# CONFIG_I2C is not set
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_I2C_ISA=y
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_VIA is not set
+CONFIG_I2C_VIAPRO=y
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_RTC_X1205_I2C is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+CONFIG_HWMON_VID=y
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+CONFIG_SENSORS_IT87=y
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_SENSORS_HDAPS is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
 
 #
 # Misc devices
@@ -828,27 +983,118 @@
 # CONFIG_IBM_ASM is not set
 
 #
+# Multimedia Capabilities Port drivers
+#
+
+#
 # Multimedia devices
 #
-# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_DEV=y
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_BT848 is not set
+# CONFIG_VIDEO_BWQCAM is not set
+# CONFIG_VIDEO_CQCAM is not set
+# CONFIG_VIDEO_W9966 is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_ZORAN is not set
+CONFIG_VIDEO_SAA7134=y
+# CONFIG_VIDEO_SAA7134_ALSA is not set
+# CONFIG_VIDEO_MXB is not set
+# CONFIG_VIDEO_DPC is not set
+# CONFIG_VIDEO_HEXIUM_ORION is not set
+# CONFIG_VIDEO_HEXIUM_GEMINI is not set
+# CONFIG_VIDEO_CX88 is not set
+# CONFIG_VIDEO_EM28XX is not set
+# CONFIG_VIDEO_OVCAMCHIP is not set
+# CONFIG_VIDEO_AUDIO_DECODER is not set
+# CONFIG_VIDEO_DECODER is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
 
 #
 # Digital Video Broadcasting Devices
 #
 # CONFIG_DVB is not set
+CONFIG_VIDEO_TUNER=y
+CONFIG_VIDEO_BUF=y
+CONFIG_VIDEO_IR=y
 
 #
 # Graphics support
 #
-# CONFIG_FB is not set
-# CONFIG_VIDEO_SELECT is not set
+CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_MACMODES is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ARC is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_VGA16 is not set
+# CONFIG_FB_VESA is not set
+CONFIG_VIDEO_SELECT=y
+# CONFIG_FB_HGA is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_I810 is not set
+# CONFIG_FB_INTEL is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON_OLD is not set
+CONFIG_FB_RADEON=y
+CONFIG_FB_RADEON_I2C=y
+# CONFIG_FB_RADEON_DEBUG is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_CYBLA is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_GEODE is not set
+# CONFIG_FB_VIRTUAL is not set
 
 #
 # Console display driver support
 #
 CONFIG_VGA_CONSOLE=y
-# CONFIG_MDA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -864,10 +1110,13 @@
 CONFIG_SND_RAWMIDI=y
 CONFIG_SND_SEQUENCER=y
 # CONFIG_SND_SEQ_DUMMY is not set
-CONFIG_SND_OSSEMUL=y
-CONFIG_SND_MIXER_OSS=y
-CONFIG_SND_PCM_OSS=y
-CONFIG_SND_SEQUENCER_OSS=y
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_SEQUENCER_OSS is not set
+CONFIG_SND_RTCTIMER=y
+CONFIG_SND_SEQ_RTCTIMER_DEFAULT=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+# CONFIG_SND_SUPPORT_OLD_API is not set
 # CONFIG_SND_VERBOSE_PRINTK is not set
 # CONFIG_SND_DEBUG is not set
 
@@ -875,6 +1124,8 @@
 # Generic devices
 #
 CONFIG_SND_MPU401_UART=y
+CONFIG_SND_AC97_CODEC=y
+CONFIG_SND_AC97_BUS=y
 # CONFIG_SND_DUMMY is not set
 # CONFIG_SND_VIRMIDI is not set
 # CONFIG_SND_MTPAV is not set
@@ -882,74 +1133,57 @@
 # CONFIG_SND_MPU401 is not set
 
 #
-# ISA devices
-#
-# CONFIG_SND_AD1848 is not set
-# CONFIG_SND_CS4231 is not set
-# CONFIG_SND_CS4232 is not set
-# CONFIG_SND_CS4236 is not set
-# CONFIG_SND_ES1688 is not set
-# CONFIG_SND_ES18XX is not set
-# CONFIG_SND_GUSCLASSIC is not set
-# CONFIG_SND_GUSEXTREME is not set
-# CONFIG_SND_GUSMAX is not set
-# CONFIG_SND_INTERWAVE is not set
-# CONFIG_SND_INTERWAVE_STB is not set
-# CONFIG_SND_OPTI92X_AD1848 is not set
-# CONFIG_SND_OPTI92X_CS4231 is not set
-# CONFIG_SND_OPTI93X is not set
-# CONFIG_SND_SB8 is not set
-# CONFIG_SND_SB16 is not set
-# CONFIG_SND_SBAWE is not set
-# CONFIG_SND_WAVEFRONT is not set
-# CONFIG_SND_CMI8330 is not set
-# CONFIG_SND_OPL3SA2 is not set
-# CONFIG_SND_SGALAXY is not set
-# CONFIG_SND_SSCAPE is not set
-
-#
 # PCI devices
 #
-CONFIG_SND_AC97_CODEC=y
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALS4000 is not set
 # CONFIG_SND_ALI5451 is not set
 # CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
 # CONFIG_SND_AU8810 is not set
 # CONFIG_SND_AU8820 is not set
 # CONFIG_SND_AU8830 is not set
 # CONFIG_SND_AZT3328 is not set
 # CONFIG_SND_BT87X is not set
-# CONFIG_SND_CS46XX is not set
-# CONFIG_SND_CS4281 is not set
-# CONFIG_SND_EMU10K1 is not set
-# CONFIG_SND_KORG1212 is not set
-# CONFIG_SND_MIXART is not set
-# CONFIG_SND_NM256 is not set
-# CONFIG_SND_RME32 is not set
-# CONFIG_SND_RME96 is not set
-# CONFIG_SND_RME9652 is not set
-# CONFIG_SND_HDSP is not set
-# CONFIG_SND_TRIDENT is not set
-# CONFIG_SND_YMFPCI is not set
-# CONFIG_SND_ALS4000 is not set
+# CONFIG_SND_CA0106 is not set
 # CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CS5535AUDIO is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
 # CONFIG_SND_ENS1370 is not set
 # CONFIG_SND_ENS1371 is not set
 # CONFIG_SND_ES1938 is not set
 # CONFIG_SND_ES1968 is not set
-# CONFIG_SND_MAESTRO3 is not set
 # CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
 # CONFIG_SND_ICE1712 is not set
 # CONFIG_SND_ICE1724 is not set
-CONFIG_SND_INTEL8X0=y
+# CONFIG_SND_INTEL8X0 is not set
 # CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
 # CONFIG_SND_SONICVIBES is not set
-# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_TRIDENT is not set
+CONFIG_SND_VIA82XX=y
+# CONFIG_SND_VIA82XX_MODEM is not set
 # CONFIG_SND_VX222 is not set
+# CONFIG_SND_YMFPCI is not set
 
 #
-# ALSA USB devices
+# USB devices
 #
 # CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_USX2Y is not set
 
 #
 # Open Sound System
@@ -959,6 +1193,8 @@
 #
 # USB support
 #
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB=y
 # CONFIG_USB_DEBUG is not set
 
@@ -968,6 +1204,8 @@
 CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_BANDWIDTH is not set
 # CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_OTG is not set
 
 #
 # USB Host Controller Drivers
@@ -975,68 +1213,93 @@
 CONFIG_USB_EHCI_HCD=y
 # CONFIG_USB_EHCI_SPLIT_ISO is not set
 # CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_ISP116X_HCD is not set
 # CONFIG_USB_OHCI_HCD is not set
 CONFIG_USB_UHCI_HCD=y
+# CONFIG_USB_SL811_HCD is not set
 
 #
 # USB Device Class drivers
 #
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH_TTY is not set
-# CONFIG_USB_MIDI is not set
+# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
 # CONFIG_USB_ACM is not set
-CONFIG_USB_PRINTER=y
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
 CONFIG_USB_STORAGE=y
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
 # CONFIG_USB_STORAGE_FREECOM is not set
 # CONFIG_USB_STORAGE_ISD200 is not set
 # CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_USBAT is not set
 # CONFIG_USB_STORAGE_SDDR09 is not set
 # CONFIG_USB_STORAGE_SDDR55 is not set
 # CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_LIBUSUAL is not set
 
 #
-# USB Human Interface Devices (HID)
+# USB Input Devices
 #
-CONFIG_USB_HID=y
-CONFIG_USB_HIDINPUT=y
-# CONFIG_HID_FF is not set
-# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_HID is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
 # CONFIG_USB_AIPTEK is not set
 # CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
 # CONFIG_USB_KBTAB is not set
 # CONFIG_USB_POWERMATE is not set
 # CONFIG_USB_MTOUCH is not set
-CONFIG_USB_EGALAX=m
+# CONFIG_USB_ITMTOUCH is not set
+# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_YEALINK is not set
 # CONFIG_USB_XPAD is not set
 # CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
 
 #
 # USB Imaging devices
 #
 # CONFIG_USB_MDC800 is not set
 # CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
 
 #
 # USB Multimedia devices
 #
 # CONFIG_USB_DABUSB is not set
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_ET61X251 is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_SN9C102 is not set
+# CONFIG_USB_STV680 is not set
+# CONFIG_USB_PWC is not set
 
 #
-# Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
+# USB Network Adapters
 #
 # CONFIG_USB_CATC is not set
 # CONFIG_USB_KAWETH is not set
 # CONFIG_USB_PEGASUS is not set
 # CONFIG_USB_RTL8150 is not set
 # CONFIG_USB_USBNET is not set
+# CONFIG_USB_MON is not set
 
 #
 # USB port drivers
@@ -1053,56 +1316,85 @@
 #
 # CONFIG_USB_EMI62 is not set
 # CONFIG_USB_EMI26 is not set
-# CONFIG_USB_TIGL is not set
 # CONFIG_USB_AUERSWALD is not set
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
 # CONFIG_USB_LED is not set
-CONFIG_USB_CYTHERM=m
-CONFIG_USB_PHIDGETSERVO=m
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
 # CONFIG_USB_TEST is not set
 
 #
+# USB DSL modem support
+#
+
+#
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
 
 #
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# SN Devices
+#
+
+#
+# EDAC - error detection and reporting (RAS)
+#
+# CONFIG_EDAC is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-CONFIG_FS_MBCACHE=y
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
+# CONFIG_INOTIFY is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
-CONFIG_AUTOFS4_FS=y
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
 
 #
 # CD-ROM/DVD Filesystems
 #
 CONFIG_ISO9660_FS=y
 CONFIG_JOLIET=y
-# CONFIG_ZISOFS is not set
-CONFIG_UDF_FS=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=y
+# CONFIG_UDF_FS is not set
 
 #
 # DOS/FAT/NT Filesystems
 #
 CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
+# CONFIG_MSDOS_FS is not set
 CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=850
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 # CONFIG_NTFS_FS is not set
 
 #
@@ -1111,12 +1403,12 @@
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
 CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
 # CONFIG_HUGETLBFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1138,38 +1430,48 @@
 #
 # Network File Systems
 #
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFS_DIRECTIO is not set
-CONFIG_NFSD=y
-# CONFIG_NFSD_V3 is not set
-CONFIG_NFSD_TCP=y
-CONFIG_LOCKD=y
-CONFIG_EXPORTFS=y
-CONFIG_SUNRPC=y
-# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
 # CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
+CONFIG_CIFS=y
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
 
 #
 # Partition Types
 #
-# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
 CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 
 #
 # Native Language Support
 #
 CONFIG_NLS=y
-CONFIG_NLS_DEFAULT="iso8859-1"
-CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_DEFAULT="iso8859-15"
+# CONFIG_NLS_CODEPAGE_437 is not set
 # CONFIG_NLS_CODEPAGE_737 is not set
 # CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
+CONFIG_NLS_CODEPAGE_850=y
 # CONFIG_NLS_CODEPAGE_852 is not set
 # CONFIG_NLS_CODEPAGE_855 is not set
 # CONFIG_NLS_CODEPAGE_857 is not set
@@ -1189,6 +1491,7 @@
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
 CONFIG_NLS_ISO8859_1=y
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
@@ -1199,31 +1502,33 @@
 # CONFIG_NLS_ISO8859_9 is not set
 # CONFIG_NLS_ISO8859_13 is not set
 # CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
+CONFIG_NLS_ISO8859_15=y
 # CONFIG_NLS_KOI8_R is not set
 # CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
+CONFIG_NLS_UTF8=y
 
 #
-# Profiling support
+# Instrumentation Support
 #
-CONFIG_PROFILING=y
-CONFIG_OPROFILE=y
+# CONFIG_PROFILING is not set
+# CONFIG_KPROBES is not set
 
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
+CONFIG_MAGIC_SYSRQ=y
 # CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_EARLY_PRINTK=y
-CONFIG_DEBUG_SPINLOCK_SLEEP=y
-# CONFIG_FRAME_POINTER is not set
-CONFIG_4KSTACKS=y
 CONFIG_X86_FIND_SMP_CONFIG=y
 CONFIG_X86_MPPARSE=y
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -1232,13 +1537,18 @@
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
 CONFIG_CRC32=y
-CONFIG_LIBCRC32C=m
-CONFIG_X86_SMP=y
-CONFIG_X86_HT=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_X86_BIOS_REBOOT=y
-CONFIG_X86_TRAMPOLINE=y
-CONFIG_X86_STD_RESOURCES=y
-CONFIG_PC=y
+CONFIG_KTIME_SCALAR=y
diff --git a/arch/m68knommu/kernel/vmlinux.lds.S b/arch/m68knommu/kernel/vmlinux.lds.S
index ac9de26..a331cc90 100644
--- a/arch/m68knommu/kernel/vmlinux.lds.S
+++ b/arch/m68knommu/kernel/vmlinux.lds.S
@@ -269,6 +269,11 @@
 		*(__ksymtab_gpl)
 		__stop___ksymtab_gpl = .;
 
+		/* Kernel symbol table: GPL-future symbols */
+		__start___ksymtab_gpl_future = .;
+		*(__ksymtab_gpl_future)
+		__stop___ksymtab_gpl_future = .;
+
 		/* Kernel symbol table: Normal symbols */
 		__start___kcrctab = .;
 		*(__kcrctab)
@@ -279,6 +284,11 @@
 		*(__kcrctab_gpl)
 		__stop___kcrctab_gpl = .;
 
+		/* Kernel symbol table: GPL-future symbols */
+		__start___kcrctab_gpl_future = .;
+		*(__kcrctab_gpl_future)
+		__stop___kcrctab_gpl_future = .;
+
 		/* Kernel symbol table: strings */
 		*(__ksymtab_strings)
 
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 3a0f89d..ac2012f 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -602,7 +602,7 @@
 	  If you want this kernel to run on SGI O2 workstation, say Y here.
 
 config SIBYTE_BIGSUR
-	bool "Support for Sibyte BigSur"
+	bool "Support for Sibyte BCM91480B-BigSur"
 	select BOOT_ELF32
 	select DMA_COHERENT
 	select PCI_DOMAINS
@@ -790,6 +790,7 @@
 source "arch/mips/tx4938/Kconfig"
 source "arch/mips/vr41xx/Kconfig"
 source "arch/mips/philips/pnx8550/common/Kconfig"
+source "arch/mips/cobalt/Kconfig"
 
 endmenu
 
@@ -1159,6 +1160,7 @@
 config CPU_TX49XX
 	bool "R49XX"
 	depends on SYS_HAS_CPU_TX49XX
+	select CPU_HAS_PREFETCH
 	select CPU_SUPPORTS_32BIT_KERNEL
 	select CPU_SUPPORTS_64BIT_KERNEL
 
@@ -1581,7 +1583,7 @@
 
 config SMP
 	bool "Multi-Processing support"
-	depends on CPU_RM9000 || ((SIBYTE_BCM1x80 || SIBYTE_BCM1x55 || SIBYTE_SB1250) && !SIBYTE_STANDALONE) || SGI_IP27 || MIPS_MT_SMP
+	depends on CPU_RM9000 || ((SIBYTE_BCM1x80 || SIBYTE_BCM1x55 || SIBYTE_SB1250 || QEMU) && !SIBYTE_STANDALONE) || SGI_IP27 || MIPS_MT_SMP
 	---help---
 	  This enables support for systems with more than one CPU. If you have
 	  a system with only one CPU, like most personal computers, say N. If
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 3d8dac6..9a69e0f 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -12,10 +12,6 @@
 # for "archclean" cleaning up for this architecture.
 #
 
-as-option = $(shell if $(CC) $(CFLAGS) $(1) -Wa,-Z -c -o /dev/null \
-	     -xassembler /dev/null > /dev/null 2>&1; then echo "$(1)"; \
-	     else echo "$(2)"; fi ;)
-
 cflags-y :=
 
 #
@@ -38,12 +34,10 @@
 endif
 
 ifdef CONFIG_32BIT
-gcc-abi			= 32
 tool-prefix		= $(32bit-tool-prefix)
 UTS_MACHINE		:= mips
 endif
 ifdef CONFIG_64BIT
-gcc-abi			= 64
 tool-prefix		= $(64bit-tool-prefix)
 UTS_MACHINE		:= mips64
 endif
@@ -52,38 +46,28 @@
 CROSS_COMPILE		:= $(tool-prefix)
 endif
 
-CHECKFLAGS-y				+= -D__linux__ -D__mips__ \
-					   -D_MIPS_SZINT=32 \
-					   -D_ABIO32=1 \
-					   -D_ABIN32=2 \
-					   -D_ABI64=3
-CHECKFLAGS-$(CONFIG_32BIT)		+= -D_MIPS_SIM=_ABIO32 \
-					   -D_MIPS_SZLONG=32 \
-					   -D_MIPS_SZPTR=32 \
-					   -D__PTRDIFF_TYPE__=int
-CHECKFLAGS-$(CONFIG_64BIT)		+= -m64 -D_MIPS_SIM=_ABI64 \
-					   -D_MIPS_SZLONG=64 \
-					   -D_MIPS_SZPTR=64 \
-					   -D__PTRDIFF_TYPE__="long int"
-CHECKFLAGS-$(CONFIG_CPU_BIG_ENDIAN)	+= -D__MIPSEB__
-CHECKFLAGS-$(CONFIG_CPU_LITTLE_ENDIAN)	+= -D__MIPSEL__
-
-CHECKFLAGS				= $(CHECKFLAGS-y)
-
-ifdef CONFIG_BUILD_ELF64
-gas-abi			= 64
-ld-emul			= $(64bit-emul)
-vmlinux-32		= vmlinux.32
-vmlinux-64		= vmlinux
-else
-gas-abi			= 32
+ifdef CONFIG_32BIT
 ld-emul			= $(32bit-emul)
 vmlinux-32		= vmlinux
 vmlinux-64		= vmlinux.64
 
-cflags-$(CONFIG_64BIT)	+= $(call cc-option,-mno-explicit-relocs)
+cflags-y		+= -mabi=32
 endif
 
+ifdef CONFIG_64BIT
+ld-emul			= $(64bit-emul)
+vmlinux-32		= vmlinux.32
+vmlinux-64		= vmlinux
+
+cflags-y		+= -mabi=64
+ifdef CONFIG_BUILD_ELF64
+cflags-y		+= $(call cc-option,-mno-explicit-relocs)
+else
+cflags-y		+= $(call cc-option,-msym32)
+endif
+endif
+
+
 #
 # GCC uses -G 0 -mabicalls -fpic as default.  We don't want PIC in the kernel
 # code since it only slows down the whole thing.  At some point we might make
@@ -105,162 +89,44 @@
 # carefully avoid to add it redundantly because gcc 3.3/3.4 complains
 # when fed the toolchain default!
 #
-cflags-$(CONFIG_CPU_BIG_ENDIAN)		+= $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' && echo -EB)
-cflags-$(CONFIG_CPU_LITTLE_ENDIAN)	+= $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' || echo -EL)
+cflags-$(CONFIG_CPU_BIG_ENDIAN)		+= $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' && echo -EB -D__MIPSEB__)
+cflags-$(CONFIG_CPU_LITTLE_ENDIAN)	+= $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' || echo -EL -D__MIPSEL__)
 
 cflags-$(CONFIG_SB1XXX_CORELIS)	+= $(call cc-option,-mno-sched-prolog) \
 				   -fno-omit-frame-pointer
 
 #
-# Use: $(call set_gccflags,<cpu0>,<isa0>,<cpu1>,<isa1>,<isa2>)
-#
-# <cpu0>,<isa0> -- preferred CPU and ISA designations (may require
-#                  recent tools)
-# <cpu1>,<isa1> -- fallback CPU and ISA designations (have to work
-#                  with up to the oldest supported tools)
-# <isa2>        -- an ISA designation used as an ABI selector for
-#                  gcc versions that do not support "-mabi=32"
-#                  (depending on the CPU type, either "mips1" or
-#                  "mips2")
-#
-set_gccflags = $(shell \
-while :; do \
-	cpu=$(1); isa=-$(2); \
-	for gcc_opt in -march= -mcpu=; do \
-		$(CC) $$gcc_opt$$cpu $$isa -S -o /dev/null \
-			-xc /dev/null > /dev/null 2>&1 && \
-			break 2; \
-	done; \
-	cpu=$(3); isa=-$(4); \
-	for gcc_opt in -march= -mcpu=; do \
-		$(CC) $$gcc_opt$$cpu $$isa -S -o /dev/null \
-			-xc /dev/null > /dev/null 2>&1 && \
-			break 2; \
-	done; \
-	break; \
-done; \
-gcc_abi=-mabi=$(gcc-abi); gcc_cpu=$$cpu; \
-if $(CC) $$gcc_abi -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then \
-	gcc_isa=$$isa; \
-else \
-	gcc_abi=; gcc_isa=-$(5); \
-fi; \
-gas_abi=-Wa,-$(gcc-abi); gas_cpu=$$cpu; gas_isa=-Wa,$$isa; \
-while :; do \
-	for gas_opt in -Wa,-march= -Wa,-mcpu=; do \
-		$(CC) $$gas_abi $$gas_opt$$cpu $$gas_isa -Wa,-Z -c \
-			-o /dev/null -xassembler /dev/null > /dev/null 2>&1 && \
-			break 2; \
-	done; \
-	gas_abi=; gas_opt=; gas_cpu=; gas_isa=; \
-	break; \
-done; \
-if test "$(gcc-abi)" != "$(gas-abi)"; then \
-	gas_abi="-Wa,-$(gas-abi) -Wa,-mgp$(gcc-abi)"; \
-fi; \
-if test "$$gcc_opt" = -march= && test -n "$$gcc_abi"; then \
-	$(CC) $$gcc_abi $$gcc_opt$$gcc_cpu -S -o /dev/null \
-		-xc /dev/null > /dev/null 2>&1 && \
-		gcc_isa=; \
-fi; \
-echo $$gcc_abi $$gcc_opt$$gcc_cpu $$gcc_isa $$gas_abi $$gas_opt$$gas_cpu $$gas_isa)
-
-#
 # CPU-dependent compiler/assembler options for optimization.
 #
-cflags-$(CONFIG_CPU_R3000)	+= \
-			$(call set_gccflags,r3000,mips1,r3000,mips1,mips1)
-CHECKFLAGS-$(CONFIG_CPU_R3000)	+= -D_MIPS_ISA=_MIPS_ISA_MIPS1
-
-cflags-$(CONFIG_CPU_TX39XX)	+= \
-			$(call set_gccflags,r3900,mips1,r3000,mips1,mips1)
-CHECKFLAGS-$(CONFIG_CPU_TX39XX)	+= -D_MIPS_ISA=_MIPS_ISA_MIPS1
-
-cflags-$(CONFIG_CPU_R6000)	+= \
-			$(call set_gccflags,r6000,mips2,r6000,mips2,mips2) \
+cflags-$(CONFIG_CPU_R3000)	+= -march=r3000
+cflags-$(CONFIG_CPU_TX39XX)	+= -march=r3900
+cflags-$(CONFIG_CPU_R6000)	+= -march=r6000 -Wa,--trap
+cflags-$(CONFIG_CPU_R4300)	+= -march=r4300 -Wa,--trap
+cflags-$(CONFIG_CPU_VR41XX)	+= -march=r4100 -Wa,--trap
+cflags-$(CONFIG_CPU_R4X00)	+= -march=r4600 -Wa,--trap
+cflags-$(CONFIG_CPU_TX49XX)	+= -march=r4600 -Wa,--trap
+cflags-$(CONFIG_CPU_MIPS32_R1)	+= $(call cc-option,-march=mips32,-mips2 -mtune=r4600) \
+			-Wa,-mips32 -Wa,--trap
+cflags-$(CONFIG_CPU_MIPS32_R2)	+= $(call cc-option,-march=mips32r2,-mips2 -mtune=r4600) \
+			-Wa,-mips32r2 -Wa,--trap
+cflags-$(CONFIG_CPU_MIPS64_R1)	+= $(call cc-option,-march=mips64,-mips2 -mtune=r4600) \
+			-Wa,-mips64 -Wa,--trap
+cflags-$(CONFIG_CPU_MIPS64_R2)	+= $(call cc-option,-march=mips64r2,-mips2 -mtune=r4600 ) \
+			-Wa,-mips64r2 -Wa,--trap
+cflags-$(CONFIG_CPU_R5000)	+= -march=r5000 -Wa,--trap
+cflags-$(CONFIG_CPU_R5432)	+= $(call cc-options,-march=r5400,-march=r5000) \
 			-Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_R6000)	+= -D_MIPS_ISA=_MIPS_ISA_MIPS2
-
-cflags-$(CONFIG_CPU_R4300)	+= \
-			$(call set_gccflags,r4300,mips3,r4300,mips3,mips2) \
+cflags-$(CONFIG_CPU_NEVADA)	+= $(call cc-options,-march=rm5200,-march=r5000) \
 			-Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_R4300)	+= -D_MIPS_ISA=_MIPS_ISA_MIPS3
-
-cflags-$(CONFIG_CPU_VR41XX)	+= \
-			$(call set_gccflags,r4100,mips3,r4600,mips3,mips2) \
+cflags-$(CONFIG_CPU_RM7000)	+= $(call cc-option,-march=rm7000,-march=r5000) \
 			-Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_VR41XX)	+= -D_MIPS_ISA=_MIPS_ISA_MIPS3
-
-cflags-$(CONFIG_CPU_R4X00)	+= \
-			$(call set_gccflags,r4600,mips3,r4600,mips3,mips2) \
+cflags-$(CONFIG_CPU_RM9000)	+= $(call cc-option,-march=rm9000,-march=r5000) \
 			-Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_R4X00)	+= -D_MIPS_ISA=_MIPS_ISA_MIPS3
-
-cflags-$(CONFIG_CPU_TX49XX)	+= \
-			$(call set_gccflags,r4600,mips3,r4600,mips3,mips2)  \
+cflags-$(CONFIG_CPU_SB1)	+= $(call cc-option,-march=sb1,-march=r5000) \
 			-Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_TX49XX)	+= -D_MIPS_ISA=_MIPS_ISA_MIPS3
-
-cflags-$(CONFIG_CPU_MIPS32_R1)	+= \
-			$(call set_gccflags,mips32,mips32,r4600,mips3,mips2) \
+cflags-$(CONFIG_CPU_R8000)	+= -march=r8000 -Wa,--trap
+cflags-$(CONFIG_CPU_R10000)	+= $(call cc-option,-march=r10000,-march=r8000) \
 			-Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_MIPS32_R1)	+= -D_MIPS_ISA=_MIPS_ISA_MIPS32
-
-cflags-$(CONFIG_CPU_MIPS32_R2)	+= \
-			$(call set_gccflags,mips32r2,mips32r2,r4600,mips3,mips2) \
-			-Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_MIPS32_R2)	+= -D_MIPS_ISA=_MIPS_ISA_MIPS32
-
-cflags-$(CONFIG_CPU_MIPS64_R1)	+= \
-			$(call set_gccflags,mips64,mips64,r4600,mips3,mips2) \
-			-Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_MIPS64_R1)	+= -D_MIPS_ISA=_MIPS_ISA_MIPS64
-
-cflags-$(CONFIG_CPU_MIPS64_R2)	+= \
-			$(call set_gccflags,mips64r2,mips64r2,r4600,mips3,mips2) \
-			-Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_MIPS64_R2)	+= -D_MIPS_ISA=_MIPS_ISA_MIPS64
-
-cflags-$(CONFIG_CPU_R5000)	+= \
-			$(call set_gccflags,r5000,mips4,r5000,mips4,mips2) \
-			-Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_R5000)	+= -D_MIPS_ISA=_MIPS_ISA_MIPS4
-
-cflags-$(CONFIG_CPU_R5432)	+= \
-			$(call set_gccflags,r5400,mips4,r5000,mips4,mips2) \
-			-Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_R5432)	+= -D_MIPS_ISA=_MIPS_ISA_MIPS4
-
-cflags-$(CONFIG_CPU_NEVADA)	+= \
-			$(call set_gccflags,rm5200,mips4,r5000,mips4,mips2) \
-			-Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_NEVADA)	+= -D_MIPS_ISA=_MIPS_ISA_MIPS4
-
-cflags-$(CONFIG_CPU_RM7000)	+= \
-			$(call set_gccflags,rm7000,mips4,r5000,mips4,mips2) \
-			-Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_RM7000)	+= -D_MIPS_ISA=_MIPS_ISA_MIPS4
-
-cflags-$(CONFIG_CPU_RM9000)	+= \
-			$(call set_gccflags,rm9000,mips4,r5000,mips4,mips2) \
-			-Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_RM9000)	+= -D_MIPS_ISA=_MIPS_ISA_MIPS4
-
-
-cflags-$(CONFIG_CPU_SB1)	+= \
-			$(call set_gccflags,sb1,mips64,r5000,mips4,mips2) \
-			-Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_SB1)	+= -D_MIPS_ISA=_MIPS_ISA_MIPS64
-
-cflags-$(CONFIG_CPU_R8000)	+= \
-			$(call set_gccflags,r8000,mips4,r8000,mips4,mips2) \
-			-Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_R8000)	+= -D_MIPS_ISA=_MIPS_ISA_MIPS4
-
-cflags-$(CONFIG_CPU_R10000)	+= \
-			$(call set_gccflags,r10000,mips4,r8000,mips4,mips2) \
-			-Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_R10000)	+= -D_MIPS_ISA=_MIPS_ISA_MIPS4
 
 ifdef CONFIG_CPU_SB1
 ifdef CONFIG_SB1_PASS_1_WORKAROUNDS
@@ -630,7 +496,6 @@
 ifdef CONFIG_SGI_IP27
 core-$(CONFIG_SGI_IP27)		+= arch/mips/sgi-ip27/
 cflags-$(CONFIG_SGI_IP27)	+= -Iinclude/asm-mips/mach-ip27
-ifdef CONFIG_BUILD_ELF64
 ifdef CONFIG_MAPPED_KERNEL
 load-$(CONFIG_SGI_IP27)		+= 0xc00000004001c000
 OBJCOPYFLAGS			:= --change-addresses=0x3fffffff80000000
@@ -639,16 +504,6 @@
 load-$(CONFIG_SGI_IP27)		+= 0xa80000000001c000
 OBJCOPYFLAGS			:= --change-addresses=0x57ffffff80000000
 endif
-else
-ifdef CONFIG_MAPPED_KERNEL
-load-$(CONFIG_SGI_IP27)		+= 0xffffffffc001c000
-OBJCOPYFLAGS			:= --change-addresses=0xc000000080000000
-dataoffset-$(CONFIG_SGI_IP27)	+= 0x01000000
-else
-load-$(CONFIG_SGI_IP27)		+= 0xffffffff8001c000
-OBJCOPYFLAGS			:= --change-addresses=0xa800000080000000
-endif
-endif
 endif
 
 #
@@ -757,6 +612,12 @@
 
 LDFLAGS			+= -m $(ld-emul)
 
+ifdef CONFIG_MIPS
+CHECKFLAGS += $(shell $(CC) $(CFLAGS) -dM -E -xc /dev/null | \
+	egrep -vw '__GNUC_(MAJOR|MINOR|PATCHLEVEL)__' | \
+	sed -e 's/^\#define /-D/' -e 's/ /="/' -e 's/$$/"/')
+endif
+
 OBJCOPYFLAGS		+= --remove-section=.reginfo
 
 #
diff --git a/arch/mips/au1000/common/cputable.c b/arch/mips/au1000/common/cputable.c
index 4dbde82..d8df5fd 100644
--- a/arch/mips/au1000/common/cputable.c
+++ b/arch/mips/au1000/common/cputable.c
@@ -38,7 +38,7 @@
     { 0xffffffff, 0x02030204, "Au1100 BE", 0, 1 },
     { 0xffffffff, 0x03030200, "Au1550 AA", 0, 1 },
     { 0xffffffff, 0x04030200, "Au1200 AB", 0, 0 },
-    { 0xffffffff, 0x04030201, "Au1200 AC", 0, 1 },
+    { 0xffffffff, 0x04030201, "Au1200 AC", 1, 0 },
     { 0x00000000, 0x00000000, "Unknown Au1xxx", 1, 0 },
 };
 
diff --git a/arch/mips/au1000/common/dbdma.c b/arch/mips/au1000/common/dbdma.c
index d00e824..6ee090b 100644
--- a/arch/mips/au1000/common/dbdma.c
+++ b/arch/mips/au1000/common/dbdma.c
@@ -214,7 +214,7 @@
 	if ( NULL != p )
 	{
 		memcpy(p, dev, sizeof(dbdev_tab_t));
- 		p->dev_id = DSCR_DEV2CUSTOM_ID(new_id,dev->dev_id);
+		p->dev_id = DSCR_DEV2CUSTOM_ID(new_id,dev->dev_id);
 		ret = p->dev_id;
 		new_id++;
 #if 0
@@ -260,7 +260,7 @@
 	spin_lock_irqsave(&au1xxx_dbdma_spin_lock, flags);
 	if (!(stp->dev_flags & DEV_FLAGS_INUSE) ||
 	     (stp->dev_flags & DEV_FLAGS_ANYUSE)) {
-	     	/* Got source */
+		/* Got source */
 		stp->dev_flags |= DEV_FLAGS_INUSE;
 		if (!(dtp->dev_flags & DEV_FLAGS_INUSE) ||
 		     (dtp->dev_flags & DEV_FLAGS_ANYUSE)) {
diff --git a/arch/mips/au1000/common/dma.c b/arch/mips/au1000/common/dma.c
index 1905c6b..1d82f22 100644
--- a/arch/mips/au1000/common/dma.c
+++ b/arch/mips/au1000/common/dma.c
@@ -174,7 +174,7 @@
 		return -EINVAL;
 #else
  	if (dev_id < 0 || dev_id >= DMA_NUM_DEV)
- 		return -EINVAL;
+		return -EINVAL;
 #endif
 
 	for (i = 0; i < NUM_AU1000_DMA_CHANNELS; i++) {
diff --git a/arch/mips/au1000/common/platform.c b/arch/mips/au1000/common/platform.c
index 48d3f54..32702e5 100644
--- a/arch/mips/au1000/common/platform.c
+++ b/arch/mips/au1000/common/platform.c
@@ -20,7 +20,7 @@
 static struct resource au1xxx_usb_ohci_resources[] = {
 	[0] = {
 		.start		= USB_OHCI_BASE,
-		.end		= USB_OHCI_BASE + USB_OHCI_LEN,
+		.end		= USB_OHCI_BASE + USB_OHCI_LEN - 1,
 		.flags		= IORESOURCE_MEM,
 	},
 	[1] = {
@@ -264,7 +264,7 @@
 
 static struct platform_device smc91x_device = {
 	.name		= "smc91x",
- 	.id		= -1,
+	.id		= -1,
 	.num_resources	= ARRAY_SIZE(smc91x_resources),
 	.resource	= smc91x_resources,
 };
@@ -278,9 +278,7 @@
 	&au1100_lcd_device,
 #endif
 #ifdef CONFIG_SOC_AU1200
-#if 0	/* fixme */
 	&au1xxx_usb_ehci_device,
-#endif
 	&au1xxx_usb_gdt_device,
 	&au1xxx_usb_otg_device,
 	&au1200_lcd_device,
@@ -288,7 +286,7 @@
 	&au1xxx_mmc_device,
 #endif
 #ifdef CONFIG_MIPS_DB1200
- 	&smc91x_device,
+	&smc91x_device,
 #endif
 };
 
diff --git a/arch/mips/au1000/common/setup.c b/arch/mips/au1000/common/setup.c
index eb155c0..1080558 100644
--- a/arch/mips/au1000/common/setup.c
+++ b/arch/mips/au1000/common/setup.c
@@ -90,7 +90,7 @@
 	else {
 		/* Clear to obtain best system bus performance */
 		clear_c0_config(1<<19); /* Clear Config[OD] */
- 	}
+	}
 
 	argptr = prom_getcmdline();
 
diff --git a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c
index 883d3f3..f85f152 100644
--- a/arch/mips/au1000/common/time.c
+++ b/arch/mips/au1000/common/time.c
@@ -359,7 +359,7 @@
 		: "hi", "lo", GCC_REG_ACCUM);
 
 	/*
- 	 * Due to possible jiffies inconsistencies, we need to check
+	 * Due to possible jiffies inconsistencies, we need to check
 	 * the result so that we'll get a timer that is monotonic.
 	 */
 	if (res >= USECS_PER_JIFFY)
diff --git a/arch/mips/cobalt/Kconfig b/arch/mips/cobalt/Kconfig
new file mode 100644
index 0000000..7c42b08
--- /dev/null
+++ b/arch/mips/cobalt/Kconfig
@@ -0,0 +1,7 @@
+config EARLY_PRINTK
+	bool "Early console support"
+	depends on MIPS_COBALT
+	help
+	  Provide early console support by direct access to the
+	  on board UART. The UART must have been previously
+	  initialised by the boot loader.
diff --git a/arch/mips/cobalt/Makefile b/arch/mips/cobalt/Makefile
index 3b6b757..720e757 100644
--- a/arch/mips/cobalt/Makefile
+++ b/arch/mips/cobalt/Makefile
@@ -4,4 +4,6 @@
 
 obj-y	 := irq.o int-handler.o reset.o setup.o
 
+obj-$(CONFIG_EARLY_PRINTK)	+= console.o
+
 EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/cobalt/console.c b/arch/mips/cobalt/console.c
new file mode 100644
index 0000000..45c2d27
--- /dev/null
+++ b/arch/mips/cobalt/console.c
@@ -0,0 +1,43 @@
+/*
+ * (C) P. Horton 2006
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/console.h>
+#include <linux/serial_reg.h>
+#include <asm/addrspace.h>
+#include <asm/mach-cobalt/cobalt.h>
+
+static void putchar(int c)
+{
+	if(c == '\n')
+		putchar('\r');
+
+	while(!(COBALT_UART[UART_LSR] & UART_LSR_THRE))
+		;
+
+	COBALT_UART[UART_TX] = c;
+}
+
+static void cons_write(struct console *c, const char *s, unsigned n)
+{
+	while(n-- && *s)
+		putchar(*s++);
+}
+
+static struct console cons_info =
+{
+	.name	= "uart",
+	.write	= cons_write,
+	.flags	= CON_PRINTBUFFER | CON_BOOT,
+	.index	= -1,
+};
+
+void __init cobalt_early_console(void)
+{
+	register_console(&cons_info);
+
+	printk("Cobalt: early console registered\n");
+}
diff --git a/arch/mips/cobalt/setup.c b/arch/mips/cobalt/setup.c
index b9713a7..4f9ea12 100644
--- a/arch/mips/cobalt/setup.c
+++ b/arch/mips/cobalt/setup.c
@@ -31,6 +31,7 @@
 extern void cobalt_machine_restart(char *command);
 extern void cobalt_machine_halt(void);
 extern void cobalt_machine_power_off(void);
+extern void cobalt_early_console(void);
 
 int cobalt_board_id;
 
@@ -109,14 +110,6 @@
 	/* I/O port resource must include UART and LCD/buttons */
 	ioport_resource.end = 0x0fffffff;
 
-	/*
-	 * This is a prom style console. We just poke at the
-	 *  UART to make it talk.
-	 * Only use this console if you really screw up and can't
-	 *  get to the stage of setting up a real serial console.
-	 */
-	/*ns16550_setup_console();*/
-
 	/* request I/O space for devices used on all i[345]86 PCs */
 	for (i = 0; i < COBALT_IO_RESOURCES; i++)
 		request_resource(&ioport_resource, cobalt_io_resources + i);
@@ -136,6 +129,10 @@
 #ifdef CONFIG_SERIAL_8250
 	if (cobalt_board_id > COBALT_BRD_ID_RAQ1) {
 
+#ifdef CONFIG_EARLY_PRINTK
+		cobalt_early_console();
+#endif
+
 		uart.line	= 0;
 		uart.type	= PORT_UNKNOWN;
 		uart.uartclk	= 18432000;
diff --git a/arch/mips/configs/atlas_defconfig b/arch/mips/configs/atlas_defconfig
index 89c2157..9e1ae95 100644
--- a/arch/mips/configs/atlas_defconfig
+++ b/arch/mips/configs/atlas_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:05:52 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:39:52 2006
 #
 CONFIG_MIPS=y
 
@@ -164,26 +164,28 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -335,6 +337,29 @@
 CONFIG_NETFILTER_NETLINK=m
 CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -353,47 +378,30 @@
 CONFIG_IP_NF_PPTP=m
 CONFIG_IP_NF_QUEUE=m
 CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
 CONFIG_IP_NF_MATCH_IPRANGE=m
-CONFIG_IP_NF_MATCH_MAC=m
-CONFIG_IP_NF_MATCH_PKTTYPE=m
-CONFIG_IP_NF_MATCH_MARK=m
 CONFIG_IP_NF_MATCH_MULTIPORT=m
 CONFIG_IP_NF_MATCH_TOS=m
 CONFIG_IP_NF_MATCH_RECENT=m
 CONFIG_IP_NF_MATCH_ECN=m
 CONFIG_IP_NF_MATCH_DSCP=m
 CONFIG_IP_NF_MATCH_AH_ESP=m
-CONFIG_IP_NF_MATCH_LENGTH=m
 CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_TCPMSS=m
-CONFIG_IP_NF_MATCH_HELPER=m
-CONFIG_IP_NF_MATCH_STATE=m
-CONFIG_IP_NF_MATCH_CONNTRACK=m
 CONFIG_IP_NF_MATCH_OWNER=m
-CONFIG_IP_NF_MATCH_PHYSDEV=m
 CONFIG_IP_NF_MATCH_ADDRTYPE=m
-CONFIG_IP_NF_MATCH_REALM=m
-CONFIG_IP_NF_MATCH_SCTP=m
-CONFIG_IP_NF_MATCH_DCCP=m
-CONFIG_IP_NF_MATCH_COMMENT=m
-CONFIG_IP_NF_MATCH_CONNMARK=m
-CONFIG_IP_NF_MATCH_CONNBYTES=m
 CONFIG_IP_NF_MATCH_HASHLIMIT=m
-CONFIG_IP_NF_MATCH_STRING=m
+CONFIG_IP_NF_MATCH_POLICY=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
 CONFIG_IP_NF_TARGET_LOG=m
 CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_IP_NF_TARGET_TCPMSS=m
-CONFIG_IP_NF_TARGET_NFQUEUE=m
 CONFIG_IP_NF_NAT=m
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
 CONFIG_IP_NF_TARGET_NETMAP=m
 CONFIG_IP_NF_TARGET_SAME=m
-CONFIG_IP_NF_NAT_SNMP_BASIC=m
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
 CONFIG_IP_NF_NAT_TFTP=m
@@ -403,13 +411,9 @@
 CONFIG_IP_NF_TARGET_TOS=m
 CONFIG_IP_NF_TARGET_ECN=m
 CONFIG_IP_NF_TARGET_DSCP=m
-CONFIG_IP_NF_TARGET_MARK=m
-CONFIG_IP_NF_TARGET_CLASSIFY=m
 CONFIG_IP_NF_TARGET_TTL=m
-CONFIG_IP_NF_TARGET_CONNMARK=m
-CONFIG_IP_NF_TARGET_CLUSTERIP=m
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
 CONFIG_IP_NF_RAW=m
-CONFIG_IP_NF_TARGET_NOTRACK=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
@@ -419,26 +423,20 @@
 #
 CONFIG_IP6_NF_QUEUE=m
 CONFIG_IP6_NF_IPTABLES=m
-CONFIG_IP6_NF_MATCH_LIMIT=m
-CONFIG_IP6_NF_MATCH_MAC=m
 CONFIG_IP6_NF_MATCH_RT=m
 CONFIG_IP6_NF_MATCH_OPTS=m
 CONFIG_IP6_NF_MATCH_FRAG=m
 CONFIG_IP6_NF_MATCH_HL=m
 CONFIG_IP6_NF_MATCH_MULTIPORT=m
 CONFIG_IP6_NF_MATCH_OWNER=m
-CONFIG_IP6_NF_MATCH_MARK=m
 CONFIG_IP6_NF_MATCH_IPV6HEADER=m
 CONFIG_IP6_NF_MATCH_AHESP=m
-CONFIG_IP6_NF_MATCH_LENGTH=m
 CONFIG_IP6_NF_MATCH_EUI64=m
-CONFIG_IP6_NF_MATCH_PHYSDEV=m
+CONFIG_IP6_NF_MATCH_POLICY=m
 CONFIG_IP6_NF_FILTER=m
 CONFIG_IP6_NF_TARGET_LOG=m
 CONFIG_IP6_NF_TARGET_REJECT=m
-CONFIG_IP6_NF_TARGET_NFQUEUE=m
 CONFIG_IP6_NF_MANGLE=m
-CONFIG_IP6_NF_TARGET_MARK=m
 CONFIG_IP6_NF_TARGET_HL=m
 CONFIG_IP6_NF_RAW=m
 
@@ -494,6 +492,11 @@
 CONFIG_IPDDP_DECAP=y
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 CONFIG_NET_DIVERT=y
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -553,7 +556,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -663,7 +665,7 @@
 # SCSI Transport Attributes
 #
 CONFIG_SCSI_SPI_ATTRS=y
-CONFIG_SCSI_FC_ATTRS=m
+CONFIG_SCSI_FC_ATTRS=y
 CONFIG_SCSI_ISCSI_ATTRS=m
 CONFIG_SCSI_SAS_ATTRS=m
 
@@ -696,13 +698,7 @@
 # CONFIG_SCSI_IPR is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA24XX is not set
+# CONFIG_SCSI_QLA_FC is not set
 # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
@@ -785,6 +781,7 @@
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -824,6 +821,7 @@
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
@@ -845,8 +843,6 @@
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # Wan interfaces
@@ -926,6 +922,7 @@
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -933,7 +930,6 @@
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -971,6 +967,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -1076,6 +1078,7 @@
 CONFIG_XFS_SECURITY=y
 CONFIG_XFS_POSIX_ACL=y
 # CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
 CONFIG_MINIX_FS=m
 CONFIG_ROMFS_FS=m
 CONFIG_INOTIFY=y
@@ -1118,6 +1121,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1225,6 +1229,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/configs/bigsur_defconfig b/arch/mips/configs/bigsur_defconfig
index 6fd3537..3298410 100644
--- a/arch/mips/configs/bigsur_defconfig
+++ b/arch/mips/configs/bigsur_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:05:54 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:39:53 2006
 #
 CONFIG_MIPS=y
 
@@ -169,29 +169,31 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 # CONFIG_CPUSETS is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -247,7 +249,6 @@
 #
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-CONFIG_BUILD_ELF64=y
 CONFIG_MIPS32_COMPAT=y
 CONFIG_COMPAT=y
 CONFIG_MIPS32_O32=y
@@ -309,6 +310,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -457,6 +463,7 @@
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -478,6 +485,7 @@
 CONFIG_NET_SB1250_MAC=y
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -543,12 +551,15 @@
 #
 # CONFIG_VT is not set
 CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_COMPUTONE is not set
 # CONFIG_ROCKETPORT is not set
 # CONFIG_CYCLADES is not set
 # CONFIG_DIGIEPCA is not set
+# CONFIG_MOXA_INTELLIO is not set
 # CONFIG_MOXA_SMARTIO is not set
 # CONFIG_ISI is not set
 # CONFIG_SYNCLINKMP is not set
+# CONFIG_SYNCLINK_GT is not set
 # CONFIG_N_HDLC is not set
 # CONFIG_SPECIALIX is not set
 # CONFIG_SX is not set
@@ -564,7 +575,6 @@
 #
 # Non-8250 serial port support
 #
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -655,6 +665,12 @@
 CONFIG_I2C_DEBUG_CHIP=y
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -732,12 +748,12 @@
 CONFIG_EXT2_FS_SECURITY=y
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -770,6 +786,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 # CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -831,18 +848,20 @@
 # Kernel hacking
 #
 CONFIG_PRINTK_TIME=y
-CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
 CONFIG_LOG_BUF_SHIFT=16
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_MUTEXES=y
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_INFO is not set
 # CONFIG_DEBUG_FS is not set
 # CONFIG_DEBUG_VM is not set
+CONFIG_FORCED_INLINING=y
 # CONFIG_RCU_TORTURE_TEST is not set
 CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE=""
diff --git a/arch/mips/configs/capcella_defconfig b/arch/mips/configs/capcella_defconfig
index 5261e29..6c2961a 100644
--- a/arch/mips/configs/capcella_defconfig
+++ b/arch/mips/configs/capcella_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:05:55 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:39:54 2006
 #
 CONFIG_MIPS=y
 
@@ -63,9 +63,9 @@
 # CONFIG_TOSHIBA_JMR3927 is not set
 # CONFIG_TOSHIBA_RBTX4927 is not set
 # CONFIG_TOSHIBA_RBTX4938 is not set
-# CONFIG_NEC_CMBVR4133 is not set
 # CONFIG_CASIO_E55 is not set
 # CONFIG_IBM_WORKPAD is not set
+# CONFIG_NEC_CMBVR4133 is not set
 # CONFIG_TANBAC_TB022X is not set
 # CONFIG_VICTOR_MPC30X is not set
 CONFIG_ZAO_CAPCELLA=y
@@ -90,7 +90,7 @@
 # CONFIG_CPU_MIPS64_R2 is not set
 # CONFIG_CPU_R3000 is not set
 # CONFIG_CPU_TX39XX is not set
-CONFIG_CPU_VR41XX=y
+# CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
 # CONFIG_CPU_TX49XX is not set
@@ -103,23 +103,18 @@
 # CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_RM9000 is not set
 # CONFIG_CPU_SB1 is not set
-CONFIG_SYS_HAS_CPU_VR41XX=y
-CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
-CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
 
 #
 # Kernel type
 #
-CONFIG_32BIT=y
+# CONFIG_32BIT is not set
 # CONFIG_64BIT is not set
 CONFIG_PAGE_SIZE_4KB=y
 # CONFIG_PAGE_SIZE_8KB is not set
 # CONFIG_PAGE_SIZE_16KB is not set
 # CONFIG_PAGE_SIZE_64KB is not set
 # CONFIG_MIPS_MT is not set
-# CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_LLSC=y
 CONFIG_CPU_HAS_SYNC=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
@@ -155,26 +150,28 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -190,7 +187,6 @@
 #
 # Block layer
 #
-# CONFIG_LBD is not set
 
 #
 # IO Schedulers
@@ -228,7 +224,6 @@
 #
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-CONFIG_TRAD_SIGNALS=y
 
 #
 # Networking
@@ -286,6 +281,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -306,7 +306,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -444,6 +443,7 @@
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -487,6 +487,7 @@
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
@@ -508,8 +509,6 @@
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # Wan interfaces
@@ -579,11 +578,6 @@
 #
 # Non-8250 serial port support
 #
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_SERIAL_VR41XX=y
-CONFIG_SERIAL_VR41XX_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -599,7 +593,6 @@
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
 # CONFIG_GEN_RTC is not set
-# CONFIG_RTC_VR41XX is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -608,7 +601,6 @@
 # Ftape, the floppy tape device driver
 #
 # CONFIG_DRM is not set
-CONFIG_GPIO_VR41XX=y
 # CONFIG_RAW_DRIVER is not set
 
 #
@@ -623,6 +615,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -704,11 +702,11 @@
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -741,6 +739,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -803,6 +802,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/configs/cobalt_defconfig b/arch/mips/configs/cobalt_defconfig
index 1d3ee18..8336b21 100644
--- a/arch/mips/configs/cobalt_defconfig
+++ b/arch/mips/configs/cobalt_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:05:57 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:39:55 2006
 #
 CONFIG_MIPS=y
 
@@ -150,26 +150,28 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -271,6 +273,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -291,7 +298,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=y
 CONFIG_IEEE80211_CRYPT_CCMP=y
-CONFIG_IEEE80211_CRYPT_TKIP=y
 
 #
 # Device Drivers
@@ -364,9 +370,38 @@
 # IDE chipset support/bugfixes
 #
 CONFIG_IDE_GENERIC=y
-# CONFIG_BLK_DEV_IDEPCI is not set
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_IDEPCI_SHARE_IRQ is not set
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_GENERIC is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+# CONFIG_IDEDMA_PCI_AUTO is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT821X is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+CONFIG_BLK_DEV_VIA82CXXX=y
 # CONFIG_IDE_ARM is not set
-# CONFIG_BLK_DEV_IDEDMA is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_BLK_DEV_HD is not set
 
@@ -433,11 +468,21 @@
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
 #
-# CONFIG_NET_TULIP is not set
+CONFIG_NET_TULIP=y
+CONFIG_DE2104X=y
+CONFIG_TULIP=y
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO is not set
+# CONFIG_TULIP_NAPI is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_DM9102 is not set
+# CONFIG_ULI526X is not set
 # CONFIG_HP100 is not set
 # CONFIG_NET_PCI is not set
 
@@ -453,6 +498,7 @@
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -473,8 +519,6 @@
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=y
 
 #
 # Wan interfaces
@@ -550,6 +594,7 @@
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -557,7 +602,6 @@
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -595,6 +639,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -678,12 +728,12 @@
 CONFIG_EXT2_FS_SECURITY=y
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -716,6 +766,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=y
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -774,6 +825,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/configs/db1000_defconfig b/arch/mips/configs/db1000_defconfig
index 18ac792..7f07140 100644
--- a/arch/mips/configs/db1000_defconfig
+++ b/arch/mips/configs/db1000_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:05:59 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:39:56 2006
 #
 CONFIG_MIPS=y
 
@@ -151,26 +151,29 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
 
 #
 # Loadable module support
@@ -285,6 +288,21 @@
 CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NETFILTER_NETLINK_LOG=m
 # CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -312,6 +330,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -320,6 +343,7 @@
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+CONFIG_NET_CLS_ROUTE=y
 
 #
 # Network testing
@@ -332,7 +356,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -395,6 +418,7 @@
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
@@ -512,6 +536,7 @@
 CONFIG_MII=m
 CONFIG_MIPS_AU1X00_ENET=y
 # CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -625,13 +650,13 @@
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_CS=m
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 CONFIG_SERIAL_8250_AU1X00=y
 
 #
 # Non-8250 serial port support
 #
-# CONFIG_SERIAL_AU1X00 is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
@@ -676,6 +701,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -773,6 +804,7 @@
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -805,6 +837,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -909,6 +942,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
@@ -963,3 +997,7 @@
 CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=m
 CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
diff --git a/arch/mips/configs/db1100_defconfig b/arch/mips/configs/db1100_defconfig
index 4f55f74..98590ca 100644
--- a/arch/mips/configs/db1100_defconfig
+++ b/arch/mips/configs/db1100_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:00 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:39:57 2006
 #
 CONFIG_MIPS=y
 
@@ -151,26 +151,29 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
 
 #
 # Loadable module support
@@ -274,6 +277,21 @@
 CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NETFILTER_NETLINK_LOG=m
 # CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -301,6 +319,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -309,6 +332,7 @@
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+CONFIG_NET_CLS_ROUTE=y
 
 #
 # Network testing
@@ -321,7 +345,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -384,6 +407,7 @@
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
@@ -501,6 +525,7 @@
 CONFIG_MII=m
 CONFIG_MIPS_AU1X00_ENET=y
 # CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -600,13 +625,13 @@
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 CONFIG_SERIAL_8250_AU1X00=y
 
 #
 # Non-8250 serial port support
 #
-# CONFIG_SERIAL_AU1X00 is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
@@ -644,6 +669,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -772,6 +803,7 @@
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -804,6 +836,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -908,6 +941,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
@@ -962,3 +996,7 @@
 CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=m
 CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
diff --git a/arch/mips/configs/db1200_defconfig b/arch/mips/configs/db1200_defconfig
index 0e5de7d..9288847 100644
--- a/arch/mips/configs/db1200_defconfig
+++ b/arch/mips/configs/db1200_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:03 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:39:58 2006
 #
 CONFIG_MIPS=y
 
@@ -151,27 +151,30 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
 
 #
 # Loadable module support
@@ -279,6 +282,21 @@
 #
 # CONFIG_NETFILTER_NETLINK is not set
 # CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -306,6 +324,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -314,6 +337,7 @@
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+CONFIG_NET_CLS_ROUTE=y
 
 #
 # Network testing
@@ -385,6 +409,7 @@
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
@@ -568,6 +593,7 @@
 CONFIG_MII=m
 # CONFIG_MIPS_AU1X00_ENET is not set
 # CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -665,13 +691,13 @@
 CONFIG_SERIAL_8250_CONSOLE=y
 # CONFIG_SERIAL_8250_CS is not set
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 CONFIG_SERIAL_8250_AU1X00=y
 
 #
 # Non-8250 serial port support
 #
-# CONFIG_SERIAL_AU1X00 is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
@@ -716,6 +742,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -842,6 +874,7 @@
 # CONFIG_JFS_STATISTICS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -881,6 +914,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 # CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -990,6 +1024,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
@@ -1020,3 +1055,7 @@
 CONFIG_LIBCRC32C=y
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
diff --git a/arch/mips/configs/db1500_defconfig b/arch/mips/configs/db1500_defconfig
index 86e7be8..5a415b1 100644
--- a/arch/mips/configs/db1500_defconfig
+++ b/arch/mips/configs/db1500_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:05 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:39:59 2006
 #
 CONFIG_MIPS=y
 
@@ -153,26 +153,29 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
 
 #
 # Loadable module support
@@ -293,6 +296,21 @@
 CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NETFILTER_NETLINK_LOG=m
 # CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -320,6 +338,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -328,6 +351,7 @@
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+CONFIG_NET_CLS_ROUTE=y
 
 #
 # Network testing
@@ -340,7 +364,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -403,6 +426,7 @@
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
@@ -561,6 +585,7 @@
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -581,6 +606,7 @@
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -601,8 +627,6 @@
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # PCMCIA network device support
@@ -692,16 +716,15 @@
 CONFIG_SERIAL_8250_CONSOLE=y
 # CONFIG_SERIAL_8250_CS is not set
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 CONFIG_SERIAL_8250_AU1X00=y
 
 #
 # Non-8250 serial port support
 #
-# CONFIG_SERIAL_AU1X00 is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -746,6 +769,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -788,8 +817,6 @@
 # Advanced Linux Sound Architecture
 #
 CONFIG_SND=m
-CONFIG_SND_AC97_CODEC=m
-CONFIG_SND_AC97_BUS=m
 CONFIG_SND_TIMER=m
 CONFIG_SND_PCM=m
 CONFIG_SND_RAWMIDI=m
@@ -799,13 +826,16 @@
 CONFIG_SND_MIXER_OSS=m
 CONFIG_SND_PCM_OSS=m
 CONFIG_SND_SEQUENCER_OSS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
 # CONFIG_SND_VERBOSE_PRINTK is not set
 # CONFIG_SND_DEBUG is not set
-CONFIG_SND_GENERIC_DRIVER=y
 
 #
 # Generic devices
 #
+CONFIG_SND_AC97_CODEC=m
+CONFIG_SND_AC97_BUS=m
 # CONFIG_SND_DUMMY is not set
 CONFIG_SND_VIRMIDI=m
 CONFIG_SND_MTPAV=m
@@ -815,6 +845,7 @@
 #
 # PCI devices
 #
+# CONFIG_SND_AD1889 is not set
 # CONFIG_SND_ALI5451 is not set
 # CONFIG_SND_ATIIXP is not set
 # CONFIG_SND_ATIIXP_MODEM is not set
@@ -823,38 +854,38 @@
 # CONFIG_SND_AU8830 is not set
 # CONFIG_SND_AZT3328 is not set
 # CONFIG_SND_BT87X is not set
-# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
 # CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
 # CONFIG_SND_EMU10K1 is not set
 # CONFIG_SND_EMU10K1X is not set
-# CONFIG_SND_CA0106 is not set
-# CONFIG_SND_KORG1212 is not set
-# CONFIG_SND_MIXART is not set
-# CONFIG_SND_NM256 is not set
-# CONFIG_SND_RME32 is not set
-# CONFIG_SND_RME96 is not set
-# CONFIG_SND_RME9652 is not set
-# CONFIG_SND_HDSP is not set
-# CONFIG_SND_HDSPM is not set
-# CONFIG_SND_TRIDENT is not set
-# CONFIG_SND_YMFPCI is not set
-# CONFIG_SND_AD1889 is not set
-# CONFIG_SND_CMIPCI is not set
 # CONFIG_SND_ENS1370 is not set
 # CONFIG_SND_ENS1371 is not set
 # CONFIG_SND_ES1938 is not set
 # CONFIG_SND_ES1968 is not set
-# CONFIG_SND_MAESTRO3 is not set
 # CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
 # CONFIG_SND_ICE1712 is not set
 # CONFIG_SND_ICE1724 is not set
 # CONFIG_SND_INTEL8X0 is not set
 # CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
 # CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
 # CONFIG_SND_VIA82XX is not set
 # CONFIG_SND_VIA82XX_MODEM is not set
 # CONFIG_SND_VX222 is not set
-# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_YMFPCI is not set
 
 #
 # ALSA MIPS devices
@@ -939,12 +970,14 @@
 # may also be needed; see USB_STORAGE Help for more information
 #
 # CONFIG_USB_STORAGE is not set
+# CONFIG_USB_LIBUSUAL is not set
 
 #
 # USB Input Devices
 #
 CONFIG_USB_HID=y
 CONFIG_USB_HIDINPUT=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
 # CONFIG_HID_FF is not set
 # CONFIG_USB_HIDDEV is not set
 # CONFIG_USB_AIPTEK is not set
@@ -958,6 +991,7 @@
 CONFIG_USB_YEALINK=m
 # CONFIG_USB_XPAD is not set
 # CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
 # CONFIG_USB_KEYSPAN_REMOTE is not set
 # CONFIG_USB_APPLETOUCH is not set
 
@@ -1057,6 +1091,7 @@
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -1089,6 +1124,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1193,6 +1229,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
@@ -1247,3 +1284,7 @@
 CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=m
 CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
diff --git a/arch/mips/configs/db1550_defconfig b/arch/mips/configs/db1550_defconfig
index ea5ab0c..8dc1f18 100644
--- a/arch/mips/configs/db1550_defconfig
+++ b/arch/mips/configs/db1550_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:07 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:00 2006
 #
 CONFIG_MIPS=y
 
@@ -152,26 +152,29 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
 
 #
 # Loadable module support
@@ -292,6 +295,21 @@
 CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NETFILTER_NETLINK_LOG=m
 # CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -319,6 +337,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -327,6 +350,7 @@
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+CONFIG_NET_CLS_ROUTE=y
 
 #
 # Network testing
@@ -339,7 +363,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -402,6 +425,7 @@
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
@@ -593,6 +617,7 @@
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -613,6 +638,7 @@
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -633,8 +659,6 @@
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # PCMCIA network device support
@@ -732,16 +756,15 @@
 CONFIG_SERIAL_8250_CONSOLE=y
 # CONFIG_SERIAL_8250_CS is not set
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 CONFIG_SERIAL_8250_AU1X00=y
 
 #
 # Non-8250 serial port support
 #
-# CONFIG_SERIAL_AU1X00 is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -786,6 +809,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -878,6 +907,7 @@
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -910,6 +940,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1014,6 +1045,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
@@ -1068,3 +1100,7 @@
 CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=m
 CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
diff --git a/arch/mips/configs/ddb5476_defconfig b/arch/mips/configs/ddb5476_defconfig
index a81e2de..8fae63e 100644
--- a/arch/mips/configs/ddb5476_defconfig
+++ b/arch/mips/configs/ddb5476_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:09 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:02 2006
 #
 CONFIG_MIPS=y
 
@@ -151,26 +151,28 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -276,6 +278,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -296,7 +303,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=y
 CONFIG_IEEE80211_CRYPT_CCMP=y
-CONFIG_IEEE80211_CRYPT_TKIP=y
 
 #
 # Device Drivers
@@ -445,6 +451,7 @@
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_DM9000 is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 
 #
@@ -469,6 +476,7 @@
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -489,8 +497,6 @@
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=y
 
 #
 # Wan interfaces
@@ -566,6 +572,7 @@
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -573,7 +580,6 @@
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -611,6 +617,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -669,7 +681,6 @@
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_SMIVGX is not set
-# CONFIG_FB_CYBLA is not set
 # CONFIG_FB_TRIDENT is not set
 # CONFIG_FB_VIRTUAL is not set
 
@@ -729,11 +740,11 @@
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -766,6 +777,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=y
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -825,6 +837,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/configs/ddb5477_defconfig b/arch/mips/configs/ddb5477_defconfig
index f1c27c2..a0fcd44 100644
--- a/arch/mips/configs/ddb5477_defconfig
+++ b/arch/mips/configs/ddb5477_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:11 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:02 2006
 #
 CONFIG_MIPS=y
 
@@ -151,26 +151,28 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -275,6 +277,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -295,7 +302,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=y
 CONFIG_IEEE80211_CRYPT_CCMP=y
-CONFIG_IEEE80211_CRYPT_TKIP=y
 
 #
 # Device Drivers
@@ -414,6 +420,7 @@
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -453,6 +460,7 @@
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
@@ -474,8 +482,6 @@
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=y
 
 #
 # Wan interfaces
@@ -551,6 +557,7 @@
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -558,7 +565,6 @@
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -596,6 +602,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -677,11 +689,11 @@
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -714,6 +726,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=y
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -776,6 +789,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/configs/decstation_defconfig b/arch/mips/configs/decstation_defconfig
index 08a4de6..5a181ea 100644
--- a/arch/mips/configs/decstation_defconfig
+++ b/arch/mips/configs/decstation_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:13 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:03 2006
 #
 CONFIG_MIPS=y
 
@@ -150,27 +150,29 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -278,6 +280,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -298,7 +305,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -436,6 +442,7 @@
 #
 CONFIG_NET_ETHERNET=y
 # CONFIG_MII is not set
+# CONFIG_DM9000 is not set
 CONFIG_DECLANCE=y
 
 #
@@ -539,6 +546,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -636,12 +649,12 @@
 CONFIG_EXT2_FS_SECURITY=y
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -674,6 +687,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -734,6 +748,7 @@
 # CONFIG_SGI_PARTITION is not set
 CONFIG_ULTRIX_PARTITION=y
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
 # CONFIG_EFI_PARTITION is not set
 
 #
@@ -750,18 +765,20 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
-CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_MUTEXES=y
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_INFO is not set
 # CONFIG_DEBUG_FS is not set
 # CONFIG_DEBUG_VM is not set
+CONFIG_FORCED_INLINING=y
 # CONFIG_RCU_TORTURE_TEST is not set
 CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE=""
diff --git a/arch/mips/configs/e55_defconfig b/arch/mips/configs/e55_defconfig
index c9070ce..8fbfc06 100644
--- a/arch/mips/configs/e55_defconfig
+++ b/arch/mips/configs/e55_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:14 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:04 2006
 #
 CONFIG_MIPS=y
 
@@ -63,9 +63,9 @@
 # CONFIG_TOSHIBA_JMR3927 is not set
 # CONFIG_TOSHIBA_RBTX4927 is not set
 # CONFIG_TOSHIBA_RBTX4938 is not set
-# CONFIG_NEC_CMBVR4133 is not set
 CONFIG_CASIO_E55=y
 # CONFIG_IBM_WORKPAD is not set
+# CONFIG_NEC_CMBVR4133 is not set
 # CONFIG_TANBAC_TB022X is not set
 # CONFIG_VICTOR_MPC30X is not set
 # CONFIG_ZAO_CAPCELLA is not set
@@ -88,7 +88,7 @@
 # CONFIG_CPU_MIPS64_R2 is not set
 # CONFIG_CPU_R3000 is not set
 # CONFIG_CPU_TX39XX is not set
-CONFIG_CPU_VR41XX=y
+# CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
 # CONFIG_CPU_TX49XX is not set
@@ -101,23 +101,18 @@
 # CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_RM9000 is not set
 # CONFIG_CPU_SB1 is not set
-CONFIG_SYS_HAS_CPU_VR41XX=y
-CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
-CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
 
 #
 # Kernel type
 #
-CONFIG_32BIT=y
+# CONFIG_32BIT is not set
 # CONFIG_64BIT is not set
 CONFIG_PAGE_SIZE_4KB=y
 # CONFIG_PAGE_SIZE_8KB is not set
 # CONFIG_PAGE_SIZE_16KB is not set
 # CONFIG_PAGE_SIZE_64KB is not set
 # CONFIG_MIPS_MT is not set
-# CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_LLSC=y
 CONFIG_CPU_HAS_SYNC=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
@@ -153,26 +148,28 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -188,7 +185,6 @@
 #
 # Block layer
 #
-# CONFIG_LBD is not set
 
 #
 # IO Schedulers
@@ -223,7 +219,6 @@
 #
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-CONFIG_TRAD_SIGNALS=y
 
 #
 # Networking
@@ -278,6 +273,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -298,7 +298,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -433,6 +432,7 @@
 # CONFIG_MII is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_DM9000 is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_AT1700 is not set
 # CONFIG_DEPCA is not set
@@ -531,10 +531,6 @@
 #
 # Non-8250 serial port support
 #
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_SERIAL_VR41XX=y
-CONFIG_SERIAL_VR41XX_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -563,14 +559,12 @@
 # CONFIG_WDT is not set
 # CONFIG_RTC is not set
 # CONFIG_GEN_RTC is not set
-# CONFIG_RTC_VR41XX is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 
 #
 # Ftape, the floppy tape device driver
 #
-CONFIG_GPIO_VR41XX=y
 # CONFIG_RAW_DRIVER is not set
 
 #
@@ -585,6 +579,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -665,11 +665,11 @@
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -702,6 +702,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -763,6 +764,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/configs/ev64120_defconfig b/arch/mips/configs/ev64120_defconfig
index aa24d85..f2d43be 100644
--- a/arch/mips/configs/ev64120_defconfig
+++ b/arch/mips/configs/ev64120_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:16 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:05 2006
 #
 CONFIG_MIPS=y
 
@@ -153,26 +153,28 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -282,6 +284,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -302,7 +309,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -420,6 +426,7 @@
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -440,6 +447,7 @@
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -460,8 +468,6 @@
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # Wan interfaces
@@ -545,6 +551,7 @@
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -552,7 +559,6 @@
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -590,6 +596,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -671,11 +683,11 @@
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -708,6 +720,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -767,6 +780,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/configs/ev96100_defconfig b/arch/mips/configs/ev96100_defconfig
index eeed0e5..ac5841c 100644
--- a/arch/mips/configs/ev96100_defconfig
+++ b/arch/mips/configs/ev96100_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:18 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:06 2006
 #
 CONFIG_MIPS=y
 
@@ -157,26 +157,28 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -284,6 +286,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -304,7 +311,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -407,6 +413,7 @@
 CONFIG_NET_ETHERNET=y
 # CONFIG_MII is not set
 CONFIG_MIPS_GT96100ETH=y
+# CONFIG_DM9000 is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -496,6 +503,7 @@
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -538,6 +546,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -617,11 +631,11 @@
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -654,6 +668,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -713,6 +728,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/configs/ip22_defconfig b/arch/mips/configs/ip22_defconfig
index e56351a..42d5cd7 100644
--- a/arch/mips/configs/ip22_defconfig
+++ b/arch/mips/configs/ip22_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:20 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:39:51 2006
 #
 CONFIG_MIPS=y
 
@@ -158,27 +158,29 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -317,6 +319,28 @@
 CONFIG_NETFILTER_NETLINK=m
 CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -335,39 +359,23 @@
 CONFIG_IP_NF_PPTP=m
 CONFIG_IP_NF_QUEUE=m
 CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
 CONFIG_IP_NF_MATCH_IPRANGE=m
-CONFIG_IP_NF_MATCH_MAC=m
-CONFIG_IP_NF_MATCH_PKTTYPE=m
-CONFIG_IP_NF_MATCH_MARK=m
 CONFIG_IP_NF_MATCH_MULTIPORT=m
 CONFIG_IP_NF_MATCH_TOS=m
 CONFIG_IP_NF_MATCH_RECENT=m
 CONFIG_IP_NF_MATCH_ECN=m
 CONFIG_IP_NF_MATCH_DSCP=m
 CONFIG_IP_NF_MATCH_AH_ESP=m
-CONFIG_IP_NF_MATCH_LENGTH=m
 CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_TCPMSS=m
-CONFIG_IP_NF_MATCH_HELPER=m
-CONFIG_IP_NF_MATCH_STATE=m
-CONFIG_IP_NF_MATCH_CONNTRACK=m
 CONFIG_IP_NF_MATCH_OWNER=m
 CONFIG_IP_NF_MATCH_ADDRTYPE=m
-CONFIG_IP_NF_MATCH_REALM=m
-CONFIG_IP_NF_MATCH_SCTP=m
-CONFIG_IP_NF_MATCH_DCCP=m
-CONFIG_IP_NF_MATCH_COMMENT=m
-CONFIG_IP_NF_MATCH_CONNMARK=m
-CONFIG_IP_NF_MATCH_CONNBYTES=m
 CONFIG_IP_NF_MATCH_HASHLIMIT=m
-CONFIG_IP_NF_MATCH_STRING=m
+CONFIG_IP_NF_MATCH_POLICY=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
 CONFIG_IP_NF_TARGET_LOG=m
 CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_IP_NF_TARGET_TCPMSS=m
-CONFIG_IP_NF_TARGET_NFQUEUE=m
 CONFIG_IP_NF_NAT=m
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
@@ -384,13 +392,9 @@
 CONFIG_IP_NF_TARGET_TOS=m
 CONFIG_IP_NF_TARGET_ECN=m
 CONFIG_IP_NF_TARGET_DSCP=m
-CONFIG_IP_NF_TARGET_MARK=m
-CONFIG_IP_NF_TARGET_CLASSIFY=m
 CONFIG_IP_NF_TARGET_TTL=m
-CONFIG_IP_NF_TARGET_CONNMARK=m
 CONFIG_IP_NF_TARGET_CLUSTERIP=m
 CONFIG_IP_NF_RAW=m
-CONFIG_IP_NF_TARGET_NOTRACK=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
@@ -400,25 +404,20 @@
 #
 CONFIG_IP6_NF_QUEUE=m
 CONFIG_IP6_NF_IPTABLES=m
-CONFIG_IP6_NF_MATCH_LIMIT=m
-CONFIG_IP6_NF_MATCH_MAC=m
 CONFIG_IP6_NF_MATCH_RT=m
 CONFIG_IP6_NF_MATCH_OPTS=m
 CONFIG_IP6_NF_MATCH_FRAG=m
 CONFIG_IP6_NF_MATCH_HL=m
 CONFIG_IP6_NF_MATCH_MULTIPORT=m
 CONFIG_IP6_NF_MATCH_OWNER=m
-CONFIG_IP6_NF_MATCH_MARK=m
 CONFIG_IP6_NF_MATCH_IPV6HEADER=m
 CONFIG_IP6_NF_MATCH_AHESP=m
-CONFIG_IP6_NF_MATCH_LENGTH=m
 CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_POLICY=m
 CONFIG_IP6_NF_FILTER=m
 CONFIG_IP6_NF_TARGET_LOG=m
 CONFIG_IP6_NF_TARGET_REJECT=m
-CONFIG_IP6_NF_TARGET_NFQUEUE=m
 CONFIG_IP6_NF_MANGLE=m
-CONFIG_IP6_NF_TARGET_MARK=m
 CONFIG_IP6_NF_TARGET_HL=m
 CONFIG_IP6_NF_RAW=m
 
@@ -445,6 +444,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 CONFIG_NET_DIVERT=y
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -504,7 +508,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -641,6 +644,7 @@
 #
 CONFIG_NET_ETHERNET=y
 # CONFIG_MII is not set
+# CONFIG_DM9000 is not set
 CONFIG_SGISEEQ=y
 
 #
@@ -787,6 +791,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -892,6 +902,7 @@
 CONFIG_XFS_SECURITY=y
 # CONFIG_XFS_POSIX_ACL is not set
 # CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
 CONFIG_MINIX_FS=m
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -934,6 +945,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1007,6 +1019,7 @@
 CONFIG_SGI_PARTITION=y
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
 # CONFIG_EFI_PARTITION is not set
 
 #
@@ -1062,6 +1075,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/configs/ip27_defconfig b/arch/mips/configs/ip27_defconfig
index 58c22cd..8c40590 100644
--- a/arch/mips/configs/ip27_defconfig
+++ b/arch/mips/configs/ip27_defconfig
@@ -132,6 +132,7 @@
 CONFIG_NEED_MULTIPLE_NODES=y
 # CONFIG_SPARSEMEM_STATIC is not set
 CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_MIGRATION=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=64
 CONFIG_PREEMPT_NONE=y
@@ -158,28 +159,30 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_CPUSETS=y
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -234,7 +237,6 @@
 #
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-CONFIG_BUILD_ELF64=y
 CONFIG_MIPS32_COMPAT=y
 CONFIG_COMPAT=y
 CONFIG_MIPS32_O32=y
@@ -290,6 +292,10 @@
 #
 # CONFIG_IP_SCTP is not set
 
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_VLAN_8021Q is not set
@@ -357,7 +363,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -368,7 +373,7 @@
 #
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
-CONFIG_FW_LOADER=m
+CONFIG_FW_LOADER=y
 
 #
 # Connector - unified userspace <-> kernelspace linker
@@ -442,7 +447,7 @@
 # SCSI Transport Attributes
 #
 CONFIG_SCSI_SPI_ATTRS=y
-# CONFIG_SCSI_FC_ATTRS is not set
+CONFIG_SCSI_FC_ATTRS=y
 CONFIG_SCSI_ISCSI_ATTRS=m
 CONFIG_SCSI_SAS_ATTRS=m
 
@@ -470,13 +475,7 @@
 # CONFIG_SCSI_IPR is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 CONFIG_SCSI_QLOGIC_1280=y
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA24XX is not set
+# CONFIG_SCSI_QLA_FC is not set
 # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
@@ -561,6 +560,7 @@
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -581,6 +581,7 @@
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -601,8 +602,6 @@
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # Wan interfaces
@@ -656,6 +655,7 @@
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_MANY_PORTS=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
@@ -706,6 +706,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -801,6 +807,7 @@
 CONFIG_XFS_SECURITY=y
 CONFIG_XFS_POSIX_ACL=y
 # CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -834,6 +841,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -894,6 +902,7 @@
 CONFIG_SGI_PARTITION=y
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
 # CONFIG_EFI_PARTITION is not set
 
 #
@@ -910,6 +919,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=15
 CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/configs/ip32_defconfig b/arch/mips/configs/ip32_defconfig
index a34db6e..7fdcaf5 100644
--- a/arch/mips/configs/ip32_defconfig
+++ b/arch/mips/configs/ip32_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:24 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:09 2006
 #
 CONFIG_MIPS=y
 
@@ -158,26 +158,28 @@
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -224,7 +226,6 @@
 #
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_MISC=y
-# CONFIG_BUILD_ELF64 is not set
 CONFIG_MIPS32_COMPAT=y
 CONFIG_COMPAT=y
 CONFIG_MIPS32_O32=y
@@ -286,6 +287,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -306,7 +312,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=y
 CONFIG_IEEE80211_CRYPT_CCMP=y
-CONFIG_IEEE80211_CRYPT_TKIP=y
 
 #
 # Device Drivers
@@ -392,7 +397,7 @@
 # SCSI Transport Attributes
 #
 CONFIG_SCSI_SPI_ATTRS=y
-# CONFIG_SCSI_FC_ATTRS is not set
+CONFIG_SCSI_FC_ATTRS=y
 # CONFIG_SCSI_ISCSI_ATTRS is not set
 CONFIG_SCSI_SAS_ATTRS=y
 
@@ -425,13 +430,7 @@
 # CONFIG_SCSI_IPR is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA24XX is not set
+# CONFIG_SCSI_QLA_FC is not set
 # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
@@ -498,6 +497,7 @@
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -518,6 +518,7 @@
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -538,8 +539,6 @@
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=y
 
 #
 # Wan interfaces
@@ -617,6 +616,7 @@
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -624,7 +624,6 @@
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -662,6 +661,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -743,11 +748,11 @@
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -780,6 +785,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=y
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -835,6 +841,7 @@
 CONFIG_SGI_PARTITION=y
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
 # CONFIG_EFI_PARTITION is not set
 
 #
@@ -851,6 +858,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/configs/it8172_defconfig b/arch/mips/configs/it8172_defconfig
index b5fa963..c716996 100644
--- a/arch/mips/configs/it8172_defconfig
+++ b/arch/mips/configs/it8172_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:26 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:10 2006
 #
 CONFIG_MIPS=y
 
@@ -153,26 +153,29 @@
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
 
 #
 # Loadable module support
@@ -281,6 +284,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -301,7 +309,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -362,6 +369,7 @@
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
@@ -500,6 +508,7 @@
 #
 CONFIG_NET_ETHERNET=y
 # CONFIG_MII is not set
+# CONFIG_DM9000 is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -593,6 +602,7 @@
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -635,6 +645,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -728,11 +744,11 @@
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -765,6 +781,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -826,6 +843,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/configs/ivr_defconfig b/arch/mips/configs/ivr_defconfig
index 7138693..a8376d1 100644
--- a/arch/mips/configs/ivr_defconfig
+++ b/arch/mips/configs/ivr_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:27 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:11 2006
 #
 CONFIG_MIPS=y
 
@@ -150,26 +150,28 @@
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -280,6 +282,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -300,7 +307,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -440,6 +446,7 @@
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -460,6 +467,7 @@
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -480,8 +488,6 @@
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # Wan interfaces
@@ -560,6 +566,7 @@
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -567,7 +574,6 @@
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -604,6 +610,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -685,11 +697,11 @@
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -722,6 +734,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -781,6 +794,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/configs/jaguar-atx_defconfig b/arch/mips/configs/jaguar-atx_defconfig
index 14fb468..3160153 100644
--- a/arch/mips/configs/jaguar-atx_defconfig
+++ b/arch/mips/configs/jaguar-atx_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:29 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:12 2006
 #
 CONFIG_MIPS=y
 
@@ -158,27 +158,28 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_INITRAMFS_SOURCE=""
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -186,6 +187,7 @@
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
 CONFIG_MODULE_SRCVERSION_ALL=y
 CONFIG_KMOD=y
 
@@ -294,7 +296,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -411,6 +412,7 @@
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -469,8 +471,6 @@
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # Wan interfaces
@@ -515,6 +515,7 @@
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -522,7 +523,6 @@
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -558,6 +558,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -631,7 +637,6 @@
 #
 # CONFIG_EXT2_FS is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
@@ -710,6 +715,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/configs/jmr3927_defconfig b/arch/mips/configs/jmr3927_defconfig
index a8ded3d..53fbef1 100644
--- a/arch/mips/configs/jmr3927_defconfig
+++ b/arch/mips/configs/jmr3927_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:31 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:13 2006
 #
 CONFIG_MIPS=y
 
@@ -148,26 +148,28 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -272,6 +274,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -292,7 +299,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=y
 CONFIG_IEEE80211_CRYPT_CCMP=y
-CONFIG_IEEE80211_CRYPT_TKIP=y
 
 #
 # Device Drivers
@@ -411,6 +417,7 @@
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -431,6 +438,7 @@
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -451,8 +459,6 @@
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=y
 
 #
 # Wan interfaces
@@ -529,6 +535,7 @@
 # CONFIG_MOXA_SMARTIO is not set
 # CONFIG_ISI is not set
 # CONFIG_SYNCLINKMP is not set
+# CONFIG_SYNCLINK_GT is not set
 # CONFIG_N_HDLC is not set
 # CONFIG_RISCOM8 is not set
 # CONFIG_SPECIALIX is not set
@@ -545,7 +552,6 @@
 # Non-8250 serial port support
 #
 CONFIG_HAS_TXX9_SERIAL=y
-# CONFIG_SERIAL_JSM is not set
 # CONFIG_UNIX98_PTYS is not set
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -583,6 +589,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -641,7 +653,6 @@
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_SMIVGX is not set
-# CONFIG_FB_CYBLA is not set
 # CONFIG_FB_TRIDENT is not set
 # CONFIG_FB_VIRTUAL is not set
 
@@ -698,11 +709,11 @@
 #
 # CONFIG_EXT2_FS is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -735,6 +746,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=y
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -794,6 +806,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/configs/lasat200_defconfig b/arch/mips/configs/lasat200_defconfig
index 6c5df76..ef0fa9f 100644
--- a/arch/mips/configs/lasat200_defconfig
+++ b/arch/mips/configs/lasat200_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:33 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:14 2006
 #
 CONFIG_MIPS=y
 
@@ -156,26 +156,29 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
 
 #
 # Loadable module support
@@ -282,6 +285,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -302,7 +310,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -365,6 +372,7 @@
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
@@ -548,6 +556,7 @@
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -568,6 +577,7 @@
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -588,8 +598,6 @@
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # Wan interfaces
@@ -665,6 +673,7 @@
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -672,7 +681,6 @@
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -710,6 +718,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -801,6 +815,7 @@
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -833,6 +848,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -895,6 +911,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/configs/malta_defconfig b/arch/mips/configs/malta_defconfig
index da0677a..367d279 100644
--- a/arch/mips/configs/malta_defconfig
+++ b/arch/mips/configs/malta_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc5
-# Fri Dec 23 02:21:03 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:15 2006
 #
 CONFIG_MIPS=y
 
@@ -170,26 +170,28 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -341,6 +343,29 @@
 CONFIG_NETFILTER_NETLINK=m
 CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -359,40 +384,23 @@
 CONFIG_IP_NF_PPTP=m
 CONFIG_IP_NF_QUEUE=m
 CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
 CONFIG_IP_NF_MATCH_IPRANGE=m
-CONFIG_IP_NF_MATCH_MAC=m
-CONFIG_IP_NF_MATCH_PKTTYPE=m
-CONFIG_IP_NF_MATCH_MARK=m
 CONFIG_IP_NF_MATCH_MULTIPORT=m
 CONFIG_IP_NF_MATCH_TOS=m
 CONFIG_IP_NF_MATCH_RECENT=m
 CONFIG_IP_NF_MATCH_ECN=m
 CONFIG_IP_NF_MATCH_DSCP=m
 CONFIG_IP_NF_MATCH_AH_ESP=m
-CONFIG_IP_NF_MATCH_LENGTH=m
 CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_TCPMSS=m
-CONFIG_IP_NF_MATCH_HELPER=m
-CONFIG_IP_NF_MATCH_STATE=m
-CONFIG_IP_NF_MATCH_CONNTRACK=m
 CONFIG_IP_NF_MATCH_OWNER=m
-CONFIG_IP_NF_MATCH_PHYSDEV=m
 CONFIG_IP_NF_MATCH_ADDRTYPE=m
-CONFIG_IP_NF_MATCH_REALM=m
-CONFIG_IP_NF_MATCH_SCTP=m
-CONFIG_IP_NF_MATCH_DCCP=m
-CONFIG_IP_NF_MATCH_COMMENT=m
-CONFIG_IP_NF_MATCH_CONNMARK=m
-CONFIG_IP_NF_MATCH_CONNBYTES=m
 CONFIG_IP_NF_MATCH_HASHLIMIT=m
-CONFIG_IP_NF_MATCH_STRING=m
+CONFIG_IP_NF_MATCH_POLICY=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
 CONFIG_IP_NF_TARGET_LOG=m
 CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_IP_NF_TARGET_TCPMSS=m
-CONFIG_IP_NF_TARGET_NFQUEUE=m
 CONFIG_IP_NF_NAT=m
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
@@ -409,13 +417,9 @@
 CONFIG_IP_NF_TARGET_TOS=m
 CONFIG_IP_NF_TARGET_ECN=m
 CONFIG_IP_NF_TARGET_DSCP=m
-CONFIG_IP_NF_TARGET_MARK=m
-CONFIG_IP_NF_TARGET_CLASSIFY=m
 CONFIG_IP_NF_TARGET_TTL=m
-CONFIG_IP_NF_TARGET_CONNMARK=m
 CONFIG_IP_NF_TARGET_CLUSTERIP=m
 CONFIG_IP_NF_RAW=m
-CONFIG_IP_NF_TARGET_NOTRACK=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
@@ -425,26 +429,20 @@
 #
 CONFIG_IP6_NF_QUEUE=m
 CONFIG_IP6_NF_IPTABLES=m
-CONFIG_IP6_NF_MATCH_LIMIT=m
-CONFIG_IP6_NF_MATCH_MAC=m
 CONFIG_IP6_NF_MATCH_RT=m
 CONFIG_IP6_NF_MATCH_OPTS=m
 CONFIG_IP6_NF_MATCH_FRAG=m
 CONFIG_IP6_NF_MATCH_HL=m
 CONFIG_IP6_NF_MATCH_MULTIPORT=m
 CONFIG_IP6_NF_MATCH_OWNER=m
-CONFIG_IP6_NF_MATCH_MARK=m
 CONFIG_IP6_NF_MATCH_IPV6HEADER=m
 CONFIG_IP6_NF_MATCH_AHESP=m
-CONFIG_IP6_NF_MATCH_LENGTH=m
 CONFIG_IP6_NF_MATCH_EUI64=m
-CONFIG_IP6_NF_MATCH_PHYSDEV=m
+CONFIG_IP6_NF_MATCH_POLICY=m
 CONFIG_IP6_NF_FILTER=m
 CONFIG_IP6_NF_TARGET_LOG=m
 CONFIG_IP6_NF_TARGET_REJECT=m
-CONFIG_IP6_NF_TARGET_NFQUEUE=m
 CONFIG_IP6_NF_MANGLE=m
-CONFIG_IP6_NF_TARGET_MARK=m
 CONFIG_IP6_NF_TARGET_HL=m
 CONFIG_IP6_NF_RAW=m
 
@@ -500,6 +498,11 @@
 CONFIG_IPDDP_DECAP=y
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 CONFIG_NET_DIVERT=y
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -559,7 +562,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -734,13 +736,7 @@
 # CONFIG_SCSI_IPR is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=m
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA24XX is not set
+# CONFIG_SCSI_QLA_FC is not set
 # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
@@ -823,6 +819,7 @@
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -862,6 +859,7 @@
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
@@ -883,8 +881,6 @@
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # Wan interfaces
@@ -961,6 +957,7 @@
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -968,7 +965,6 @@
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -1005,6 +1001,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -1110,6 +1112,7 @@
 CONFIG_XFS_SECURITY=y
 CONFIG_XFS_POSIX_ACL=y
 # CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
 CONFIG_MINIX_FS=m
 CONFIG_ROMFS_FS=m
 CONFIG_INOTIFY=y
@@ -1152,6 +1155,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1259,6 +1263,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/configs/mipssim_defconfig b/arch/mips/configs/mipssim_defconfig
index ac39ab7..fe789617 100644
--- a/arch/mips/configs/mipssim_defconfig
+++ b/arch/mips/configs/mipssim_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:37 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:16 2006
 #
 CONFIG_MIPS=y
 
@@ -156,27 +156,29 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -297,6 +299,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 CONFIG_NET_DIVERT=y
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -525,6 +532,7 @@
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=1
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -567,6 +575,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -640,11 +654,11 @@
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_ROMFS_FS=y
 # CONFIG_INOTIFY is not set
@@ -677,6 +691,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 # CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -738,17 +753,19 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
-CONFIG_DEBUG_KERNEL=y
 # CONFIG_MAGIC_SYSRQ is not set
+CONFIG_DEBUG_KERNEL=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_DETECT_SOFTLOCKUP is not set
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_MUTEXES=y
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_INFO=y
 # CONFIG_DEBUG_VM is not set
+CONFIG_FORCED_INLINING=y
 # CONFIG_RCU_TORTURE_TEST is not set
 CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE="nfsroot=192.168.192.169:/u1/mipsel,timeo=20 ip=dhcp"
diff --git a/arch/mips/configs/mpc30x_defconfig b/arch/mips/configs/mpc30x_defconfig
index 2b5ea37..e4620e7 100644
--- a/arch/mips/configs/mpc30x_defconfig
+++ b/arch/mips/configs/mpc30x_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:39 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:17 2006
 #
 CONFIG_MIPS=y
 
@@ -63,9 +63,9 @@
 # CONFIG_TOSHIBA_JMR3927 is not set
 # CONFIG_TOSHIBA_RBTX4927 is not set
 # CONFIG_TOSHIBA_RBTX4938 is not set
-# CONFIG_NEC_CMBVR4133 is not set
 # CONFIG_CASIO_E55 is not set
 # CONFIG_IBM_WORKPAD is not set
+# CONFIG_NEC_CMBVR4133 is not set
 # CONFIG_TANBAC_TB022X is not set
 CONFIG_VICTOR_MPC30X=y
 # CONFIG_ZAO_CAPCELLA is not set
@@ -90,7 +90,7 @@
 # CONFIG_CPU_MIPS64_R2 is not set
 # CONFIG_CPU_R3000 is not set
 # CONFIG_CPU_TX39XX is not set
-CONFIG_CPU_VR41XX=y
+# CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
 # CONFIG_CPU_TX49XX is not set
@@ -103,23 +103,18 @@
 # CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_RM9000 is not set
 # CONFIG_CPU_SB1 is not set
-CONFIG_SYS_HAS_CPU_VR41XX=y
-CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
-CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
 
 #
 # Kernel type
 #
-CONFIG_32BIT=y
+# CONFIG_32BIT is not set
 # CONFIG_64BIT is not set
 CONFIG_PAGE_SIZE_4KB=y
 # CONFIG_PAGE_SIZE_8KB is not set
 # CONFIG_PAGE_SIZE_16KB is not set
 # CONFIG_PAGE_SIZE_64KB is not set
 # CONFIG_MIPS_MT is not set
-# CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_LLSC=y
 CONFIG_CPU_HAS_SYNC=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
@@ -155,26 +150,28 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -190,7 +187,6 @@
 #
 # Block layer
 #
-# CONFIG_LBD is not set
 
 #
 # IO Schedulers
@@ -229,7 +225,6 @@
 # CONFIG_YENTA is not set
 # CONFIG_PD6729 is not set
 # CONFIG_I82092 is not set
-CONFIG_PCMCIA_VRC4173=y
 
 #
 # PCI Hotplug Support
@@ -241,7 +236,6 @@
 #
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-CONFIG_TRAD_SIGNALS=y
 
 #
 # Networking
@@ -296,6 +290,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -455,6 +454,7 @@
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -604,11 +604,6 @@
 #
 # Non-8250 serial port support
 #
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_SERIAL_VR41XX=y
-CONFIG_SERIAL_VR41XX_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -624,7 +619,6 @@
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
 # CONFIG_GEN_RTC is not set
-# CONFIG_RTC_VR41XX is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -640,7 +634,6 @@
 # CONFIG_SYNCLINK_CS is not set
 # CONFIG_CARDMAN_4000 is not set
 # CONFIG_CARDMAN_4040 is not set
-CONFIG_GPIO_VR41XX=y
 # CONFIG_RAW_DRIVER is not set
 
 #
@@ -655,6 +648,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -740,6 +739,7 @@
 # may also be needed; see USB_STORAGE Help for more information
 #
 # CONFIG_USB_STORAGE is not set
+# CONFIG_USB_LIBUSUAL is not set
 
 #
 # USB Input Devices
@@ -762,6 +762,7 @@
 # CONFIG_USB_YEALINK is not set
 # CONFIG_USB_XPAD is not set
 # CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
 # CONFIG_USB_KEYSPAN_REMOTE is not set
 # CONFIG_USB_APPLETOUCH is not set
 
@@ -846,11 +847,11 @@
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -883,6 +884,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -941,6 +943,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/configs/ocelot_3_defconfig b/arch/mips/configs/ocelot_3_defconfig
index 7ad8718..925d8ad 100644
--- a/arch/mips/configs/ocelot_3_defconfig
+++ b/arch/mips/configs/ocelot_3_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:41 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:18 2006
 #
 CONFIG_MIPS=y
 
@@ -159,27 +159,29 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -291,6 +293,21 @@
 CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NETFILTER_NETLINK_LOG=m
 # CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -324,6 +341,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -332,6 +354,7 @@
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+CONFIG_NET_CLS_ROUTE=y
 
 #
 # Network testing
@@ -344,7 +367,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -426,7 +448,7 @@
 # SCSI Transport Attributes
 #
 # CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
+CONFIG_SCSI_FC_ATTRS=m
 CONFIG_SCSI_ISCSI_ATTRS=m
 CONFIG_SCSI_SAS_ATTRS=m
 
@@ -455,13 +477,7 @@
 # CONFIG_SCSI_IPR is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=m
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA24XX is not set
+# CONFIG_SCSI_QLA_FC is not set
 # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
@@ -528,6 +544,7 @@
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -567,6 +584,7 @@
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
@@ -592,8 +610,6 @@
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # Wan interfaces
@@ -675,6 +691,7 @@
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -682,7 +699,6 @@
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -719,6 +735,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -777,7 +799,6 @@
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_SMIVGX is not set
-# CONFIG_FB_CYBLA is not set
 # CONFIG_FB_TRIDENT is not set
 # CONFIG_FB_VIRTUAL is not set
 
@@ -861,6 +882,7 @@
 # CONFIG_XFS_SECURITY is not set
 # CONFIG_XFS_POSIX_ACL is not set
 # CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -893,6 +915,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -999,6 +1022,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
@@ -1052,3 +1076,7 @@
 CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
diff --git a/arch/mips/configs/ocelot_c_defconfig b/arch/mips/configs/ocelot_c_defconfig
index e8d6bb3..ee1cf9b 100644
--- a/arch/mips/configs/ocelot_c_defconfig
+++ b/arch/mips/configs/ocelot_c_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:43 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:19 2006
 #
 CONFIG_MIPS=y
 
@@ -154,26 +154,28 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -220,7 +222,6 @@
 #
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_BUILD_ELF64 is not set
 CONFIG_MIPS32_COMPAT=y
 CONFIG_COMPAT=y
 CONFIG_MIPS32_O32=y
@@ -281,6 +282,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -301,7 +307,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=y
 CONFIG_IEEE80211_CRYPT_CCMP=y
-CONFIG_IEEE80211_CRYPT_TKIP=y
 
 #
 # Device Drivers
@@ -420,6 +425,7 @@
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -440,6 +446,7 @@
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -461,8 +468,6 @@
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=y
 
 #
 # Wan interfaces
@@ -538,6 +543,7 @@
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -545,7 +551,6 @@
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -583,6 +588,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -664,11 +675,11 @@
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -701,6 +712,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=y
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -763,6 +775,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/configs/ocelot_defconfig b/arch/mips/configs/ocelot_defconfig
index f3787b6..d80ff27 100644
--- a/arch/mips/configs/ocelot_defconfig
+++ b/arch/mips/configs/ocelot_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:44 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:20 2006
 #
 CONFIG_MIPS=y
 
@@ -159,26 +159,28 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -280,6 +282,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -300,7 +307,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=y
 CONFIG_IEEE80211_CRYPT_CCMP=y
-CONFIG_IEEE80211_CRYPT_TKIP=y
 
 #
 # Device Drivers
@@ -403,6 +409,7 @@
 #
 CONFIG_NET_ETHERNET=y
 # CONFIG_MII is not set
+# CONFIG_DM9000 is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -492,6 +499,7 @@
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -534,6 +542,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -613,11 +627,11 @@
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -650,6 +664,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=y
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -712,6 +727,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/configs/ocelot_g_defconfig b/arch/mips/configs/ocelot_g_defconfig
index b6126ad..c0f508d 100644
--- a/arch/mips/configs/ocelot_g_defconfig
+++ b/arch/mips/configs/ocelot_g_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:46 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:21 2006
 #
 CONFIG_MIPS=y
 
@@ -157,26 +157,28 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -223,7 +225,6 @@
 #
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_BUILD_ELF64 is not set
 CONFIG_MIPS32_COMPAT=y
 CONFIG_COMPAT=y
 CONFIG_MIPS32_O32=y
@@ -284,6 +285,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -304,7 +310,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=y
 CONFIG_IEEE80211_CRYPT_CCMP=y
-CONFIG_IEEE80211_CRYPT_TKIP=y
 
 #
 # Device Drivers
@@ -424,6 +429,7 @@
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -444,6 +450,7 @@
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -464,8 +471,6 @@
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=y
 
 #
 # Wan interfaces
@@ -541,6 +546,7 @@
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -548,7 +554,6 @@
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -586,6 +591,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -667,11 +678,11 @@
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -704,6 +715,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=y
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -766,6 +778,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/configs/pb1100_defconfig b/arch/mips/configs/pb1100_defconfig
index 883626a..194b3c7 100644
--- a/arch/mips/configs/pb1100_defconfig
+++ b/arch/mips/configs/pb1100_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:48 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:22 2006
 #
 CONFIG_MIPS=y
 
@@ -153,26 +153,29 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
 
 #
 # Loadable module support
@@ -287,6 +290,21 @@
 CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NETFILTER_NETLINK_LOG=m
 # CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -314,6 +332,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -322,6 +345,7 @@
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+CONFIG_NET_CLS_ROUTE=y
 
 #
 # Network testing
@@ -334,7 +358,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -397,6 +420,7 @@
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
@@ -514,6 +538,7 @@
 # CONFIG_MII is not set
 # CONFIG_MIPS_AU1X00_ENET is not set
 # CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -619,13 +644,13 @@
 CONFIG_SERIAL_8250_CONSOLE=y
 # CONFIG_SERIAL_8250_CS is not set
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 CONFIG_SERIAL_8250_AU1X00=y
 
 #
 # Non-8250 serial port support
 #
-# CONFIG_SERIAL_AU1X00 is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
@@ -670,6 +695,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -767,6 +798,7 @@
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -799,6 +831,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -903,6 +936,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
@@ -957,3 +991,7 @@
 CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=m
 CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
diff --git a/arch/mips/configs/pb1500_defconfig b/arch/mips/configs/pb1500_defconfig
index f8fbc77..8985725 100644
--- a/arch/mips/configs/pb1500_defconfig
+++ b/arch/mips/configs/pb1500_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:50 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:24 2006
 #
 CONFIG_MIPS=y
 
@@ -152,26 +152,29 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
 
 #
 # Loadable module support
@@ -293,6 +296,21 @@
 CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NETFILTER_NETLINK_LOG=m
 # CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -320,6 +338,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -328,6 +351,7 @@
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+CONFIG_NET_CLS_ROUTE=y
 
 #
 # Network testing
@@ -340,7 +364,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -403,6 +426,7 @@
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
@@ -589,6 +613,7 @@
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -609,6 +634,7 @@
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -629,8 +655,6 @@
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # PCMCIA network device support
@@ -728,16 +752,15 @@
 CONFIG_SERIAL_8250_CONSOLE=y
 # CONFIG_SERIAL_8250_CS is not set
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 CONFIG_SERIAL_8250_AU1X00=y
 
 #
 # Non-8250 serial port support
 #
-# CONFIG_SERIAL_AU1X00 is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -782,6 +805,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -874,6 +903,7 @@
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -906,6 +936,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1010,6 +1041,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
@@ -1064,3 +1096,7 @@
 CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=m
 CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
diff --git a/arch/mips/configs/pb1550_defconfig b/arch/mips/configs/pb1550_defconfig
index 3d694cd..adbf997 100644
--- a/arch/mips/configs/pb1550_defconfig
+++ b/arch/mips/configs/pb1550_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:52 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:25 2006
 #
 CONFIG_MIPS=y
 
@@ -152,26 +152,29 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
 
 #
 # Loadable module support
@@ -293,6 +296,21 @@
 CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NETFILTER_NETLINK_LOG=m
 # CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -320,6 +338,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -328,6 +351,7 @@
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+CONFIG_NET_CLS_ROUTE=y
 
 #
 # Network testing
@@ -340,7 +364,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -403,6 +426,7 @@
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
@@ -589,6 +613,7 @@
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -609,6 +634,7 @@
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -629,8 +655,6 @@
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # PCMCIA network device support
@@ -720,16 +744,15 @@
 CONFIG_SERIAL_8250_CONSOLE=y
 # CONFIG_SERIAL_8250_CS is not set
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 CONFIG_SERIAL_8250_AU1X00=y
 
 #
 # Non-8250 serial port support
 #
-# CONFIG_SERIAL_AU1X00 is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -774,6 +797,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -866,6 +895,7 @@
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -898,6 +928,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1002,6 +1033,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
@@ -1056,3 +1088,7 @@
 CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=m
 CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
diff --git a/arch/mips/configs/pnx8550-jbs_defconfig b/arch/mips/configs/pnx8550-jbs_defconfig
index fba624a..b5db700 100644
--- a/arch/mips/configs/pnx8550-jbs_defconfig
+++ b/arch/mips/configs/pnx8550-jbs_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:54 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:26 2006
 #
 CONFIG_MIPS=y
 
@@ -151,28 +151,30 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -281,6 +283,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -308,7 +315,7 @@
 #
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
+CONFIG_FW_LOADER=y
 # CONFIG_DEBUG_DRIVER is not set
 
 #
@@ -435,7 +442,7 @@
 # SCSI Transport Attributes
 #
 # CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
+CONFIG_SCSI_FC_ATTRS=y
 CONFIG_SCSI_ISCSI_ATTRS=m
 # CONFIG_SCSI_SAS_ATTRS is not set
 
@@ -464,13 +471,7 @@
 # CONFIG_SCSI_IPR is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA24XX is not set
+# CONFIG_SCSI_QLA_FC is not set
 # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
@@ -528,6 +529,7 @@
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -571,6 +573,7 @@
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
@@ -668,7 +671,6 @@
 # Non-8250 serial port support
 #
 # CONFIG_SERIAL_IP3106 is not set
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -706,6 +708,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -801,6 +809,8 @@
 CONFIG_USB_STORAGE_SDDR09=y
 CONFIG_USB_STORAGE_SDDR55=y
 CONFIG_USB_STORAGE_JUMPSHOT=y
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_LIBUSUAL is not set
 
 #
 # USB Input Devices
@@ -823,6 +833,7 @@
 # CONFIG_USB_YEALINK is not set
 # CONFIG_USB_XPAD is not set
 # CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
 # CONFIG_USB_KEYSPAN_REMOTE is not set
 # CONFIG_USB_APPLETOUCH is not set
 
@@ -906,11 +917,11 @@
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -946,6 +957,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 # CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1049,18 +1061,20 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
-CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_SCHEDSTATS is not set
 CONFIG_DEBUG_SLAB=y
+CONFIG_DEBUG_MUTEXES=y
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_INFO is not set
 # CONFIG_DEBUG_FS is not set
 # CONFIG_DEBUG_VM is not set
+CONFIG_FORCED_INLINING=y
 # CONFIG_RCU_TORTURE_TEST is not set
 CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE="console=ttyS1,38400n8 kgdb=ttyS0 root=/dev/nfs ip=bootp"
diff --git a/arch/mips/configs/pnx8550-v2pci_defconfig b/arch/mips/configs/pnx8550-v2pci_defconfig
index 4c650e7..4187287 100644
--- a/arch/mips/configs/pnx8550-v2pci_defconfig
+++ b/arch/mips/configs/pnx8550-v2pci_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:58 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:28 2006
 #
 CONFIG_MIPS=y
 
@@ -152,27 +152,29 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -279,6 +281,21 @@
 #
 # CONFIG_NETFILTER_NETLINK is not set
 # CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -312,6 +329,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -320,6 +342,7 @@
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+CONFIG_NET_CLS_ROUTE=y
 
 #
 # Network testing
@@ -339,7 +362,7 @@
 #
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
+CONFIG_FW_LOADER=y
 
 #
 # Connector - unified userspace <-> kernelspace linker
@@ -466,7 +489,7 @@
 # SCSI Transport Attributes
 #
 CONFIG_SCSI_SPI_ATTRS=m
-# CONFIG_SCSI_FC_ATTRS is not set
+CONFIG_SCSI_FC_ATTRS=y
 CONFIG_SCSI_ISCSI_ATTRS=m
 # CONFIG_SCSI_SAS_ATTRS is not set
 
@@ -500,13 +523,7 @@
 # CONFIG_SCSI_IPR is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA24XX is not set
+# CONFIG_SCSI_QLA_FC is not set
 # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
@@ -564,6 +581,7 @@
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -607,6 +625,7 @@
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
@@ -721,6 +740,7 @@
 # CONFIG_MOXA_SMARTIO is not set
 # CONFIG_ISI is not set
 # CONFIG_SYNCLINKMP is not set
+# CONFIG_SYNCLINK_GT is not set
 # CONFIG_N_HDLC is not set
 # CONFIG_RISCOM8 is not set
 # CONFIG_SPECIALIX is not set
@@ -737,7 +757,6 @@
 # Non-8250 serial port support
 #
 # CONFIG_SERIAL_IP3106 is not set
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -825,6 +844,12 @@
 # CONFIG_I2C_DEBUG_CHIP is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -863,6 +888,7 @@
 # CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
 # CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT8231 is not set
 # CONFIG_SENSORS_W83781D is not set
 # CONFIG_SENSORS_W83792D is not set
 # CONFIG_SENSORS_W83L785TS is not set
@@ -918,7 +944,6 @@
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_SMIVGX is not set
-# CONFIG_FB_CYBLA is not set
 # CONFIG_FB_TRIDENT is not set
 # CONFIG_FB_VIRTUAL is not set
 
@@ -988,13 +1013,16 @@
 # CONFIG_USB_STORAGE_SDDR09 is not set
 # CONFIG_USB_STORAGE_SDDR55 is not set
 # CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
 # CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_LIBUSUAL is not set
 
 #
 # USB Input Devices
 #
 CONFIG_USB_HID=y
 CONFIG_USB_HIDINPUT=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
 # CONFIG_HID_FF is not set
 CONFIG_USB_HIDDEV=y
 # CONFIG_USB_AIPTEK is not set
@@ -1008,6 +1036,7 @@
 # CONFIG_USB_YEALINK is not set
 # CONFIG_USB_XPAD is not set
 # CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
 # CONFIG_USB_KEYSPAN_REMOTE is not set
 # CONFIG_USB_APPLETOUCH is not set
 
@@ -1107,6 +1136,7 @@
 # CONFIG_XFS_SECURITY is not set
 # CONFIG_XFS_POSIX_ACL is not set
 # CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -1142,6 +1172,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 # CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1246,6 +1277,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
@@ -1299,3 +1331,7 @@
 CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
diff --git a/arch/mips/configs/qemu_defconfig b/arch/mips/configs/qemu_defconfig
index c02beca..31f5afa 100644
--- a/arch/mips/configs/qemu_defconfig
+++ b/arch/mips/configs/qemu_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.16-rc2
-# Fri Feb  3 17:14:27 2006
+# Sun Feb 12 19:18:55 2006
 #
 CONFIG_MIPS=y
 
@@ -133,7 +133,6 @@
 # Code maturity level options
 #
 # CONFIG_EXPERIMENTAL is not set
-CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 
@@ -145,7 +144,7 @@
 # CONFIG_SWAP is not set
 # CONFIG_SYSVIPC is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
@@ -222,6 +221,7 @@
 #
 # Networking options
 #
+# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
 CONFIG_UNIX=y
@@ -476,8 +476,9 @@
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_UNIX98_PTYS is not set
-# CONFIG_LEGACY_PTYS is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
 
 #
 # IPMI
@@ -627,7 +628,7 @@
 #
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
-# CONFIG_SYSFS is not set
+CONFIG_SYSFS=y
 # CONFIG_TMPFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
@@ -680,12 +681,13 @@
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
-CONFIG_CMDLINE="console=ttyS0 debug ip=172.20.0.2:172.20.0.1::255.255.0.0"
+CONFIG_CMDLINE=""
 
 #
 # Security options
 #
 # CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
 
 #
 # Cryptographic options
diff --git a/arch/mips/configs/rbhma4500_defconfig b/arch/mips/configs/rbhma4500_defconfig
index 9aaa430..b126f76 100644
--- a/arch/mips/configs/rbhma4500_defconfig
+++ b/arch/mips/configs/rbhma4500_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:07:03 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:30 2006
 #
 CONFIG_MIPS=y
 
@@ -160,27 +160,30 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-# CONFIG_KOBJECT_UEVENT is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
 
 #
 # Loadable module support
@@ -291,6 +294,21 @@
 CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NETFILTER_NETLINK_LOG=m
 # CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -324,6 +342,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -332,6 +355,7 @@
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+CONFIG_NET_CLS_ROUTE=y
 
 #
 # Network testing
@@ -407,6 +431,7 @@
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
@@ -598,6 +623,7 @@
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_DM9000 is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 
 #
@@ -654,6 +680,7 @@
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
@@ -687,8 +714,8 @@
 # Wireless 802.11b ISA/PCI cards support
 #
 # CONFIG_IPW2100 is not set
-# CONFIG_IPW_DEBUG is not set
 CONFIG_IPW2200=m
+# CONFIG_IPW2200_DEBUG is not set
 # CONFIG_HERMES is not set
 # CONFIG_ATMEL is not set
 
@@ -795,7 +822,6 @@
 # Non-8250 serial port support
 #
 CONFIG_HAS_TXX9_SERIAL=y
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -833,6 +859,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -887,7 +919,6 @@
 CONFIG_FB_ATY=y
 CONFIG_FB_ATY_CT=y
 # CONFIG_FB_ATY_GENERIC_LCD is not set
-# CONFIG_FB_ATY_XL_INIT is not set
 # CONFIG_FB_ATY_GX is not set
 # CONFIG_FB_SAVAGE is not set
 # CONFIG_FB_SIS is not set
@@ -896,7 +927,6 @@
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_SMIVGX is not set
-# CONFIG_FB_CYBLA is not set
 # CONFIG_FB_TRIDENT is not set
 # CONFIG_FB_VIRTUAL is not set
 
@@ -958,12 +988,14 @@
 # may also be needed; see USB_STORAGE Help for more information
 #
 # CONFIG_USB_STORAGE is not set
+# CONFIG_USB_LIBUSUAL is not set
 
 #
 # USB Input Devices
 #
 CONFIG_USB_HID=y
 CONFIG_USB_HIDINPUT=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
 # CONFIG_HID_FF is not set
 CONFIG_USB_HIDDEV=y
 # CONFIG_USB_AIPTEK is not set
@@ -977,6 +1009,7 @@
 CONFIG_USB_YEALINK=m
 # CONFIG_USB_XPAD is not set
 # CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
 # CONFIG_USB_KEYSPAN_REMOTE is not set
 # CONFIG_USB_APPLETOUCH is not set
 
@@ -1078,6 +1111,7 @@
 # CONFIG_XFS_SECURITY is not set
 # CONFIG_XFS_POSIX_ACL is not set
 # CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -1115,6 +1149,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1228,6 +1263,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
@@ -1281,3 +1317,7 @@
 CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
diff --git a/arch/mips/configs/rm200_defconfig b/arch/mips/configs/rm200_defconfig
index abf6109..463ed3d 100644
--- a/arch/mips/configs/rm200_defconfig
+++ b/arch/mips/configs/rm200_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:07:06 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:31 2006
 #
 CONFIG_MIPS=y
 
@@ -161,27 +161,29 @@
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -297,6 +299,28 @@
 CONFIG_NETFILTER_NETLINK=m
 CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -315,39 +339,23 @@
 CONFIG_IP_NF_PPTP=m
 CONFIG_IP_NF_QUEUE=m
 CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
 CONFIG_IP_NF_MATCH_IPRANGE=m
-CONFIG_IP_NF_MATCH_MAC=m
-CONFIG_IP_NF_MATCH_PKTTYPE=m
-CONFIG_IP_NF_MATCH_MARK=m
 CONFIG_IP_NF_MATCH_MULTIPORT=m
 CONFIG_IP_NF_MATCH_TOS=m
 CONFIG_IP_NF_MATCH_RECENT=m
 CONFIG_IP_NF_MATCH_ECN=m
 CONFIG_IP_NF_MATCH_DSCP=m
 CONFIG_IP_NF_MATCH_AH_ESP=m
-CONFIG_IP_NF_MATCH_LENGTH=m
 CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_TCPMSS=m
-CONFIG_IP_NF_MATCH_HELPER=m
-CONFIG_IP_NF_MATCH_STATE=m
-CONFIG_IP_NF_MATCH_CONNTRACK=m
 CONFIG_IP_NF_MATCH_OWNER=m
-CONFIG_IP_NF_MATCH_PHYSDEV=m
 CONFIG_IP_NF_MATCH_ADDRTYPE=m
-CONFIG_IP_NF_MATCH_REALM=m
-CONFIG_IP_NF_MATCH_SCTP=m
-CONFIG_IP_NF_MATCH_DCCP=m
-CONFIG_IP_NF_MATCH_COMMENT=m
-CONFIG_IP_NF_MATCH_CONNMARK=m
 CONFIG_IP_NF_MATCH_HASHLIMIT=m
-CONFIG_IP_NF_MATCH_STRING=m
+CONFIG_IP_NF_MATCH_POLICY=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
 CONFIG_IP_NF_TARGET_LOG=m
 CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_IP_NF_TARGET_TCPMSS=m
-CONFIG_IP_NF_TARGET_NFQUEUE=m
 CONFIG_IP_NF_NAT=m
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
@@ -364,13 +372,9 @@
 CONFIG_IP_NF_TARGET_TOS=m
 CONFIG_IP_NF_TARGET_ECN=m
 CONFIG_IP_NF_TARGET_DSCP=m
-CONFIG_IP_NF_TARGET_MARK=m
-CONFIG_IP_NF_TARGET_CLASSIFY=m
 CONFIG_IP_NF_TARGET_TTL=m
-CONFIG_IP_NF_TARGET_CONNMARK=m
 CONFIG_IP_NF_TARGET_CLUSTERIP=m
 CONFIG_IP_NF_RAW=m
-CONFIG_IP_NF_TARGET_NOTRACK=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
@@ -380,26 +384,20 @@
 #
 CONFIG_IP6_NF_QUEUE=m
 CONFIG_IP6_NF_IPTABLES=m
-CONFIG_IP6_NF_MATCH_LIMIT=m
-CONFIG_IP6_NF_MATCH_MAC=m
 CONFIG_IP6_NF_MATCH_RT=m
 CONFIG_IP6_NF_MATCH_OPTS=m
 CONFIG_IP6_NF_MATCH_FRAG=m
 CONFIG_IP6_NF_MATCH_HL=m
 CONFIG_IP6_NF_MATCH_MULTIPORT=m
 CONFIG_IP6_NF_MATCH_OWNER=m
-CONFIG_IP6_NF_MATCH_MARK=m
 CONFIG_IP6_NF_MATCH_IPV6HEADER=m
 CONFIG_IP6_NF_MATCH_AHESP=m
-CONFIG_IP6_NF_MATCH_LENGTH=m
 CONFIG_IP6_NF_MATCH_EUI64=m
-CONFIG_IP6_NF_MATCH_PHYSDEV=m
+CONFIG_IP6_NF_MATCH_POLICY=m
 CONFIG_IP6_NF_FILTER=m
 CONFIG_IP6_NF_TARGET_LOG=m
 CONFIG_IP6_NF_TARGET_REJECT=m
-CONFIG_IP6_NF_TARGET_NFQUEUE=m
 CONFIG_IP6_NF_MANGLE=m
-CONFIG_IP6_NF_TARGET_MARK=m
 CONFIG_IP6_NF_TARGET_HL=m
 CONFIG_IP6_NF_RAW=m
 
@@ -451,6 +449,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -530,7 +533,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -541,7 +543,7 @@
 #
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
-CONFIG_FW_LOADER=m
+CONFIG_FW_LOADER=y
 
 #
 # Connector - unified userspace <-> kernelspace linker
@@ -657,7 +659,7 @@
 # SCSI Transport Attributes
 #
 CONFIG_SCSI_SPI_ATTRS=y
-# CONFIG_SCSI_FC_ATTRS is not set
+CONFIG_SCSI_FC_ATTRS=y
 CONFIG_SCSI_ISCSI_ATTRS=m
 CONFIG_SCSI_SAS_ATTRS=m
 
@@ -678,6 +680,7 @@
 CONFIG_MEGARAID_NEWGEN=y
 CONFIG_MEGARAID_MM=m
 CONFIG_MEGARAID_MAILBOX=m
+# CONFIG_MEGARAID_LEGACY is not set
 # CONFIG_MEGARAID_SAS is not set
 # CONFIG_SCSI_SATA is not set
 # CONFIG_SCSI_DMX3191D is not set
@@ -704,13 +707,7 @@
 # CONFIG_SCSI_QLOGIC_FAS is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA24XX is not set
+# CONFIG_SCSI_QLA_FC is not set
 # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_SYM53C416 is not set
 # CONFIG_SCSI_DC395x is not set
@@ -801,6 +798,7 @@
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_DM9000 is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 
 #
@@ -858,6 +856,7 @@
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 CONFIG_VIA_VELOCITY=m
 # CONFIG_TIGON3 is not set
@@ -879,8 +878,6 @@
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # Wan interfaces
@@ -969,6 +966,7 @@
 #
 CONFIG_SERIAL_8250=m
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 CONFIG_SERIAL_8250_EXTENDED=y
 # CONFIG_SERIAL_8250_MANY_PORTS is not set
 CONFIG_SERIAL_8250_SHARE_IRQ=y
@@ -979,7 +977,6 @@
 # Non-8250 serial port support
 #
 CONFIG_SERIAL_CORE=m
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -1021,6 +1018,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 CONFIG_W1=m
@@ -1123,12 +1126,15 @@
 CONFIG_USB_STORAGE_SDDR09=y
 CONFIG_USB_STORAGE_SDDR55=y
 CONFIG_USB_STORAGE_JUMPSHOT=y
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_LIBUSUAL is not set
 
 #
 # USB Input Devices
 #
 CONFIG_USB_HID=m
 CONFIG_USB_HIDINPUT=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
 CONFIG_HID_FF=y
 CONFIG_HID_PID=y
 CONFIG_LOGITECH_FF=y
@@ -1151,6 +1157,7 @@
 CONFIG_USB_YEALINK=m
 CONFIG_USB_XPAD=m
 # CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
 # CONFIG_USB_KEYSPAN_REMOTE is not set
 # CONFIG_USB_APPLETOUCH is not set
 
@@ -1309,6 +1316,7 @@
 CONFIG_XFS_SECURITY=y
 # CONFIG_XFS_POSIX_ACL is not set
 # CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
 CONFIG_MINIX_FS=m
 CONFIG_ROMFS_FS=m
 CONFIG_INOTIFY=y
@@ -1351,6 +1359,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1432,6 +1441,7 @@
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
 # CONFIG_EFI_PARTITION is not set
 
 #
@@ -1487,6 +1497,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/configs/sb1250-swarm_defconfig b/arch/mips/configs/sb1250-swarm_defconfig
index 52048c9..da68c3f 100644
--- a/arch/mips/configs/sb1250-swarm_defconfig
+++ b/arch/mips/configs/sb1250-swarm_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:07:09 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:32 2006
 #
 CONFIG_MIPS=y
 
@@ -173,27 +173,29 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_CPUSETS=y
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -247,7 +249,6 @@
 #
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_BUILD_ELF64 is not set
 CONFIG_MIPS32_COMPAT=y
 CONFIG_COMPAT=y
 CONFIG_MIPS32_O32=y
@@ -309,6 +310,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -329,7 +335,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -472,6 +477,7 @@
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -493,6 +499,7 @@
 CONFIG_NET_SB1250_MAC=y
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -513,8 +520,6 @@
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # Wan interfaces
@@ -560,12 +565,15 @@
 #
 # CONFIG_VT is not set
 CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_COMPUTONE is not set
 # CONFIG_ROCKETPORT is not set
 # CONFIG_CYCLADES is not set
 # CONFIG_DIGIEPCA is not set
+# CONFIG_MOXA_INTELLIO is not set
 # CONFIG_MOXA_SMARTIO is not set
 # CONFIG_ISI is not set
 # CONFIG_SYNCLINKMP is not set
+# CONFIG_SYNCLINK_GT is not set
 # CONFIG_N_HDLC is not set
 # CONFIG_SPECIALIX is not set
 # CONFIG_SX is not set
@@ -581,7 +589,6 @@
 #
 # Non-8250 serial port support
 #
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -619,6 +626,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -696,12 +709,12 @@
 CONFIG_EXT2_FS_SECURITY=y
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -734,6 +747,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -795,6 +809,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=15
 CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/configs/sead_defconfig b/arch/mips/configs/sead_defconfig
index 41dd708..9a936d7 100644
--- a/arch/mips/configs/sead_defconfig
+++ b/arch/mips/configs/sead_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:07:10 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:33 2006
 #
 CONFIG_MIPS=y
 
@@ -153,25 +153,28 @@
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
-# CONFIG_HOTPLUG is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -330,6 +333,7 @@
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -372,6 +376,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -444,7 +454,6 @@
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
@@ -481,6 +490,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=y
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -513,6 +523,7 @@
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
 # CONFIG_EFI_PARTITION is not set
 
 #
@@ -529,6 +540,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/configs/tb0226_defconfig b/arch/mips/configs/tb0226_defconfig
index 8396946..c2dee0d 100644
--- a/arch/mips/configs/tb0226_defconfig
+++ b/arch/mips/configs/tb0226_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:07:12 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:34 2006
 #
 CONFIG_MIPS=y
 
@@ -63,11 +63,12 @@
 # CONFIG_TOSHIBA_JMR3927 is not set
 # CONFIG_TOSHIBA_RBTX4927 is not set
 # CONFIG_TOSHIBA_RBTX4938 is not set
-# CONFIG_NEC_CMBVR4133 is not set
 # CONFIG_CASIO_E55 is not set
 # CONFIG_IBM_WORKPAD is not set
+# CONFIG_NEC_CMBVR4133 is not set
 CONFIG_TANBAC_TB022X=y
 CONFIG_TANBAC_TB0226=y
+CONFIG_TANBAC_TB0287=y
 # CONFIG_VICTOR_MPC30X is not set
 # CONFIG_ZAO_CAPCELLA is not set
 CONFIG_PCI_VR41XX=y
@@ -91,7 +92,7 @@
 # CONFIG_CPU_MIPS64_R2 is not set
 # CONFIG_CPU_R3000 is not set
 # CONFIG_CPU_TX39XX is not set
-CONFIG_CPU_VR41XX=y
+# CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
 # CONFIG_CPU_TX49XX is not set
@@ -104,23 +105,18 @@
 # CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_RM9000 is not set
 # CONFIG_CPU_SB1 is not set
-CONFIG_SYS_HAS_CPU_VR41XX=y
-CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
-CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
 
 #
 # Kernel type
 #
-CONFIG_32BIT=y
+# CONFIG_32BIT is not set
 # CONFIG_64BIT is not set
 CONFIG_PAGE_SIZE_4KB=y
 # CONFIG_PAGE_SIZE_8KB is not set
 # CONFIG_PAGE_SIZE_16KB is not set
 # CONFIG_PAGE_SIZE_64KB is not set
 # CONFIG_MIPS_MT is not set
-# CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_LLSC=y
 CONFIG_CPU_HAS_SYNC=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
@@ -156,26 +152,28 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -191,7 +189,6 @@
 #
 # Block layer
 #
-# CONFIG_LBD is not set
 
 #
 # IO Schedulers
@@ -229,7 +226,6 @@
 #
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-CONFIG_TRAD_SIGNALS=y
 
 #
 # Networking
@@ -293,6 +289,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -313,7 +314,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -324,7 +324,7 @@
 #
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
+CONFIG_FW_LOADER=y
 
 #
 # Connector - unified userspace <-> kernelspace linker
@@ -397,7 +397,7 @@
 # SCSI Transport Attributes
 #
 # CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
+CONFIG_SCSI_FC_ATTRS=y
 CONFIG_SCSI_ISCSI_ATTRS=m
 # CONFIG_SCSI_SAS_ATTRS is not set
 
@@ -426,13 +426,7 @@
 # CONFIG_SCSI_IPR is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA24XX is not set
+# CONFIG_SCSI_QLA_FC is not set
 # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
@@ -499,6 +493,7 @@
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -538,6 +533,7 @@
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
@@ -559,7 +555,6 @@
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW2200 is not set
 
 #
 # Wan interfaces
@@ -630,11 +625,6 @@
 #
 # Non-8250 serial port support
 #
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_SERIAL_VR41XX=y
-CONFIG_SERIAL_VR41XX_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -650,7 +640,6 @@
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
 # CONFIG_GEN_RTC is not set
-# CONFIG_RTC_VR41XX is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -675,6 +664,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -770,6 +765,8 @@
 # CONFIG_USB_STORAGE_SDDR09 is not set
 # CONFIG_USB_STORAGE_SDDR55 is not set
 # CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_LIBUSUAL is not set
 
 #
 # USB Input Devices
@@ -792,6 +789,7 @@
 # CONFIG_USB_YEALINK is not set
 # CONFIG_USB_XPAD is not set
 # CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
 # CONFIG_USB_KEYSPAN_REMOTE is not set
 # CONFIG_USB_APPLETOUCH is not set
 
@@ -877,11 +875,11 @@
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_ROMFS_FS=m
 CONFIG_INOTIFY=y
@@ -914,6 +912,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1021,6 +1020,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/configs/tb0229_defconfig b/arch/mips/configs/tb0229_defconfig
index ce7b9ed..be99261 100644
--- a/arch/mips/configs/tb0229_defconfig
+++ b/arch/mips/configs/tb0229_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:07:15 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:35 2006
 #
 CONFIG_MIPS=y
 
@@ -63,11 +63,12 @@
 # CONFIG_TOSHIBA_JMR3927 is not set
 # CONFIG_TOSHIBA_RBTX4927 is not set
 # CONFIG_TOSHIBA_RBTX4938 is not set
-# CONFIG_NEC_CMBVR4133 is not set
 # CONFIG_CASIO_E55 is not set
 # CONFIG_IBM_WORKPAD is not set
+# CONFIG_NEC_CMBVR4133 is not set
 CONFIG_TANBAC_TB022X=y
 # CONFIG_TANBAC_TB0226 is not set
+CONFIG_TANBAC_TB0287=y
 # CONFIG_VICTOR_MPC30X is not set
 # CONFIG_ZAO_CAPCELLA is not set
 CONFIG_PCI_VR41XX=y
@@ -91,7 +92,7 @@
 # CONFIG_CPU_MIPS64_R2 is not set
 # CONFIG_CPU_R3000 is not set
 # CONFIG_CPU_TX39XX is not set
-CONFIG_CPU_VR41XX=y
+# CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
 # CONFIG_CPU_TX49XX is not set
@@ -104,23 +105,18 @@
 # CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_RM9000 is not set
 # CONFIG_CPU_SB1 is not set
-CONFIG_SYS_HAS_CPU_VR41XX=y
-CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
-CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
 
 #
 # Kernel type
 #
-CONFIG_32BIT=y
+# CONFIG_32BIT is not set
 # CONFIG_64BIT is not set
 CONFIG_PAGE_SIZE_4KB=y
 # CONFIG_PAGE_SIZE_8KB is not set
 # CONFIG_PAGE_SIZE_16KB is not set
 # CONFIG_PAGE_SIZE_64KB is not set
 # CONFIG_MIPS_MT is not set
-# CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_LLSC=y
 CONFIG_CPU_HAS_SYNC=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
@@ -156,26 +152,28 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -191,7 +189,6 @@
 #
 # Block layer
 #
-# CONFIG_LBD is not set
 
 #
 # IO Schedulers
@@ -229,7 +226,6 @@
 #
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-CONFIG_TRAD_SIGNALS=y
 
 #
 # Networking
@@ -294,6 +290,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -314,7 +315,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -436,6 +436,7 @@
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -480,6 +481,7 @@
 # CONFIG_R8169_NAPI is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
@@ -501,8 +503,6 @@
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # Wan interfaces
@@ -583,11 +583,6 @@
 #
 # Non-8250 serial port support
 #
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_SERIAL_VR41XX=y
-CONFIG_SERIAL_VR41XX_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -603,7 +598,6 @@
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
 # CONFIG_GEN_RTC is not set
-# CONFIG_RTC_VR41XX is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -613,7 +607,6 @@
 # Ftape, the floppy tape device driver
 #
 # CONFIG_DRM is not set
-CONFIG_GPIO_VR41XX=y
 # CONFIG_RAW_DRIVER is not set
 
 #
@@ -628,6 +621,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -715,6 +714,7 @@
 # may also be needed; see USB_STORAGE Help for more information
 #
 # CONFIG_USB_STORAGE is not set
+# CONFIG_USB_LIBUSUAL is not set
 
 #
 # USB Input Devices
@@ -737,6 +737,7 @@
 # CONFIG_USB_YEALINK is not set
 # CONFIG_USB_XPAD is not set
 # CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
 # CONFIG_USB_KEYSPAN_REMOTE is not set
 # CONFIG_USB_APPLETOUCH is not set
 
@@ -840,6 +841,7 @@
 # CONFIG_XFS_SECURITY is not set
 CONFIG_XFS_POSIX_ACL=y
 # CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_ROMFS_FS=m
 CONFIG_INOTIFY=y
@@ -879,6 +881,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -986,6 +989,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/configs/tb0287_defconfig b/arch/mips/configs/tb0287_defconfig
deleted file mode 100644
index 9534483..0000000
--- a/arch/mips/configs/tb0287_defconfig
+++ /dev/null
@@ -1,1105 +0,0 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.14-rc5-mm1
-# Tue Oct 25 00:20:22 2005
-#
-CONFIG_MIPS=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
-CONFIG_BROKEN_ON_SMP=y
-CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
-CONFIG_LOCALVERSION=""
-CONFIG_LOCALVERSION_AUTO=y
-CONFIG_SWAP=y
-CONFIG_SWAP_PREFETCH=y
-CONFIG_SYSVIPC=y
-# CONFIG_POSIX_MQUEUE is not set
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-# CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
-# CONFIG_IKCONFIG is not set
-CONFIG_INITRAMFS_SOURCE=""
-CONFIG_EMBEDDED=y
-CONFIG_KALLSYMS=y
-# CONFIG_KALLSYMS_EXTRA_PASS is not set
-CONFIG_PRINTK=y
-CONFIG_BUG=y
-CONFIG_BASE_FULL=y
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
-# CONFIG_TINY_SHMEM is not set
-CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-CONFIG_MODVERSIONS=y
-CONFIG_MODULE_SRCVERSION_ALL=y
-CONFIG_KMOD=y
-
-#
-# Machine selection
-#
-# CONFIG_MIPS_MTX1 is not set
-# CONFIG_MIPS_BOSPORUS is not set
-# CONFIG_MIPS_PB1000 is not set
-# CONFIG_MIPS_PB1100 is not set
-# CONFIG_MIPS_PB1500 is not set
-# CONFIG_MIPS_PB1550 is not set
-# CONFIG_MIPS_PB1200 is not set
-# CONFIG_MIPS_DB1000 is not set
-# CONFIG_MIPS_DB1100 is not set
-# CONFIG_MIPS_DB1500 is not set
-# CONFIG_MIPS_DB1550 is not set
-# CONFIG_MIPS_DB1200 is not set
-# CONFIG_MIPS_MIRAGE is not set
-# CONFIG_MIPS_COBALT is not set
-# CONFIG_MACH_DECSTATION is not set
-# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
-# CONFIG_MIPS_IVR is not set
-# CONFIG_MIPS_ITE8172 is not set
-# CONFIG_MACH_JAZZ is not set
-# CONFIG_LASAT is not set
-# CONFIG_MIPS_ATLAS is not set
-# CONFIG_MIPS_MALTA is not set
-# CONFIG_MIPS_SEAD is not set
-# CONFIG_MIPS_SIM is not set
-# CONFIG_MOMENCO_JAGUAR_ATX is not set
-# CONFIG_MOMENCO_OCELOT is not set
-# CONFIG_MOMENCO_OCELOT_3 is not set
-# CONFIG_MOMENCO_OCELOT_C is not set
-# CONFIG_MOMENCO_OCELOT_G is not set
-# CONFIG_MIPS_XXS1500 is not set
-# CONFIG_PNX8550_V2PCI is not set
-# CONFIG_PNX8550_JBS is not set
-# CONFIG_DDB5074 is not set
-# CONFIG_DDB5476 is not set
-# CONFIG_DDB5477 is not set
-CONFIG_MACH_VR41XX=y
-# CONFIG_PMC_YOSEMITE is not set
-# CONFIG_QEMU is not set
-# CONFIG_SGI_IP22 is not set
-# CONFIG_SGI_IP27 is not set
-# CONFIG_SGI_IP32 is not set
-# CONFIG_SIBYTE_SWARM is not set
-# CONFIG_SIBYTE_SENTOSA is not set
-# CONFIG_SIBYTE_RHONE is not set
-# CONFIG_SIBYTE_CARMEL is not set
-# CONFIG_SIBYTE_PTSWARM is not set
-# CONFIG_SIBYTE_LITTLESUR is not set
-# CONFIG_SIBYTE_CRHINE is not set
-# CONFIG_SIBYTE_CRHONE is not set
-# CONFIG_SNI_RM200_PCI is not set
-# CONFIG_TOSHIBA_JMR3927 is not set
-# CONFIG_TOSHIBA_RBTX4927 is not set
-# CONFIG_TOSHIBA_RBTX4938 is not set
-# CONFIG_CASIO_E55 is not set
-# CONFIG_IBM_WORKPAD is not set
-# CONFIG_NEC_CMBVR4133 is not set
-CONFIG_TANBAC_TB022X=y
-# CONFIG_TANBAC_TB0226 is not set
-CONFIG_TANBAC_TB0287=y
-# CONFIG_VICTOR_MPC30X is not set
-# CONFIG_ZAO_CAPCELLA is not set
-CONFIG_PCI_VR41XX=y
-# CONFIG_VRC4173 is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_DMA_NONCOHERENT=y
-CONFIG_DMA_NEED_PCI_MAP_STATE=y
-# CONFIG_CPU_BIG_ENDIAN is not set
-CONFIG_CPU_LITTLE_ENDIAN=y
-CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
-CONFIG_IRQ_CPU=y
-CONFIG_MIPS_L1_CACHE_SHIFT=5
-
-#
-# CPU selection
-#
-# CONFIG_CPU_MIPS32_R1 is not set
-# CONFIG_CPU_MIPS32_R2 is not set
-# CONFIG_CPU_MIPS64_R1 is not set
-# CONFIG_CPU_MIPS64_R2 is not set
-# CONFIG_CPU_R3000 is not set
-# CONFIG_CPU_TX39XX is not set
-CONFIG_CPU_VR41XX=y
-# CONFIG_CPU_R4300 is not set
-# CONFIG_CPU_R4X00 is not set
-# CONFIG_CPU_TX49XX is not set
-# CONFIG_CPU_R5000 is not set
-# CONFIG_CPU_R5432 is not set
-# CONFIG_CPU_R6000 is not set
-# CONFIG_CPU_NEVADA is not set
-# CONFIG_CPU_R8000 is not set
-# CONFIG_CPU_R10000 is not set
-# CONFIG_CPU_RM7000 is not set
-# CONFIG_CPU_RM9000 is not set
-# CONFIG_CPU_SB1 is not set
-CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
-CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
-
-#
-# Kernel type
-#
-CONFIG_32BIT=y
-# CONFIG_64BIT is not set
-CONFIG_PAGE_SIZE_4KB=y
-# CONFIG_PAGE_SIZE_8KB is not set
-# CONFIG_PAGE_SIZE_16KB is not set
-# CONFIG_PAGE_SIZE_64KB is not set
-# CONFIG_MIPS_MT is not set
-# CONFIG_CPU_ADVANCED is not set
-CONFIG_CPU_HAS_SYNC=y
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_ARCH_FLATMEM_ENABLE=y
-CONFIG_SELECT_MEMORY_MODEL=y
-CONFIG_FLATMEM_MANUAL=y
-# CONFIG_DISCONTIGMEM_MANUAL is not set
-# CONFIG_SPARSEMEM_MANUAL is not set
-CONFIG_FLATMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
-# CONFIG_SPARSEMEM_STATIC is not set
-CONFIG_SPLIT_PTLOCK_CPUS=4
-CONFIG_PREEMPT_NONE=y
-# CONFIG_PREEMPT_VOLUNTARY is not set
-# CONFIG_PREEMPT is not set
-
-#
-# Bus options (PCI, PCMCIA, EISA, ISA, TC)
-#
-CONFIG_HW_HAS_PCI=y
-CONFIG_PCI=y
-# CONFIG_PCI_LEGACY_PROC is not set
-CONFIG_MMU=y
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
-# CONFIG_PCCARD is not set
-
-#
-# PCI Hotplug Support
-#
-# CONFIG_HOTPLUG_PCI is not set
-
-#
-# Executable file formats
-#
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-CONFIG_TRAD_SIGNALS=y
-
-#
-# Networking
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_UNIX=y
-CONFIG_XFRM=y
-CONFIG_XFRM_USER=m
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_ADVANCED_ROUTER=y
-CONFIG_ASK_IP_FIB_HASH=y
-# CONFIG_IP_FIB_TRIE is not set
-CONFIG_IP_FIB_HASH=y
-CONFIG_IP_MULTIPLE_TABLES=y
-CONFIG_IP_ROUTE_MULTIPATH=y
-# CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set
-CONFIG_IP_ROUTE_VERBOSE=y
-CONFIG_IP_PNP=y
-# CONFIG_IP_PNP_DHCP is not set
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_IP_PNP_RARP is not set
-CONFIG_NET_IPIP=m
-CONFIG_NET_IPGRE=m
-# CONFIG_NET_IPGRE_BROADCAST is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-CONFIG_INET_TUNNEL=m
-CONFIG_INET_DIAG=y
-CONFIG_INET_TCP_DIAG=y
-CONFIG_TCP_CONG_ADVANCED=y
-
-#
-# TCP congestion control
-#
-CONFIG_TCP_CONG_BIC=y
-CONFIG_TCP_CONG_WESTWOOD=m
-CONFIG_TCP_CONG_HTCP=m
-# CONFIG_TCP_CONG_HSTCP is not set
-# CONFIG_TCP_CONG_HYBLA is not set
-# CONFIG_TCP_CONG_VEGAS is not set
-# CONFIG_TCP_CONG_SCALABLE is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
-# CONFIG_IEEE80211 is not set
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
-# CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_UMEM is not set
-# CONFIG_BLK_DEV_COW_COMMON is not set
-CONFIG_BLK_DEV_LOOP=m
-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-CONFIG_BLK_DEV_NBD=m
-# CONFIG_BLK_DEV_SX8 is not set
-# CONFIG_BLK_DEV_UB is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=4096
-# CONFIG_BLK_DEV_INITRD is not set
-# CONFIG_LBD is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-CONFIG_DEFAULT_AS=y
-# CONFIG_DEFAULT_DEADLINE is not set
-# CONFIG_DEFAULT_CFQ is not set
-# CONFIG_DEFAULT_NOOP is not set
-CONFIG_DEFAULT_IOSCHED="anticipatory"
-# CONFIG_ATA_OVER_ETH is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_IDE_SATA is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-# CONFIG_IDE_TASK_IOCTL is not set
-
-#
-# IDE chipset support/bugfixes
-#
-CONFIG_IDE_GENERIC=y
-CONFIG_BLK_DEV_IDEPCI=y
-# CONFIG_IDEPCI_SHARE_IRQ is not set
-# CONFIG_BLK_DEV_OFFBOARD is not set
-# CONFIG_BLK_DEV_GENERIC is not set
-# CONFIG_BLK_DEV_OPTI621 is not set
-CONFIG_BLK_DEV_IDEDMA_PCI=y
-# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-# CONFIG_IDEDMA_PCI_AUTO is not set
-# CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_BLK_DEV_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD74XX is not set
-# CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_BLK_DEV_TRIFLEX is not set
-# CONFIG_BLK_DEV_CY82C693 is not set
-# CONFIG_BLK_DEV_CS5520 is not set
-# CONFIG_BLK_DEV_CS5530 is not set
-# CONFIG_BLK_DEV_HPT34X is not set
-# CONFIG_BLK_DEV_HPT366 is not set
-# CONFIG_BLK_DEV_SC1200 is not set
-# CONFIG_BLK_DEV_PIIX is not set
-# CONFIG_BLK_DEV_IT821X is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_PDC202XX_OLD is not set
-# CONFIG_BLK_DEV_PDC202XX_NEW is not set
-# CONFIG_BLK_DEV_SVWKS is not set
-CONFIG_BLK_DEV_SIIMAGE=y
-# CONFIG_BLK_DEV_SLC90E66 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
-# CONFIG_IDE_ARM is not set
-CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_IVB is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# SCSI device support
-#
-# CONFIG_RAID_ATTRS is not set
-CONFIG_SCSI=y
-CONFIG_SCSI_PROC_FS=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG is not set
-# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI Transport Attributes
-#
-# CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
-# CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_ATTRS is not set
-
-#
-# SCSI Transport Layers
-#
-# CONFIG_SAS_CLASS is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_ISCSI_TCP is not set
-# CONFIG_SCSI_ARCMSR is not set
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_3W_9XXX is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AACRAID is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_AIC79XX is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_MEGARAID_NEWGEN is not set
-# CONFIG_MEGARAID_LEGACY is not set
-# CONFIG_MEGARAID_SAS is not set
-# CONFIG_SCSI_SATA is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_IPS is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_SYM53C8XX_2 is not set
-# CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA24XX is not set
-# CONFIG_SCSI_LPFC is not set
-# CONFIG_SCSI_DC395x is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_NSP32 is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-# CONFIG_FUSION_SPI is not set
-# CONFIG_FUSION_FC is not set
-# CONFIG_FUSION_SAS is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-CONFIG_IEEE1394=m
-
-#
-# Subsystem Options
-#
-# CONFIG_IEEE1394_VERBOSEDEBUG is not set
-# CONFIG_IEEE1394_OUI_DB is not set
-CONFIG_IEEE1394_EXTRA_CONFIG_ROMS=y
-CONFIG_IEEE1394_CONFIG_ROM_IP1394=y
-# CONFIG_IEEE1394_EXPORT_FULL_API is not set
-
-#
-# Device Drivers
-#
-
-#
-# Texas Instruments PCILynx requires I2C
-#
-CONFIG_IEEE1394_OHCI1394=m
-
-#
-# Protocol Drivers
-#
-CONFIG_IEEE1394_VIDEO1394=m
-CONFIG_IEEE1394_SBP2=m
-# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set
-CONFIG_IEEE1394_ETH1394=m
-CONFIG_IEEE1394_DV1394=m
-CONFIG_IEEE1394_RAWIO=m
-CONFIG_IEEE1394_CMP=m
-CONFIG_IEEE1394_AMDTP=m
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-CONFIG_DUMMY=m
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-
-#
-# PHY device support
-#
-# CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_CASSINI is not set
-# CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
-# CONFIG_NET_TULIP is not set
-# CONFIG_HP100 is not set
-# CONFIG_NET_PCI is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_E1000 is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-CONFIG_R8169=y
-# CONFIG_R8169_NAPI is not set
-# CONFIG_SIS190 is not set
-# CONFIG_SKGE is not set
-# CONFIG_SKY2 is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_TIGON3 is not set
-# CONFIG_BNX2 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_CHELSIO_T1 is not set
-# CONFIG_IXGB is not set
-# CONFIG_S2IO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-# CONFIG_HOSTAP is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-# CONFIG_NET_FC is not set
-# CONFIG_SHAPER is not set
-# CONFIG_NETCONSOLE is not set
-# CONFIG_KGDBOE is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NETPOLL_RX is not set
-# CONFIG_NETPOLL_TRAP is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-
-#
-# Userland interfaces
-#
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input Device Drivers
-#
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Hardware I/O ports
-#
-# CONFIG_SERIO is not set
-# CONFIG_GAMEPORT is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_SERIAL_VR41XX=y
-CONFIG_SERIAL_VR41XX_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_RTC is not set
-# CONFIG_GEN_RTC is not set
-# CONFIG_RTC_VR41XX is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-# CONFIG_TANBAC_TB0219 is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_DRM is not set
-CONFIG_GPIO_VR41XX=y
-# CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
-# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Dallas's 1-wire bus
-#
-# CONFIG_W1 is not set
-
-#
-# Hardware Monitoring support
-#
-# CONFIG_HWMON is not set
-# CONFIG_HWMON_VID is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia Capabilities Port drivers
-#
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-
-#
-# Speakup console speech
-#
-# CONFIG_SPEAKUP is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
-CONFIG_USB=m
-# CONFIG_USB_DEBUG is not set
-
-#
-# Miscellaneous USB options
-#
-# CONFIG_USB_DEVICEFS is not set
-# CONFIG_USB_BANDWIDTH is not set
-# CONFIG_USB_DYNAMIC_MINORS is not set
-# CONFIG_USB_OTG is not set
-
-#
-# USB Host Controller Drivers
-#
-CONFIG_USB_EHCI_HCD=m
-# CONFIG_USB_EHCI_SPLIT_ISO is not set
-# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
-# CONFIG_USB_ISP116X_HCD is not set
-CONFIG_USB_OHCI_HCD=m
-# CONFIG_USB_OHCI_BIG_ENDIAN is not set
-CONFIG_USB_OHCI_LITTLE_ENDIAN=y
-# CONFIG_USB_UHCI_HCD is not set
-# CONFIG_USB_SL811_HCD is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
-#
-
-#
-# may also be needed; see USB_STORAGE Help for more information
-#
-CONFIG_USB_STORAGE=m
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_USBAT is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_SDDR55 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-
-#
-# USB Input Devices
-#
-CONFIG_USB_HID=m
-CONFIG_USB_HIDINPUT=y
-# CONFIG_HID_FF is not set
-# CONFIG_USB_HIDDEV is not set
-
-#
-# USB HID Boot Protocol drivers
-#
-# CONFIG_USB_KBD is not set
-# CONFIG_USB_MOUSE is not set
-# CONFIG_USB_AIPTEK is not set
-# CONFIG_USB_WACOM is not set
-# CONFIG_USB_ACECAD is not set
-# CONFIG_USB_KBTAB is not set
-# CONFIG_USB_POWERMATE is not set
-# CONFIG_USB_MTOUCH is not set
-# CONFIG_USB_ITMTOUCH is not set
-# CONFIG_USB_EGALAX is not set
-# CONFIG_USB_YEALINK is not set
-# CONFIG_USB_XPAD is not set
-# CONFIG_USB_ATI_REMOTE is not set
-# CONFIG_USB_KEYSPAN_REMOTE is not set
-# CONFIG_USB_APPLETOUCH is not set
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_MICROTEK is not set
-
-#
-# USB Multimedia devices
-#
-# CONFIG_USB_DABUSB is not set
-
-#
-# Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network Adapters
-#
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_RTL8150 is not set
-# CONFIG_USB_USBNET is not set
-CONFIG_USB_MON=y
-
-#
-# USB port drivers
-#
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_EMI62 is not set
-# CONFIG_USB_EMI26 is not set
-# CONFIG_USB_AUERSWALD is not set
-# CONFIG_USB_RIO500 is not set
-# CONFIG_USB_LEGOTOWER is not set
-# CONFIG_USB_LCD is not set
-# CONFIG_USB_LED is not set
-# CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_GOTEMP is not set
-# CONFIG_USB_PHIDGETKIT is not set
-# CONFIG_USB_PHIDGETSERVO is not set
-# CONFIG_USB_IDMOUSE is not set
-# CONFIG_USB_SISUSBVGA is not set
-# CONFIG_USB_LD is not set
-
-#
-# USB DSL modem support
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
-
-#
-# InfiniBand support
-#
-# CONFIG_INFINIBAND is not set
-
-#
-# SN Devices
-#
-
-#
-# EDAC - error detection and reporting (RAS)
-#
-# CONFIG_EDAC is not set
-
-#
-# Distributed Lock Manager
-#
-# CONFIG_DLM is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT2_FS_XIP is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-CONFIG_FS_MBCACHE=y
-# CONFIG_REISER4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_FS_POSIX_ACL is not set
-CONFIG_XFS_FS=y
-CONFIG_XFS_QUOTA=y
-# CONFIG_XFS_SECURITY is not set
-CONFIG_XFS_POSIX_ACL=y
-# CONFIG_XFS_RT is not set
-# CONFIG_OCFS2_FS is not set
-# CONFIG_MINIX_FS is not set
-CONFIG_ROMFS_FS=m
-CONFIG_INOTIFY=y
-# CONFIG_QUOTA is not set
-CONFIG_QUOTACTL=y
-# CONFIG_DNOTIFY is not set
-# CONFIG_AUTOFS_FS is not set
-CONFIG_AUTOFS4_FS=y
-# CONFIG_FUSE_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_MSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-CONFIG_SYSFS=y
-CONFIG_TMPFS=y
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-# CONFIG_RELAYFS_FS is not set
-# CONFIG_CONFIGFS_FS is not set
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_ASFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-CONFIG_CRAMFS=m
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_NFS_V3_ACL is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFS_DIRECTIO is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=y
-# CONFIG_RPCSEC_GSS_KRB5 is not set
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
-# CONFIG_NLS is not set
-
-#
-# Profiling support
-#
-# CONFIG_PROFILING is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_PRINTK_TIME is not set
-# CONFIG_DEBUG_KERNEL is not set
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_CROSSCOMPILE=y
-CONFIG_CMDLINE="mem=64M console=ttyVR0,115200 ip=any root=/dev/nfs"
-
-#
-# Security options
-#
-CONFIG_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
-
-#
-# Hardware crypto devices
-#
-
-#
-# Library routines
-#
-# CONFIG_CRC_CCITT is not set
-# CONFIG_CRC16 is not set
-CONFIG_CRC32=y
-# CONFIG_LIBCRC32C is not set
-CONFIG_ZLIB_INFLATE=m
diff --git a/arch/mips/configs/workpad_defconfig b/arch/mips/configs/workpad_defconfig
index 02b2551..7132e29 100644
--- a/arch/mips/configs/workpad_defconfig
+++ b/arch/mips/configs/workpad_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:07:17 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:36 2006
 #
 CONFIG_MIPS=y
 
@@ -63,9 +63,9 @@
 # CONFIG_TOSHIBA_JMR3927 is not set
 # CONFIG_TOSHIBA_RBTX4927 is not set
 # CONFIG_TOSHIBA_RBTX4938 is not set
-# CONFIG_NEC_CMBVR4133 is not set
 # CONFIG_CASIO_E55 is not set
 CONFIG_IBM_WORKPAD=y
+# CONFIG_NEC_CMBVR4133 is not set
 # CONFIG_TANBAC_TB022X is not set
 # CONFIG_VICTOR_MPC30X is not set
 # CONFIG_ZAO_CAPCELLA is not set
@@ -88,7 +88,7 @@
 # CONFIG_CPU_MIPS64_R2 is not set
 # CONFIG_CPU_R3000 is not set
 # CONFIG_CPU_TX39XX is not set
-CONFIG_CPU_VR41XX=y
+# CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
 # CONFIG_CPU_TX49XX is not set
@@ -101,23 +101,18 @@
 # CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_RM9000 is not set
 # CONFIG_CPU_SB1 is not set
-CONFIG_SYS_HAS_CPU_VR41XX=y
-CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
-CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
 
 #
 # Kernel type
 #
-CONFIG_32BIT=y
+# CONFIG_32BIT is not set
 # CONFIG_64BIT is not set
 CONFIG_PAGE_SIZE_4KB=y
 # CONFIG_PAGE_SIZE_8KB is not set
 # CONFIG_PAGE_SIZE_16KB is not set
 # CONFIG_PAGE_SIZE_64KB is not set
 # CONFIG_MIPS_MT is not set
-# CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_LLSC=y
 CONFIG_CPU_HAS_SYNC=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
@@ -153,26 +148,28 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -188,7 +185,6 @@
 #
 # Block layer
 #
-# CONFIG_LBD is not set
 
 #
 # IO Schedulers
@@ -234,7 +230,6 @@
 #
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-CONFIG_TRAD_SIGNALS=y
 
 #
 # Networking
@@ -289,6 +284,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -309,7 +309,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -445,6 +444,7 @@
 CONFIG_MII=m
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_DM9000 is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_AT1700 is not set
 # CONFIG_DEPCA is not set
@@ -556,10 +556,6 @@
 #
 # Non-8250 serial port support
 #
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_SERIAL_VR41XX=y
-CONFIG_SERIAL_VR41XX_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -588,7 +584,6 @@
 # CONFIG_WDT is not set
 # CONFIG_RTC is not set
 # CONFIG_GEN_RTC is not set
-# CONFIG_RTC_VR41XX is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 
@@ -602,7 +597,6 @@
 # CONFIG_SYNCLINK_CS is not set
 # CONFIG_CARDMAN_4000 is not set
 # CONFIG_CARDMAN_4040 is not set
-# CONFIG_GPIO_VR41XX is not set
 # CONFIG_RAW_DRIVER is not set
 
 #
@@ -617,6 +611,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -699,12 +699,12 @@
 CONFIG_EXT2_FS_SECURITY=y
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -737,6 +737,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -798,6 +799,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/configs/yosemite_defconfig b/arch/mips/configs/yosemite_defconfig
index 468c2e4..6745785 100644
--- a/arch/mips/configs/yosemite_defconfig
+++ b/arch/mips/configs/yosemite_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:07:19 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:37 2006
 #
 CONFIG_MIPS=y
 
@@ -154,8 +154,6 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 # CONFIG_CPUSETS is not set
@@ -164,19 +162,22 @@
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -184,6 +185,7 @@
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 CONFIG_STOP_MACHINE=y
@@ -295,7 +297,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -413,6 +414,7 @@
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -452,8 +454,6 @@
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # Wan interfaces
@@ -498,6 +498,7 @@
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -505,7 +506,6 @@
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -542,6 +542,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -615,7 +621,6 @@
 #
 # CONFIG_EXT2_FS is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
@@ -694,12 +699,13 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
-CONFIG_DEBUG_KERNEL=y
 # CONFIG_MAGIC_SYSRQ is not set
+CONFIG_DEBUG_KERNEL=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_MUTEXES=y
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
@@ -707,6 +713,7 @@
 # CONFIG_DEBUG_INFO is not set
 # CONFIG_DEBUG_FS is not set
 # CONFIG_DEBUG_VM is not set
+CONFIG_FORCED_INLINING=y
 # CONFIG_RCU_TORTURE_TEST is not set
 CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE=""
diff --git a/arch/mips/dec/prom/memory.c b/arch/mips/dec/prom/memory.c
index 83d4556..81cb5a7 100644
--- a/arch/mips/dec/prom/memory.c
+++ b/arch/mips/dec/prom/memory.c
@@ -45,7 +45,7 @@
 	 */
 	for (memory_page = (unsigned char *)CKSEG1 + CHUNK_SIZE;
 	     mem_err == 0 && memory_page < (unsigned char *)CKSEG1 + 0x1e00000;
-  	     memory_page += CHUNK_SIZE) {
+	     memory_page += CHUNK_SIZE) {
 		dummy = *memory_page;
 	}
 	memcpy((void *)(CKSEG0 + 0x80), &old_handler, 0x80);
diff --git a/arch/mips/defconfig b/arch/mips/defconfig
index 4f125e9..42d5cd7 100644
--- a/arch/mips/defconfig
+++ b/arch/mips/defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:05:49 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:39:51 2006
 #
 CONFIG_MIPS=y
 
@@ -158,27 +158,29 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -317,6 +319,28 @@
 CONFIG_NETFILTER_NETLINK=m
 CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -335,39 +359,23 @@
 CONFIG_IP_NF_PPTP=m
 CONFIG_IP_NF_QUEUE=m
 CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
 CONFIG_IP_NF_MATCH_IPRANGE=m
-CONFIG_IP_NF_MATCH_MAC=m
-CONFIG_IP_NF_MATCH_PKTTYPE=m
-CONFIG_IP_NF_MATCH_MARK=m
 CONFIG_IP_NF_MATCH_MULTIPORT=m
 CONFIG_IP_NF_MATCH_TOS=m
 CONFIG_IP_NF_MATCH_RECENT=m
 CONFIG_IP_NF_MATCH_ECN=m
 CONFIG_IP_NF_MATCH_DSCP=m
 CONFIG_IP_NF_MATCH_AH_ESP=m
-CONFIG_IP_NF_MATCH_LENGTH=m
 CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_TCPMSS=m
-CONFIG_IP_NF_MATCH_HELPER=m
-CONFIG_IP_NF_MATCH_STATE=m
-CONFIG_IP_NF_MATCH_CONNTRACK=m
 CONFIG_IP_NF_MATCH_OWNER=m
 CONFIG_IP_NF_MATCH_ADDRTYPE=m
-CONFIG_IP_NF_MATCH_REALM=m
-CONFIG_IP_NF_MATCH_SCTP=m
-CONFIG_IP_NF_MATCH_DCCP=m
-CONFIG_IP_NF_MATCH_COMMENT=m
-CONFIG_IP_NF_MATCH_CONNMARK=m
-CONFIG_IP_NF_MATCH_CONNBYTES=m
 CONFIG_IP_NF_MATCH_HASHLIMIT=m
-CONFIG_IP_NF_MATCH_STRING=m
+CONFIG_IP_NF_MATCH_POLICY=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
 CONFIG_IP_NF_TARGET_LOG=m
 CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_IP_NF_TARGET_TCPMSS=m
-CONFIG_IP_NF_TARGET_NFQUEUE=m
 CONFIG_IP_NF_NAT=m
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
@@ -384,13 +392,9 @@
 CONFIG_IP_NF_TARGET_TOS=m
 CONFIG_IP_NF_TARGET_ECN=m
 CONFIG_IP_NF_TARGET_DSCP=m
-CONFIG_IP_NF_TARGET_MARK=m
-CONFIG_IP_NF_TARGET_CLASSIFY=m
 CONFIG_IP_NF_TARGET_TTL=m
-CONFIG_IP_NF_TARGET_CONNMARK=m
 CONFIG_IP_NF_TARGET_CLUSTERIP=m
 CONFIG_IP_NF_RAW=m
-CONFIG_IP_NF_TARGET_NOTRACK=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
@@ -400,25 +404,20 @@
 #
 CONFIG_IP6_NF_QUEUE=m
 CONFIG_IP6_NF_IPTABLES=m
-CONFIG_IP6_NF_MATCH_LIMIT=m
-CONFIG_IP6_NF_MATCH_MAC=m
 CONFIG_IP6_NF_MATCH_RT=m
 CONFIG_IP6_NF_MATCH_OPTS=m
 CONFIG_IP6_NF_MATCH_FRAG=m
 CONFIG_IP6_NF_MATCH_HL=m
 CONFIG_IP6_NF_MATCH_MULTIPORT=m
 CONFIG_IP6_NF_MATCH_OWNER=m
-CONFIG_IP6_NF_MATCH_MARK=m
 CONFIG_IP6_NF_MATCH_IPV6HEADER=m
 CONFIG_IP6_NF_MATCH_AHESP=m
-CONFIG_IP6_NF_MATCH_LENGTH=m
 CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_POLICY=m
 CONFIG_IP6_NF_FILTER=m
 CONFIG_IP6_NF_TARGET_LOG=m
 CONFIG_IP6_NF_TARGET_REJECT=m
-CONFIG_IP6_NF_TARGET_NFQUEUE=m
 CONFIG_IP6_NF_MANGLE=m
-CONFIG_IP6_NF_TARGET_MARK=m
 CONFIG_IP6_NF_TARGET_HL=m
 CONFIG_IP6_NF_RAW=m
 
@@ -445,6 +444,11 @@
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 CONFIG_NET_DIVERT=y
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -504,7 +508,6 @@
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -641,6 +644,7 @@
 #
 CONFIG_NET_ETHERNET=y
 # CONFIG_MII is not set
+# CONFIG_DM9000 is not set
 CONFIG_SGISEEQ=y
 
 #
@@ -787,6 +791,12 @@
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -892,6 +902,7 @@
 CONFIG_XFS_SECURITY=y
 # CONFIG_XFS_POSIX_ACL is not set
 # CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
 CONFIG_MINIX_FS=m
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -934,6 +945,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1007,6 +1019,7 @@
 CONFIG_SGI_PARTITION=y
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
 # CONFIG_EFI_PARTITION is not set
 
 #
@@ -1062,6 +1075,7 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/jazz/int-handler.S b/arch/mips/jazz/int-handler.S
index 4dbcf91..dc752c6 100644
--- a/arch/mips/jazz/int-handler.S
+++ b/arch/mips/jazz/int-handler.S
@@ -248,17 +248,17 @@
 		and	t2,s1
 		sh	t2,JAZZ_IO_IRQ_ENABLE
 
- 		nor	s1,zero,s1
+		nor	s1,zero,s1
 		jal	do_IRQ
 
- 		/*
- 		 * Reenable interrupt
- 		 */
+		/*
+		 * Reenable interrupt
+		 */
 		lhu	t2,JAZZ_IO_IRQ_ENABLE
- 		or	t2,s1
+		or	t2,s1
 		sh	t2,JAZZ_IO_IRQ_ENABLE
 
- 		j	ret_from_irq
+		j	ret_from_irq
 
 /*
  * "Jump extender" to reach spurious_interrupt
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index 292f8b2..58b3b14 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -291,7 +291,7 @@
 		 * for documentation.  Commented out because it shares
 		 * it's c0_prid id number with the TX3900.
 		 */
- 		c->cputype = CPU_R4650;
+		c->cputype = CPU_R4650;
 	 	c->isa_level = MIPS_CPU_ISA_III;
 		c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_LLSC;
 	        c->tlbsize = 48;
@@ -604,7 +604,7 @@
 	case PRID_IMP_AU1_REV2:
 		switch ((c->processor_id >> 24) & 0xff) {
 		case 0:
- 			c->cputype = CPU_AU1000;
+			c->cputype = CPU_AU1000;
 			break;
 		case 1:
 			c->cputype = CPU_AU1500;
@@ -705,7 +705,7 @@
 		break;
  	case PRID_COMP_PHILIPS:
 		cpu_probe_philips(c);
- 		break;
+		break;
 	default:
 		c->cputype = CPU_UNKNOWN;
 	}
diff --git a/arch/mips/kernel/gdb-low.S b/arch/mips/kernel/gdb-low.S
index 83b8986..235ad9f 100644
--- a/arch/mips/kernel/gdb-low.S
+++ b/arch/mips/kernel/gdb-low.S
@@ -41,7 +41,7 @@
  */
 		.align 	5
 		NESTED(trap_low, GDB_FR_SIZE, sp)
- 		.set	noat
+		.set	noat
 		.set 	noreorder
 
 		mfc0	k0, CP0_STATUS
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
index e00e5f6..013bc93 100644
--- a/arch/mips/kernel/linux32.c
+++ b/arch/mips/kernel/linux32.c
@@ -69,7 +69,7 @@
  * Revalidate the inode. This is required for proper NFS attribute caching.
  */
 
-int cp_compat_stat(struct kstat *stat, struct compat_stat *statbuf)
+int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
 {
 	struct compat_stat tmp;
 
@@ -106,6 +106,10 @@
 	unsigned long error;
 
 	error = -EINVAL;
+	if (pgoff & (~PAGE_MASK >> 12))
+		goto out;
+	pgoff >>= PAGE_SHIFT-12;
+
 	if (!(flags & MAP_ANONYMOUS)) {
 		error = -EBADF;
 		file = fget(fd);
@@ -125,7 +129,7 @@
 }
 
 
-asmlinkage int sys_truncate64(const char *path, unsigned int high,
+asmlinkage int sys_truncate64(const char __user *path, unsigned int high,
 			      unsigned int low)
 {
 	if ((int)high < 0)
@@ -161,12 +165,6 @@
 	return error;
 }
 
-asmlinkage int
-sys32_waitpid(compat_pid_t pid, unsigned int *stat_addr, int options)
-{
-	return compat_sys_wait4(pid, stat_addr, options, NULL);
-}
-
 asmlinkage long
 sysn32_waitid(int which, compat_pid_t pid,
 	      siginfo_t __user *uinfo, int options,
@@ -175,6 +173,7 @@
 	struct rusage ru;
 	long ret;
 	mm_segment_t old_fs = get_fs();
+	int si_signo;
 
 	if (!access_ok(VERIFY_WRITE, uinfo, sizeof(*uinfo)))
 		return -EFAULT;
@@ -184,7 +183,9 @@
 			 uru ? (struct rusage __user *) &ru : NULL);
 	set_fs (old_fs);
 
-	if (ret < 0 || uinfo->si_signo == 0)
+	if (__get_user(si_signo, &uinfo->si_signo))
+		return -EFAULT;
+	if (ret < 0 || si_signo == 0)
 		return ret;
 
 	if (uru)
@@ -208,14 +209,14 @@
 	char _f[8];
 };
 
-asmlinkage int sys32_sysinfo(struct sysinfo32 *info)
+asmlinkage int sys32_sysinfo(struct sysinfo32 __user *info)
 {
 	struct sysinfo s;
 	int ret, err;
 	mm_segment_t old_fs = get_fs ();
 
 	set_fs (KERNEL_DS);
-	ret = sys_sysinfo(&s);
+	ret = sys_sysinfo((struct sysinfo __user *)&s);
 	set_fs (old_fs);
 	err = put_user (s.uptime, &info->uptime);
 	err |= __put_user (s.loads[0], &info->loads[0]);
@@ -245,11 +246,11 @@
 };
 
 #ifdef __MIPSEB__
-asmlinkage long sys32_truncate64(const char * path, unsigned long __dummy,
+asmlinkage long sys32_truncate64(const char __user * path, unsigned long __dummy,
 	int length_hi, int length_lo)
 #endif
 #ifdef __MIPSEL__
-asmlinkage long sys32_truncate64(const char * path, unsigned long __dummy,
+asmlinkage long sys32_truncate64(const char __user * path, unsigned long __dummy,
 	int length_lo, int length_hi)
 #endif
 {
@@ -277,7 +278,7 @@
 }
 
 static inline long
-get_tv32(struct timeval *o, struct compat_timeval *i)
+get_tv32(struct timeval *o, struct compat_timeval __user *i)
 {
 	return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
 		(__get_user(o->tv_sec, &i->tv_sec) |
@@ -285,7 +286,7 @@
 }
 
 static inline long
-put_tv32(struct compat_timeval *o, struct timeval *i)
+put_tv32(struct compat_timeval __user *o, struct timeval *i)
 {
 	return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
 		(__put_user(i->tv_sec, &o->tv_sec) |
@@ -295,7 +296,7 @@
 extern struct timezone sys_tz;
 
 asmlinkage int
-sys32_gettimeofday(struct compat_timeval *tv, struct timezone *tz)
+sys32_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
 {
 	if (tv) {
 		struct timeval ktv;
@@ -310,7 +311,7 @@
 	return 0;
 }
 
-static inline long get_ts32(struct timespec *o, struct compat_timeval *i)
+static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i)
 {
 	long usec;
 
@@ -325,7 +326,7 @@
 }
 
 asmlinkage int
-sys32_settimeofday(struct compat_timeval *tv, struct timezone *tz)
+sys32_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
 {
 	struct timespec kts;
 	struct timezone ktz;
@@ -343,7 +344,7 @@
 }
 
 asmlinkage int sys32_llseek(unsigned int fd, unsigned int offset_high,
-			    unsigned int offset_low, loff_t * result,
+			    unsigned int offset_low, loff_t __user * result,
 			    unsigned int origin)
 {
 	return sys_llseek(fd, offset_high, offset_low, result, origin);
@@ -353,12 +354,12 @@
    lseek back to original location.  They fail just like lseek does on
    non-seekable files.  */
 
-asmlinkage ssize_t sys32_pread(unsigned int fd, char * buf,
+asmlinkage ssize_t sys32_pread(unsigned int fd, char __user * buf,
 			       size_t count, u32 unused, u64 a4, u64 a5)
 {
 	ssize_t ret;
 	struct file * file;
-	ssize_t (*read)(struct file *, char *, size_t, loff_t *);
+	ssize_t (*read)(struct file *, char __user *, size_t, loff_t *);
 	loff_t pos;
 
 	ret = -EBADF;
@@ -388,12 +389,12 @@
 	return ret;
 }
 
-asmlinkage ssize_t sys32_pwrite(unsigned int fd, const char * buf,
+asmlinkage ssize_t sys32_pwrite(unsigned int fd, const char __user * buf,
 			        size_t count, u32 unused, u64 a4, u64 a5)
 {
 	ssize_t ret;
 	struct file * file;
-	ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
+	ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *);
 	loff_t pos;
 
 	ret = -EBADF;
@@ -426,14 +427,14 @@
 }
 
 asmlinkage int sys32_sched_rr_get_interval(compat_pid_t pid,
-	struct compat_timespec *interval)
+	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, &t);
+	ret = sys_sched_rr_get_interval(pid, (struct timespec __user *)&t);
 	set_fs (old_fs);
 	if (put_user (t.tv_sec, &interval->tv_sec) ||
 	    __put_user (t.tv_nsec, &interval->tv_nsec))
@@ -551,7 +552,7 @@
 };
 
 static int
-do_sys32_semctl(int first, int second, int third, void *uptr)
+do_sys32_semctl(int first, int second, int third, void __user *uptr)
 {
 	union semun fourth;
 	u32 pad;
@@ -562,12 +563,12 @@
 	if (!uptr)
 		return -EINVAL;
 	err = -EFAULT;
-	if (get_user (pad, (u32 *)uptr))
+	if (get_user (pad, (u32 __user *)uptr))
 		return err;
 	if ((third & ~IPC_64) == SETVAL)
 		fourth.val = (int)pad;
 	else
-		fourth.__pad = (void *)A(pad);
+		fourth.__pad = (void __user *)A(pad);
 	switch (third & ~IPC_64) {
 	case IPC_INFO:
 	case IPC_RMID:
@@ -585,14 +586,14 @@
 
 	case IPC_STAT:
 	case SEM_STAT:
-		fourth.__pad = &s;
+		fourth.__pad = (struct semid64_ds __user *)&s;
 		old_fs = get_fs();
 		set_fs(KERNEL_DS);
 		err = sys_semctl(first, second, third | IPC_64, fourth);
 		set_fs(old_fs);
 
 		if (third & IPC_64) {
-			struct semid64_ds32 *usp64 = (struct semid64_ds32 *) A(pad);
+			struct semid64_ds32 __user *usp64 = (struct semid64_ds32 __user *) A(pad);
 
 			if (!access_ok(VERIFY_WRITE, usp64, sizeof(*usp64))) {
 				err = -EFAULT;
@@ -609,7 +610,7 @@
 			err2 |= __put_user(s.sem_ctime, &usp64->sem_ctime);
 			err2 |= __put_user(s.sem_nsems, &usp64->sem_nsems);
 		} else {
-			struct semid_ds32 *usp32 = (struct semid_ds32 *) A(pad);
+			struct semid_ds32 __user *usp32 = (struct semid_ds32 __user *) A(pad);
 
 			if (!access_ok(VERIFY_WRITE, usp32, sizeof(*usp32))) {
 				err = -EFAULT;
@@ -639,9 +640,9 @@
 }
 
 static int
-do_sys32_msgsnd (int first, int second, int third, void *uptr)
+do_sys32_msgsnd (int first, int second, int third, void __user *uptr)
 {
-	struct msgbuf32 *up = (struct msgbuf32 *)uptr;
+	struct msgbuf32 __user *up = (struct msgbuf32 __user *)uptr;
 	struct msgbuf *p;
 	mm_segment_t old_fs;
 	int err;
@@ -660,7 +661,7 @@
 		goto out;
 	old_fs = get_fs ();
 	set_fs (KERNEL_DS);
-	err = sys_msgsnd (first, p, second, third);
+	err = sys_msgsnd (first, (struct msgbuf __user *)p, second, third);
 	set_fs (old_fs);
 out:
 	kfree (p);
@@ -670,15 +671,15 @@
 
 static int
 do_sys32_msgrcv (int first, int second, int msgtyp, int third,
-		 int version, void *uptr)
+		 int version, void __user *uptr)
 {
-	struct msgbuf32 *up;
+	struct msgbuf32 __user *up;
 	struct msgbuf *p;
 	mm_segment_t old_fs;
 	int err;
 
 	if (!version) {
-		struct ipc_kludge32 *uipck = (struct ipc_kludge32 *)uptr;
+		struct ipc_kludge32 __user *uipck = (struct ipc_kludge32 __user *)uptr;
 		struct ipc_kludge32 ipck;
 
 		err = -EINVAL;
@@ -687,7 +688,7 @@
 		err = -EFAULT;
 		if (copy_from_user (&ipck, uipck, sizeof (struct ipc_kludge32)))
 			goto out;
-		uptr = (void *)AA(ipck.msgp);
+		uptr = (void __user *)AA(ipck.msgp);
 		msgtyp = ipck.msgtyp;
 	}
 
@@ -699,11 +700,11 @@
 		goto out;
 	old_fs = get_fs ();
 	set_fs (KERNEL_DS);
-	err = sys_msgrcv (first, p, second + 4, msgtyp, third);
+	err = sys_msgrcv (first, (struct msgbuf __user *)p, second + 4, msgtyp, third);
 	set_fs (old_fs);
 	if (err < 0)
 		goto free_then_out;
-	up = (struct msgbuf32 *)uptr;
+	up = (struct msgbuf32 __user *)uptr;
 	if (put_user (p->mtype, &up->mtype) ||
 	    __copy_to_user (&up->mtext, p->mtext, err))
 		err = -EFAULT;
@@ -714,19 +715,19 @@
 }
 
 static int
-do_sys32_msgctl (int first, int second, void *uptr)
+do_sys32_msgctl (int first, int second, void __user *uptr)
 {
 	int err = -EINVAL, err2;
 	struct msqid64_ds m;
-	struct msqid_ds32 *up32 = (struct msqid_ds32 *)uptr;
-	struct msqid64_ds32 *up64 = (struct msqid64_ds32 *)uptr;
+	struct msqid_ds32 __user *up32 = (struct msqid_ds32 __user *)uptr;
+	struct msqid64_ds32 __user *up64 = (struct msqid64_ds32 __user *)uptr;
 	mm_segment_t old_fs;
 
 	switch (second & ~IPC_64) {
 	case IPC_INFO:
 	case IPC_RMID:
 	case MSG_INFO:
-		err = sys_msgctl (first, second, (struct msqid_ds *)uptr);
+		err = sys_msgctl (first, second, (struct msqid_ds __user *)uptr);
 		break;
 
 	case IPC_SET:
@@ -753,7 +754,7 @@
 			break;
 		old_fs = get_fs();
 		set_fs(KERNEL_DS);
-		err = sys_msgctl(first, second | IPC_64, (struct msqid_ds *)&m);
+		err = sys_msgctl(first, second | IPC_64, (struct msqid_ds __user *)&m);
 		set_fs(old_fs);
 		break;
 
@@ -761,7 +762,7 @@
 	case MSG_STAT:
 		old_fs = get_fs();
 		set_fs(KERNEL_DS);
-		err = sys_msgctl(first, second | IPC_64, (struct msqid_ds *)&m);
+		err = sys_msgctl(first, second | IPC_64, (struct msqid_ds __user *)&m);
 		set_fs(old_fs);
 		if (second & IPC_64) {
 			if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) {
@@ -815,10 +816,10 @@
 }
 
 static int
-do_sys32_shmat (int first, int second, int third, int version, void *uptr)
+do_sys32_shmat (int first, int second, int third, int version, void __user *uptr)
 {
 	unsigned long raddr;
-	u32 *uaddr = (u32 *)A((u32)third);
+	u32 __user *uaddr = (u32 __user *)A((u32)third);
 	int err = -EINVAL;
 
 	if (version == 1)
@@ -837,11 +838,11 @@
 };
 
 static int
-do_sys32_shmctl (int first, int second, void *uptr)
+do_sys32_shmctl (int first, int second, void __user *uptr)
 {
-	struct shmid64_ds32 *up64 = (struct shmid64_ds32 *)uptr;
-	struct shmid_ds32 *up32 = (struct shmid_ds32 *)uptr;
-	struct shm_info32 *uip = (struct shm_info32 *)uptr;
+	struct shmid64_ds32 __user *up64 = (struct shmid64_ds32 __user *)uptr;
+	struct shmid_ds32 __user *up32 = (struct shmid_ds32 __user *)uptr;
+	struct shm_info32 __user *uip = (struct shm_info32 __user *)uptr;
 	int err = -EFAULT, err2;
 	struct shmid64_ds s64;
 	mm_segment_t old_fs;
@@ -854,7 +855,7 @@
 	case IPC_RMID:
 	case SHM_LOCK:
 	case SHM_UNLOCK:
-		err = sys_shmctl(first, second, (struct shmid_ds *)uptr);
+		err = sys_shmctl(first, second, (struct shmid_ds __user *)uptr);
 		break;
 	case IPC_SET:
 		if (second & IPC_64) {
@@ -870,7 +871,7 @@
 			break;
 		old_fs = get_fs();
 		set_fs(KERNEL_DS);
-		err = sys_shmctl(first, second & ~IPC_64, &s);
+		err = sys_shmctl(first, second & ~IPC_64, (struct shmid_ds __user *)&s);
 		set_fs(old_fs);
 		break;
 
@@ -878,7 +879,7 @@
 	case SHM_STAT:
 		old_fs = get_fs();
 		set_fs(KERNEL_DS);
-		err = sys_shmctl(first, second | IPC_64, (void *) &s64);
+		err = sys_shmctl(first, second | IPC_64, (void __user *) &s64);
 		set_fs(old_fs);
 		if (err < 0)
 			break;
@@ -928,7 +929,7 @@
 	case SHM_INFO:
 		old_fs = get_fs();
 		set_fs(KERNEL_DS);
-		err = sys_shmctl(first, second, (void *)&si);
+		err = sys_shmctl(first, second, (void __user *)&si);
 		set_fs(old_fs);
 		if (err < 0)
 			break;
@@ -950,11 +951,11 @@
 	return err;
 }
 
-static int sys32_semtimedop(int semid, struct sembuf *tsems, int nsems,
-                            const struct compat_timespec *timeout32)
+static int sys32_semtimedop(int semid, struct sembuf __user *tsems, int nsems,
+                            const struct compat_timespec __user *timeout32)
 {
 	struct compat_timespec t32;
-	struct timespec *t64 = compat_alloc_user_space(sizeof(*t64));
+	struct timespec __user *t64 = compat_alloc_user_space(sizeof(*t64));
 
 	if (copy_from_user(&t32, timeout32, sizeof(t32)))
 		return -EFAULT;
@@ -977,11 +978,11 @@
 	switch (call) {
 	case SEMOP:
 		/* struct sembuf is the same on 32 and 64bit :)) */
-		err = sys_semtimedop (first, (struct sembuf *)AA(ptr), second,
+		err = sys_semtimedop (first, (struct sembuf __user *)AA(ptr), second,
 		                      NULL);
 		break;
 	case SEMTIMEDOP:
-		err = sys32_semtimedop (first, (struct sembuf *)AA(ptr), second,
+		err = sys32_semtimedop (first, (struct sembuf __user *)AA(ptr), second,
 		                      (const struct compat_timespec __user *)AA(fifth));
 		break;
 	case SEMGET:
@@ -989,36 +990,36 @@
 		break;
 	case SEMCTL:
 		err = do_sys32_semctl (first, second, third,
-				       (void *)AA(ptr));
+				       (void __user *)AA(ptr));
 		break;
 
 	case MSGSND:
 		err = do_sys32_msgsnd (first, second, third,
-				       (void *)AA(ptr));
+				       (void __user *)AA(ptr));
 		break;
 	case MSGRCV:
 		err = do_sys32_msgrcv (first, second, fifth, third,
-				       version, (void *)AA(ptr));
+				       version, (void __user *)AA(ptr));
 		break;
 	case MSGGET:
 		err = sys_msgget ((key_t) first, second);
 		break;
 	case MSGCTL:
-		err = do_sys32_msgctl (first, second, (void *)AA(ptr));
+		err = do_sys32_msgctl (first, second, (void __user *)AA(ptr));
 		break;
 
 	case SHMAT:
 		err = do_sys32_shmat (first, second, third,
-				      version, (void *)AA(ptr));
+				      version, (void __user *)AA(ptr));
 		break;
 	case SHMDT:
-		err = sys_shmdt ((char *)A(ptr));
+		err = sys_shmdt ((char __user *)A(ptr));
 		break;
 	case SHMGET:
 		err = sys_shmget (first, (unsigned)second, third);
 		break;
 	case SHMCTL:
-		err = do_sys32_shmctl (first, second, (void *)AA(ptr));
+		err = do_sys32_shmctl (first, second, (void __user *)AA(ptr));
 		break;
 	default:
 		err = -EINVAL;
@@ -1029,7 +1030,7 @@
 }
 
 asmlinkage long sys32_shmat(int shmid, char __user *shmaddr,
-			  int shmflg, int32_t *addr)
+			  int shmflg, int32_t __user *addr)
 {
 	unsigned long raddr;
 	int err;
@@ -1054,12 +1055,13 @@
 
 #ifdef CONFIG_SYSCTL
 
-asmlinkage long sys32_sysctl(struct sysctl_args32 *args)
+asmlinkage long sys32_sysctl(struct sysctl_args32 __user *args)
 {
 	struct sysctl_args32 tmp;
 	int error;
-	size_t oldlen, *oldlenp = NULL;
-	unsigned long addr = (((long)&args->__unused[0]) + 7) & ~7;
+	size_t oldlen;
+	size_t __user *oldlenp = NULL;
+	unsigned long addr = (((unsigned long)&args->__unused[0]) + 7) & ~7;
 
 	if (copy_from_user(&tmp, args, sizeof(tmp)))
 		return -EFAULT;
@@ -1071,20 +1073,20 @@
 		   basically copy the whole sysctl.c here, and
 		   glibc's __sysctl uses rw memory for the structure
 		   anyway.  */
-		if (get_user(oldlen, (u32 *)A(tmp.oldlenp)) ||
-		    put_user(oldlen, (size_t *)addr))
+		if (get_user(oldlen, (u32 __user *)A(tmp.oldlenp)) ||
+		    put_user(oldlen, (size_t __user *)addr))
 			return -EFAULT;
-		oldlenp = (size_t *)addr;
+		oldlenp = (size_t __user *)addr;
 	}
 
 	lock_kernel();
-	error = do_sysctl((int *)A(tmp.name), tmp.nlen, (void *)A(tmp.oldval),
-			  oldlenp, (void *)A(tmp.newval), tmp.newlen);
+	error = do_sysctl((int __user *)A(tmp.name), tmp.nlen, (void __user *)A(tmp.oldval),
+			  oldlenp, (void __user *)A(tmp.newval), tmp.newlen);
 	unlock_kernel();
 	if (oldlenp) {
 		if (!error) {
-			if (get_user(oldlen, (size_t *)addr) ||
-			    put_user(oldlen, (u32 *)A(tmp.oldlenp)))
+			if (get_user(oldlen, (size_t __user *)addr) ||
+			    put_user(oldlen, (u32 __user *)A(tmp.oldlenp)))
 				error = -EFAULT;
 		}
 		copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused));
@@ -1094,7 +1096,7 @@
 
 #endif /* CONFIG_SYSCTL */
 
-asmlinkage long sys32_newuname(struct new_utsname * name)
+asmlinkage long sys32_newuname(struct new_utsname __user * name)
 {
 	int ret = 0;
 
@@ -1129,9 +1131,9 @@
 	char		f_fpack[6];
 };
 
-extern asmlinkage long sys_ustat(dev_t dev, struct ustat * ubuf);
+extern asmlinkage long sys_ustat(dev_t dev, struct ustat __user * ubuf);
 
-asmlinkage int sys32_ustat(dev_t dev, struct ustat32 * ubuf32)
+asmlinkage int sys32_ustat(dev_t dev, struct ustat32 __user * ubuf32)
 {
 	int err;
         struct ustat tmp;
@@ -1139,7 +1141,7 @@
 	mm_segment_t old_fs = get_fs();
 
 	set_fs(KERNEL_DS);
-	err = sys_ustat(dev, &tmp);
+	err = sys_ustat(dev, (struct ustat __user *)&tmp);
 	set_fs (old_fs);
 
 	if (err)
@@ -1172,7 +1174,7 @@
 
 extern int do_adjtimex(struct timex *);
 
-asmlinkage int sys32_adjtimex(struct timex32 *utp)
+asmlinkage int sys32_adjtimex(struct timex32 __user *utp)
 {
 	struct timex txc;
 	int ret;
@@ -1228,7 +1230,7 @@
 	return ret;
 }
 
-asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t *offset,
+asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset,
 	s32 count)
 {
 	mm_segment_t old_fs = get_fs();
@@ -1239,7 +1241,7 @@
 		return -EFAULT;
 
 	set_fs(KERNEL_DS);
-	ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count);
+	ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *)&of : NULL, count);
 	set_fs(old_fs);
 
 	if (offset && put_user(of, offset))
@@ -1269,7 +1271,7 @@
  *  it is set by the callees.
  */
 
-asmlinkage long sys32_socketcall(int call, unsigned int *args32)
+asmlinkage long sys32_socketcall(int call, unsigned int __user *args32)
 {
 	unsigned int a[6];
 	unsigned int a0,a1;
@@ -1291,7 +1293,7 @@
 					    struct sockaddr __user *addr, int __user *addr_len);
 	extern asmlinkage long sys_shutdown(int fd, int how);
 	extern asmlinkage long sys_setsockopt(int fd, int level, int optname, char __user *optval, int optlen);
-	extern asmlinkage long sys_getsockopt(int fd, int level, int optname, char __user *optval, int *optlen);
+	extern asmlinkage long sys_getsockopt(int fd, int level, int optname, char __user *optval, int __user *optlen);
 	extern asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags);
 	extern asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned int flags);
 
@@ -1411,7 +1413,7 @@
 	newsp = regs.regs[5];
 	if (!newsp)
 		newsp = regs.regs[29];
-	parent_tidptr = (int *) regs.regs[6];
+	parent_tidptr = (int __user *) regs.regs[6];
 
 	/* Use __dummy4 instead of getting it off the stack, so that
 	   syscall() works.  */
diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c
index 86fe15b..84ab959 100644
--- a/arch/mips/kernel/proc.c
+++ b/arch/mips/kernel/proc.c
@@ -135,6 +135,7 @@
 	        cpu_has_vce ? "%u" : "not available");
 	seq_printf(m, fmt, 'D', vced_count);
 	seq_printf(m, fmt, 'I', vcei_count);
+	seq_printf(m, "\n");
 
 	return 0;
 }
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 092679c..a8f435d 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -60,17 +60,9 @@
 	}
 }
 
-extern void do_signal(struct pt_regs *regs);
-extern void do_signal32(struct pt_regs *regs);
-
 /*
  * Native o32 and N64 ABI without DSP ASE
  */
-extern int setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
-        int signr, sigset_t *set);
-extern int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
-        int signr, sigset_t *set, siginfo_t *info);
-
 struct mips_abi mips_abi = {
 	.do_signal	= do_signal,
 #ifdef CONFIG_TRAD_SIGNALS
@@ -83,11 +75,6 @@
 /*
  * o32 compatibility on 64-bit kernels, without DSP ASE
  */
-extern int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
-        int signr, sigset_t *set);
-extern int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
-        int signr, sigset_t *set, siginfo_t *info);
-
 struct mips_abi mips_abi_32 = {
 	.do_signal	= do_signal32,
 	.setup_frame	= setup_frame_32,
@@ -99,9 +86,6 @@
 /*
  * N32 on 64-bit kernels, without DSP ASE
  */
-extern int setup_rt_frame_n32(struct k_sigaction * ka, struct pt_regs *regs,
-        int signr, sigset_t *set, siginfo_t *info);
-
 struct mips_abi mips_abi_n32 = {
 	.do_signal	= do_signal,
 	.setup_rt_frame	= setup_rt_frame_n32
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index d9293c5..0cb3b60 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -447,21 +447,10 @@
 {
 	int i;
 
-#if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64)
-	/*
-	 * The 64bit code in 32bit object format trick can't represent
-	 * 64bit wide relocations for linker script symbols.
-	 */
-	code_resource.start = CPHYSADDR(&_text);
-	code_resource.end = CPHYSADDR(&_etext) - 1;
-	data_resource.start = CPHYSADDR(&_etext);
-	data_resource.end = CPHYSADDR(&_edata) - 1;
-#else
 	code_resource.start = virt_to_phys(&_text);
 	code_resource.end = virt_to_phys(&_etext) - 1;
 	data_resource.start = virt_to_phys(&_etext);
 	data_resource.end = virt_to_phys(&_edata) - 1;
-#endif
 
 	/*
 	 * Request address space for all standard RAM.
diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h
index 36bfc25..3ca7862 100644
--- a/arch/mips/kernel/signal-common.h
+++ b/arch/mips/kernel/signal-common.h
@@ -166,11 +166,11 @@
 	sp = regs->regs[29];
 
 	/*
- 	 * FPU emulator may have it's own trampoline active just
- 	 * above the user stack, 16-bytes before the next lowest
- 	 * 16 byte boundary.  Try to avoid trashing it.
- 	 */
- 	sp -= 32;
+	 * FPU emulator may have it's own trampoline active just
+	 * above the user stack, 16-bytes before the next lowest
+	 * 16 byte boundary.  Try to avoid trashing it.
+	 */
+	sp -= 32;
 
 	/* This is the X/Open sanctioned signal stack switching.  */
 	if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0))
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index c974cc9..402efd2 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -100,8 +100,8 @@
 }
 
 #ifdef CONFIG_TRAD_SIGNALS
-asmlinkage int sys_sigaction(int sig, const struct sigaction *act,
-	struct sigaction *oact)
+asmlinkage int sys_sigaction(int sig, const struct sigaction __user *act,
+	struct sigaction __user *oact)
 {
 	struct k_sigaction new_ka, old_ka;
 	int ret;
@@ -331,7 +331,7 @@
 	/* Create the ucontext.  */
 	err |= __put_user(0, &frame->rs_uc.uc_flags);
 	err |= __put_user(NULL, &frame->rs_uc.uc_link);
-	err |= __put_user((void *)current->sas_ss_sp,
+	err |= __put_user((void __user *)current->sas_ss_sp,
 	                  &frame->rs_uc.uc_stack.ss_sp);
 	err |= __put_user(sas_ss_flags(regs->regs[29]),
 	                  &frame->rs_uc.uc_stack.ss_flags);
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index 237cd8a..f32a229 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -163,7 +163,7 @@
 	return err;
 }
 
-static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t *ubuf)
+static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf)
 {
 	int err = 0;
 	unsigned long sig[4];
@@ -195,10 +195,10 @@
 __attribute_used__ noinline static int
 _sys32_sigsuspend(nabi_no_regargs struct pt_regs regs)
 {
-	compat_sigset_t *uset;
+	compat_sigset_t __user *uset;
 	sigset_t newset;
 
-	uset = (compat_sigset_t *) regs.regs[4];
+	uset = (compat_sigset_t __user *) regs.regs[4];
 	if (get_sigset(&newset, uset))
 		return -EFAULT;
 	sigdelsetmask(&newset, ~_BLOCKABLE);
@@ -219,7 +219,7 @@
 __attribute_used__ noinline static int
 _sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
 {
-	compat_sigset_t *uset;
+	compat_sigset_t __user *uset;
 	sigset_t newset;
 	size_t sigsetsize;
 
@@ -228,7 +228,7 @@
 	if (sigsetsize != sizeof(compat_sigset_t))
 		return -EINVAL;
 
-	uset = (compat_sigset_t *) regs.regs[4];
+	uset = (compat_sigset_t __user *) regs.regs[4];
 	if (get_sigset(&newset, uset))
 		return -EFAULT;
 	sigdelsetmask(&newset, ~_BLOCKABLE);
@@ -236,7 +236,7 @@
 	spin_lock_irq(&current->sighand->siglock);
 	current->saved_sigmask = current->blocked;
 	current->blocked = newset;
-        recalc_sigpending();
+	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
 
 	current->state = TASK_INTERRUPTIBLE;
@@ -245,8 +245,8 @@
 	return -ERESTARTNOHAND;
 }
 
-asmlinkage int sys32_sigaction(int sig, const struct sigaction32 *act,
-                               struct sigaction32 *oact)
+asmlinkage int sys32_sigaction(int sig, const struct sigaction32 __user *act,
+                               struct sigaction32 __user *oact)
 {
 	struct k_sigaction new_ka, old_ka;
 	int ret;
@@ -272,15 +272,15 @@
 
 	if (!ret && oact) {
 		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
-                        return -EFAULT;
+			return -EFAULT;
 		err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
 		err |= __put_user((u32)(u64)old_ka.sa.sa_handler,
 		                  &oact->sa_handler);
 		err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
-                err |= __put_user(0, &oact->sa_mask.sig[1]);
-                err |= __put_user(0, &oact->sa_mask.sig[2]);
-                err |= __put_user(0, &oact->sa_mask.sig[3]);
-                if (err)
+		err |= __put_user(0, &oact->sa_mask.sig[1]);
+		err |= __put_user(0, &oact->sa_mask.sig[2]);
+		err |= __put_user(0, &oact->sa_mask.sig[3]);
+		if (err)
 			return -EFAULT;
 	}
 
@@ -301,7 +301,7 @@
 		if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))
 			return -EFAULT;
 		err |= __get_user(sp, &uss->ss_sp);
-		kss.ss_sp = (void *) (long) sp;
+		kss.ss_sp = (void __user *) (long) sp;
 		err |= __get_user(kss.ss_size, &uss->ss_size);
 		err |= __get_user(kss.ss_flags, &uss->ss_flags);
 		if (err)
@@ -316,7 +316,7 @@
 	if (!ret && uoss) {
 		if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
 			return -EFAULT;
-		sp = (int) (long) koss.ss_sp;
+		sp = (int) (unsigned long) koss.ss_sp;
 		err |= __put_user(sp, &uoss->ss_sp);
 		err |= __put_user(koss.ss_size, &uoss->ss_size);
 		err |= __put_user(koss.ss_flags, &uoss->ss_flags);
@@ -527,7 +527,7 @@
 	/* The ucontext contains a stack32_t, so we must convert!  */
 	if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp))
 		goto badframe;
-	st.ss_sp = (void *)(long) sp;
+	st.ss_sp = (void __user *)(long) sp;
 	if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size))
 		goto badframe;
 	if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags))
@@ -624,11 +624,11 @@
 	sp = regs->regs[29];
 
 	/*
- 	 * FPU emulator may have it's own trampoline active just
- 	 * above the user stack, 16-bytes before the next lowest
- 	 * 16 byte boundary.  Try to avoid trashing it.
- 	 */
- 	sp -= 32;
+	 * FPU emulator may have it's own trampoline active just
+	 * above the user stack, 16-bytes before the next lowest
+	 * 16 byte boundary.  Try to avoid trashing it.
+	 */
+	sp -= 32;
 
 	/* This is the X/Open sanctioned signal stack switching.  */
 	if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0))
@@ -868,7 +868,7 @@
 	}
 }
 
-asmlinkage int sys32_rt_sigaction(int sig, const struct sigaction32 *act,
+asmlinkage int sys32_rt_sigaction(int sig, const struct sigaction32 __user *act,
 				  struct sigaction32 __user *oact,
 				  unsigned int sigsetsize)
 {
@@ -912,7 +912,7 @@
 	return ret;
 }
 
-asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t *set,
+asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
 	compat_sigset_t __user *oset, unsigned int sigsetsize)
 {
 	sigset_t old_set, new_set;
diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c
index 3e168c0..477c533 100644
--- a/arch/mips/kernel/signal_n32.c
+++ b/arch/mips/kernel/signal_n32.c
@@ -87,7 +87,8 @@
 __attribute_used__ noinline static int
 _sysn32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
 {
-	compat_sigset_t __user *unewset, uset;
+	compat_sigset_t __user *unewset;
+	compat_sigset_t uset;
 	size_t sigsetsize;
 	sigset_t newset;
 
@@ -141,7 +142,7 @@
 	/* The ucontext contains a stack32_t, so we must convert!  */
 	if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp))
 		goto badframe;
-	st.ss_sp = (void *)(long) sp;
+	st.ss_sp = (void __user *)(long) sp;
 	if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size))
 		goto badframe;
 	if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags))
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index 1da2eeb..2aeaa2f 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -162,7 +162,10 @@
 sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
           unsigned long flags, unsigned long fd, unsigned long pgoff)
 {
-	return do_mmap2(addr, len, prot, flags, fd, pgoff);
+	if (pgoff & (~PAGE_MASK >> 12))
+		return -EINVAL;
+
+	return do_mmap2(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT-12));
 }
 
 save_static_function(sys_fork);
@@ -345,7 +348,7 @@
 		union semun fourth;
 		if (!ptr)
 			return -EINVAL;
-		if (get_user(fourth.__pad, (void *__user *) ptr))
+		if (get_user(fourth.__pad, (void __user *__user *) ptr))
 			return -EFAULT;
 		return sys_semctl (first, second, third, fourth);
 	}
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 005debb..bed0eb6 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -576,7 +576,7 @@
 		}
 #endif
 		/*
-	 	 * Unimplemented operation exception.  If we've got the full
+		 * Unimplemented operation exception.  If we've got the full
 		 * software emulator on-board, let's use it...
 		 *
 		 * Force FPU to dump state into task/thread context.  We're
diff --git a/arch/mips/lasat/image/romscript.normal b/arch/mips/lasat/image/romscript.normal
index ca22336..988f8ad 100644
--- a/arch/mips/lasat/image/romscript.normal
+++ b/arch/mips/lasat/image/romscript.normal
@@ -16,7 +16,8 @@
   _image_start = ADDR(.data);
   _image_size = SIZEOF(.data);
 
-  .other : {
-  	*(.*)
+  .other :
+  {
+    *(.*)
   }
 }
diff --git a/arch/mips/mips-boards/generic/mipsIRQ.S b/arch/mips/mips-boards/generic/mipsIRQ.S
index a397ecb..ddd5c73 100644
--- a/arch/mips/mips-boards/generic/mipsIRQ.S
+++ b/arch/mips/mips-boards/generic/mipsIRQ.S
@@ -98,7 +98,7 @@
 	and	s0, s1
 
 #if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
- 	.set	mips32
+	.set	mips32
 	clz	a0, s0
 	.set	mips0
 	negu	a0
diff --git a/arch/mips/mips-boards/sim/sim_IRQ.c b/arch/mips/mips-boards/sim/sim_IRQ.c
index 9987a85..5b84c7f 100644
--- a/arch/mips/mips-boards/sim/sim_IRQ.c
+++ b/arch/mips/mips-boards/sim/sim_IRQ.c
@@ -96,7 +96,7 @@
 	 andi	a0, s0, CAUSEF_IP3	# delay slot, check hw1 interrupt
 #else
 	beq	a0, zero, 1f		# delay slot, check hw3 interrupt
- 	 andi	a0, s0, CAUSEF_IP5
+	 andi	a0, s0, CAUSEF_IP5
 #endif
 
 	/* Wheee, combined hardware level zero interrupt. */
diff --git a/arch/mips/mips-boards/sim/sim_irq.S b/arch/mips/mips-boards/sim/sim_irq.S
index 835f038..da52297 100644
--- a/arch/mips/mips-boards/sim/sim_irq.S
+++ b/arch/mips/mips-boards/sim/sim_irq.S
@@ -42,7 +42,7 @@
 	and	s0, s1
 
 #if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
- 	.set	mips32
+	.set	mips32
 	clz	a0, s0
 	.set	mips0
 	negu	a0
diff --git a/arch/mips/mips-boards/sim/sim_smp.c b/arch/mips/mips-boards/sim/sim_smp.c
index 1982435..a9f0c2b 100644
--- a/arch/mips/mips-boards/sim/sim_smp.c
+++ b/arch/mips/mips-boards/sim/sim_smp.c
@@ -115,7 +115,7 @@
 #ifdef CONFIG_MIPS_MT_SMTC
 	void mipsmt_prepare_cpus(int c);
 	/*
- 	 * As noted above, we can assume a single CPU for now
+	 * As noted above, we can assume a single CPU for now
 	 * but it may be multithreaded.
 	 */
 
diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile
index b0178da..4a622011 100644
--- a/arch/mips/mm/Makefile
+++ b/arch/mips/mm/Makefile
@@ -12,7 +12,7 @@
 obj-$(CONFIG_CPU_MIPS32)	+= c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o
 obj-$(CONFIG_CPU_MIPS64)	+= c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o
 obj-$(CONFIG_CPU_NEVADA)	+= c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o
-obj-$(CONFIG_CPU_R10000)	+= c-r4k.o cex-gen.o pg-r4k.o tlb-andes.o
+obj-$(CONFIG_CPU_R10000)	+= c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o
 obj-$(CONFIG_CPU_R3000)		+= c-r3k.o tlb-r3k.o pg-r4k.o
 obj-$(CONFIG_CPU_R4300)		+= c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o
 obj-$(CONFIG_CPU_R4X00)		+= c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o
diff --git a/arch/mips/mm/c-r3k.c b/arch/mips/mm/c-r3k.c
index 27f4fa2..9dd1352 100644
--- a/arch/mips/mm/c-r3k.c
+++ b/arch/mips/mm/c-r3k.c
@@ -129,7 +129,7 @@
 			"sb\t$0, 0x014(%0)\n\t"
 			"sb\t$0, 0x018(%0)\n\t"
 			"sb\t$0, 0x01c(%0)\n\t"
-		 	"sb\t$0, 0x020(%0)\n\t"
+			"sb\t$0, 0x020(%0)\n\t"
 			"sb\t$0, 0x024(%0)\n\t"
 			"sb\t$0, 0x028(%0)\n\t"
 			"sb\t$0, 0x02c(%0)\n\t"
@@ -145,7 +145,7 @@
 			"sb\t$0, 0x054(%0)\n\t"
 			"sb\t$0, 0x058(%0)\n\t"
 			"sb\t$0, 0x05c(%0)\n\t"
-		 	"sb\t$0, 0x060(%0)\n\t"
+			"sb\t$0, 0x060(%0)\n\t"
 			"sb\t$0, 0x064(%0)\n\t"
 			"sb\t$0, 0x068(%0)\n\t"
 			"sb\t$0, 0x06c(%0)\n\t"
@@ -182,31 +182,31 @@
 			"sb\t$0, 0x004(%0)\n\t"
 			"sb\t$0, 0x008(%0)\n\t"
 			"sb\t$0, 0x00c(%0)\n\t"
-		 	"sb\t$0, 0x010(%0)\n\t"
+			"sb\t$0, 0x010(%0)\n\t"
 			"sb\t$0, 0x014(%0)\n\t"
 			"sb\t$0, 0x018(%0)\n\t"
 			"sb\t$0, 0x01c(%0)\n\t"
-		 	"sb\t$0, 0x020(%0)\n\t"
+			"sb\t$0, 0x020(%0)\n\t"
 			"sb\t$0, 0x024(%0)\n\t"
 			"sb\t$0, 0x028(%0)\n\t"
 			"sb\t$0, 0x02c(%0)\n\t"
-		 	"sb\t$0, 0x030(%0)\n\t"
+			"sb\t$0, 0x030(%0)\n\t"
 			"sb\t$0, 0x034(%0)\n\t"
 			"sb\t$0, 0x038(%0)\n\t"
 			"sb\t$0, 0x03c(%0)\n\t"
-		 	"sb\t$0, 0x040(%0)\n\t"
+			"sb\t$0, 0x040(%0)\n\t"
 			"sb\t$0, 0x044(%0)\n\t"
 			"sb\t$0, 0x048(%0)\n\t"
 			"sb\t$0, 0x04c(%0)\n\t"
-		 	"sb\t$0, 0x050(%0)\n\t"
+			"sb\t$0, 0x050(%0)\n\t"
 			"sb\t$0, 0x054(%0)\n\t"
 			"sb\t$0, 0x058(%0)\n\t"
 			"sb\t$0, 0x05c(%0)\n\t"
-		 	"sb\t$0, 0x060(%0)\n\t"
+			"sb\t$0, 0x060(%0)\n\t"
 			"sb\t$0, 0x064(%0)\n\t"
 			"sb\t$0, 0x068(%0)\n\t"
 			"sb\t$0, 0x06c(%0)\n\t"
-		 	"sb\t$0, 0x070(%0)\n\t"
+			"sb\t$0, 0x070(%0)\n\t"
 			"sb\t$0, 0x074(%0)\n\t"
 			"sb\t$0, 0x078(%0)\n\t"
 			"sb\t$0, 0x07c(%0)\n\t"
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index 9572ed44..32b7f6a 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -786,6 +786,7 @@
 		c->dcache.waybit = 0;
 
 		c->options |= MIPS_CPU_CACHE_CDEX_P;
+		c->options |= MIPS_CPU_PREFETCH;
 		break;
 
 	case CPU_R4000PC:
diff --git a/arch/mips/mm/pg-r4k.c b/arch/mips/mm/pg-r4k.c
index f51e180..e4390dc 100644
--- a/arch/mips/mm/pg-r4k.c
+++ b/arch/mips/mm/pg-r4k.c
@@ -124,7 +124,7 @@
 
 static inline void build_src_pref(int advance)
 {
-	if (!(load_offset & (cpu_dcache_line_size() - 1))) {
+	if (!(load_offset & (cpu_dcache_line_size() - 1)) && advance) {
 		union mips_instruction mi;
 
 		mi.i_format.opcode     = pref_op;
@@ -166,7 +166,7 @@
 
 static inline void build_dst_pref(int advance)
 {
-	if (!(store_offset & (cpu_dcache_line_size() - 1))) {
+	if (!(store_offset & (cpu_dcache_line_size() - 1)) && advance) {
 		union mips_instruction mi;
 
 		mi.i_format.opcode     = pref_op;
@@ -340,6 +340,12 @@
 
 	if (cpu_has_prefetch) {
 		switch (current_cpu_data.cputype) {
+		case CPU_TX49XX:
+			/* TX49 supports only Pref_Load */
+			pref_offset_clear = 0;
+			pref_offset_copy = 0;
+			break;
+
 		case CPU_RM9000:
 			/*
 			 * As a workaround for erratum G105 which make the
diff --git a/arch/mips/mm/sc-rm7k.c b/arch/mips/mm/sc-rm7k.c
index 9e8ff8b..3b6cc9b 100644
--- a/arch/mips/mm/sc-rm7k.c
+++ b/arch/mips/mm/sc-rm7k.c
@@ -9,6 +9,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/bitops.h>
 
 #include <asm/addrspace.h>
 #include <asm/bcache.h>
@@ -43,14 +44,7 @@
 	/* Catch bad driver code */
 	BUG_ON(size == 0);
 
-	a = addr & ~(sc_lsize - 1);
-	end = (addr + size - 1) & ~(sc_lsize - 1);
-	while (1) {
-		flush_scache_line(a);	/* Hit_Writeback_Inv_SD */
-		if (a == end)
-			break;
-		a += sc_lsize;
-	}
+	blast_scache_range(addr, addr + size);
 
 	if (!rm7k_tcache_enabled)
 		return;
@@ -74,14 +68,7 @@
 	/* Catch bad driver code */
 	BUG_ON(size == 0);
 
-	a = addr & ~(sc_lsize - 1);
-	end = (addr + size - 1) & ~(sc_lsize - 1);
-	while (1) {
-		invalidate_scache_line(a);	/* Hit_Invalidate_SD */
-		if (a == end)
-			break;
-		a += sc_lsize;
-	}
+	blast_inv_scache_range(addr, addr + size);
 
 	if (!rm7k_tcache_enabled)
 		return;
@@ -143,11 +130,17 @@
 
 void __init rm7k_sc_init(void)
 {
+	struct cpuinfo_mips *c = &current_cpu_data;
 	unsigned int config = read_c0_config();
 
 	if ((config & RM7K_CONF_SC))
 		return;
 
+	c->scache.linesz = sc_lsize;
+	c->scache.ways = 4;
+	c->scache.waybit= ffs(scache_size / c->scache.ways) - 1;
+	c->scache.waysize = scache_size / c->scache.ways;
+	c->scache.sets = scache_size / (c->scache.linesz * c->scache.ways);
 	printk(KERN_INFO "Secondary cache size %dK, linesize %d bytes.\n",
 	       (scache_size >> 10), sc_lsize);
 
diff --git a/arch/mips/mm/tlb-andes.c b/arch/mips/mm/tlb-andes.c
deleted file mode 100644
index 3f422a8..0000000
--- a/arch/mips/mm/tlb-andes.c
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * 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) 1997, 1998, 1999 Ralf Baechle (ralf@gnu.org)
- * Copyright (C) 1999 Silicon Graphics, Inc.
- * Copyright (C) 2000 Kanoj Sarcar (kanoj@sgi.com)
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/mmu_context.h>
-
-extern void build_tlb_refill_handler(void);
-
-#define NTLB_ENTRIES       64
-#define NTLB_ENTRIES_HALF  32
-
-void local_flush_tlb_all(void)
-{
-	unsigned long flags;
-	unsigned long old_ctx;
-	unsigned long entry;
-
-	local_irq_save(flags);
-	/* Save old context and create impossible VPN2 value */
-	old_ctx = read_c0_entryhi() & ASID_MASK;
-	write_c0_entryhi(CKSEG0);
-	write_c0_entrylo0(0);
-	write_c0_entrylo1(0);
-
-	entry = read_c0_wired();
-
-	/* Blast 'em all away. */
-	while (entry < NTLB_ENTRIES) {
-		write_c0_index(entry);
-		tlb_write_indexed();
-		entry++;
-	}
-	write_c0_entryhi(old_ctx);
-	local_irq_restore(flags);
-}
-
-void local_flush_tlb_mm(struct mm_struct *mm)
-{
-	int cpu = smp_processor_id();
-	if (cpu_context(cpu, mm) != 0) {
-		drop_mmu_context(mm,cpu);
-	}
-}
-
-void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
-                           unsigned long end)
-{
-	struct mm_struct *mm = vma->vm_mm;
-	int cpu = smp_processor_id();
-
-	if (cpu_context(cpu, mm) != 0) {
-		unsigned long flags;
-		int size;
-
-		local_irq_save(flags);
-		size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
-		size = (size + 1) >> 1;
-		if (size <= NTLB_ENTRIES_HALF) {
-			int oldpid = (read_c0_entryhi() & ASID_MASK);
-			int newpid = (cpu_context(smp_processor_id(), mm)
-				      & ASID_MASK);
-
-			start &= (PAGE_MASK << 1);
-			end += ((PAGE_SIZE << 1) - 1);
-			end &= (PAGE_MASK << 1);
-			while(start < end) {
-				int idx;
-
-				write_c0_entryhi(start | newpid);
-				start += (PAGE_SIZE << 1);
-				tlb_probe();
-				idx = read_c0_index();
-				write_c0_entrylo0(0);
-				write_c0_entrylo1(0);
-				write_c0_entryhi(CKSEG0);
-				if(idx < 0)
-					continue;
-				tlb_write_indexed();
-			}
-			write_c0_entryhi(oldpid);
-		} else {
-			drop_mmu_context(mm, cpu);
-		}
-		local_irq_restore(flags);
-	}
-}
-
-void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
-{
-	unsigned long flags;
-	int size;
-
-	size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
-	size = (size + 1) >> 1;
-
-	local_irq_save(flags);
-	if (size <= NTLB_ENTRIES_HALF) {
-		int pid = read_c0_entryhi();
-
-		start &= (PAGE_MASK << 1);
-		end += ((PAGE_SIZE << 1) - 1);
-		end &= (PAGE_MASK << 1);
-
-		while (start < end) {
-			int idx;
-
-			write_c0_entryhi(start);
-			start += (PAGE_SIZE << 1);
-			tlb_probe();
-			idx = read_c0_index();
-			write_c0_entrylo0(0);
-			write_c0_entrylo1(0);
-			write_c0_entryhi(CKSEG0 + (idx << (PAGE_SHIFT+1)));
-			if (idx < 0)
-				continue;
-			tlb_write_indexed();
-		}
-		write_c0_entryhi(pid);
-	} else {
-		local_flush_tlb_all();
-	}
-	local_irq_restore(flags);
-}
-
-void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
-{
-	if (cpu_context(smp_processor_id(), vma->vm_mm) != 0) {
-		unsigned long flags;
-		int oldpid, newpid, idx;
-
-		newpid = (cpu_context(smp_processor_id(), vma->vm_mm) &
-			  ASID_MASK);
-		page &= (PAGE_MASK << 1);
-		local_irq_save(flags);
-		oldpid = (read_c0_entryhi() & ASID_MASK);
-		write_c0_entryhi(page | newpid);
-		tlb_probe();
-		idx = read_c0_index();
-		write_c0_entrylo0(0);
-		write_c0_entrylo1(0);
-		write_c0_entryhi(CKSEG0);
-		if (idx < 0)
-			goto finish;
-		tlb_write_indexed();
-
-	finish:
-		write_c0_entryhi(oldpid);
-		local_irq_restore(flags);
-	}
-}
-
-/*
- * This one is only used for pages with the global bit set so we don't care
- * much about the ASID.
- */
-void local_flush_tlb_one(unsigned long page)
-{
-	unsigned long flags;
-	int oldpid, idx;
-
-	local_irq_save(flags);
-	page &= (PAGE_MASK << 1);
-	oldpid = read_c0_entryhi() & 0xff;
-	write_c0_entryhi(page);
-	tlb_probe();
-	idx = read_c0_index();
-	write_c0_entrylo0(0);
-	write_c0_entrylo1(0);
-	if (idx >= 0) {
-		/* Make sure all entries differ. */
-		write_c0_entryhi(CKSEG0+(idx<<(PAGE_SHIFT+1)));
-		tlb_write_indexed();
-	}
-	write_c0_entryhi(oldpid);
-
-	local_irq_restore(flags);
-}
-
-/* XXX Simplify this.  On the R10000 writing a TLB entry for an virtual
-   address that already exists will overwrite the old entry and not result
-   in TLB malfunction or TLB shutdown.  */
-void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte)
-{
-	unsigned long flags;
-	pgd_t *pgdp;
-	pud_t *pudp;
-	pmd_t *pmdp;
-	pte_t *ptep;
-	int idx, pid;
-
-	/*
-	 * Handle debugger faulting in for debugee.
-	 */
-	if (current->active_mm != vma->vm_mm)
-		return;
-
-	pid = read_c0_entryhi() & ASID_MASK;
-
-	if ((pid != (cpu_context(smp_processor_id(), vma->vm_mm) & ASID_MASK))
-	    || (cpu_context(smp_processor_id(), vma->vm_mm) == 0)) {
-		printk(KERN_WARNING
-		       "%s: Wheee, bogus tlbpid mmpid=%d tlbpid=%d\n",
-		       __FUNCTION__, (int) (cpu_context(smp_processor_id(),
-		       vma->vm_mm) & ASID_MASK), pid);
-	}
-
-	local_irq_save(flags);
-	address &= (PAGE_MASK << 1);
-	write_c0_entryhi(address | (pid));
-	pgdp = pgd_offset(vma->vm_mm, address);
-	tlb_probe();
-	pudp = pud_offset(pgdp, address);
-	pmdp = pmd_offset(pudp, address);
-	idx = read_c0_index();
-	ptep = pte_offset_map(pmdp, address);
-	write_c0_entrylo0(pte_val(*ptep++) >> 6);
-	write_c0_entrylo1(pte_val(*ptep) >> 6);
-	write_c0_entryhi(address | pid);
-	if (idx < 0) {
-		tlb_write_random();
-	} else {
-		tlb_write_indexed();
-	}
-	write_c0_entryhi(pid);
-	local_irq_restore(flags);
-}
-
-void __init tlb_init(void)
-{
-	/*
-	 * You should never change this register:
-	 *   - On R4600 1.7 the tlbp never hits for pages smaller than
-	 *     the value in the c0_pagemask register.
-	 *   - The entire mm handling assumes the c0_pagemask register to
-	 *     be set for 4kb pages.
-	 */
-	write_c0_pagemask(PM_4K);
-	write_c0_wired(0);
-	write_c0_framemask(0);
-
-        /* From this point on the ARC firmware is dead.  */
-	local_flush_tlb_all();
-
-	/* Did I tell you that ARC SUCKS?  */
-
-	build_tlb_refill_handler();
-}
diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c
index 8297970..a865f239 100644
--- a/arch/mips/mm/tlb-r4k.c
+++ b/arch/mips/mm/tlb-r4k.c
@@ -424,8 +424,13 @@
 	probe_tlb(config);
 	write_c0_pagemask(PM_DEFAULT_MASK);
 	write_c0_wired(0);
+	write_c0_framemask(0);
 	temp_tlb_entry = current_cpu_data.tlbsize - 1;
+
+        /* From this point on the ARC firmware is dead.  */
 	local_flush_tlb_all();
 
+	/* Did I tell you that ARC SUCKS?  */
+
 	build_tlb_refill_handler();
 }
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index ac4f4bf..599b3c2 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -951,7 +951,6 @@
 	/* No i_nop needed here, since the next insn doesn't touch TMP. */
 
 #ifdef CONFIG_SMP
-# ifdef CONFIG_BUILD_ELF64
 	/*
 	 * 64 bit SMP running in XKPHYS has smp_processor_id() << 3
 	 * stored in CONTEXT.
@@ -962,18 +961,6 @@
 	i_daddu(p, ptr, ptr, tmp);
 	i_dmfc0(p, tmp, C0_BADVADDR);
 	i_ld(p, ptr, rel_lo(pgdc), ptr);
-# else
-	/*
-	 * 64 bit SMP running in compat space has the lower part of
-	 * &pgd_current[smp_processor_id()] stored in CONTEXT.
-	 */
-	if (!in_compat_space_p(pgdc))
-		panic("Invalid page directory address!");
-
-	i_dmfc0(p, ptr, C0_CONTEXT);
-	i_dsra(p, ptr, ptr, 23);
-	i_ld(p, ptr, 0, ptr);
-# endif
 #else
 	i_LA_mostly(p, ptr, pgdc);
 	i_ld(p, ptr, rel_lo(pgdc), ptr);
diff --git a/arch/mips/momentum/jaguar_atx/reset.c b/arch/mips/momentum/jaguar_atx/reset.c
index c4236b1..ce9fb2e 100644
--- a/arch/mips/momentum/jaguar_atx/reset.c
+++ b/arch/mips/momentum/jaguar_atx/reset.c
@@ -32,7 +32,7 @@
 #else
 	void *nvram = (void*) 0xfc807000;
 #endif
- 	/* Ask the NVRAM/RTC/watchdog chip to assert reset in 1/16 second */
+	/* Ask the NVRAM/RTC/watchdog chip to assert reset in 1/16 second */
 	writeb(0x84, nvram + 0xff7);
 
 	/* wait for the watchdog to go off */
diff --git a/arch/mips/momentum/jaguar_atx/setup.c b/arch/mips/momentum/jaguar_atx/setup.c
index 2699917..3784c89 100644
--- a/arch/mips/momentum/jaguar_atx/setup.c
+++ b/arch/mips/momentum/jaguar_atx/setup.c
@@ -461,7 +461,7 @@
 	  unsigned int tbControl;
 	  tbControl =
 	    0 << 26 |  /* post trigger delay 0 */
-	    	    0x2 << 16 |		/* sequential trace mode */
+		    0x2 << 16 |		/* sequential trace mode */
 	    //	    0x0 << 16 |		/* non-sequential trace mode */
 	    //	    0xf << 4 |		/* watchpoints disabled */
 	    2 << 2 |		/* armed */
diff --git a/arch/mips/momentum/ocelot_3/reset.c b/arch/mips/momentum/ocelot_3/reset.c
index 72b4423..9d86d24 100644
--- a/arch/mips/momentum/ocelot_3/reset.c
+++ b/arch/mips/momentum/ocelot_3/reset.c
@@ -34,7 +34,7 @@
 	/* base address of timekeeper portion of part */
 	void *nvram = (void *) 0xfc807000L;
 
- 	/* Ask the NVRAM/RTC/watchdog chip to assert reset in 1/16 second */
+	/* Ask the NVRAM/RTC/watchdog chip to assert reset in 1/16 second */
 	writeb(0x84, nvram + 0xff7);
 
 	/* wait for the watchdog to go off */
diff --git a/arch/mips/momentum/ocelot_c/reset.c b/arch/mips/momentum/ocelot_c/reset.c
index 6a2489f..9dcd154 100644
--- a/arch/mips/momentum/ocelot_c/reset.c
+++ b/arch/mips/momentum/ocelot_c/reset.c
@@ -34,7 +34,7 @@
 		0xfc807000;
 #endif
 
- 	/* Ask the NVRAM/RTC/watchdog chip to assert reset in 1/16 second */
+	/* Ask the NVRAM/RTC/watchdog chip to assert reset in 1/16 second */
 	writeb(0x84, nvram + 0xff7);
 
 	/* wait for the watchdog to go off */
diff --git a/arch/mips/pci/fixup-vr4133.c b/arch/mips/pci/fixup-vr4133.c
index 03a0ff2..a8a47b4 100644
--- a/arch/mips/pci/fixup-vr4133.c
+++ b/arch/mips/pci/fixup-vr4133.c
@@ -45,7 +45,7 @@
 
 	/*
 	 * we have to open the bridges' windows down to 0 because otherwise
- 	 * we cannot access ISA south bridge I/O registers that get mapped from
+	 * we cannot access ISA south bridge I/O registers that get mapped from
 	 * 0. for example, 8259 PIC would be unaccessible without that
 	 */
 	if(dev->vendor == PCI_VENDOR_ID_INTEL && dev->device == PCI_DEVICE_ID_INTEL_S21152BB) {
diff --git a/arch/mips/pci/ops-ddb5477.c b/arch/mips/pci/ops-ddb5477.c
index 0406b50..8e57d4c 100644
--- a/arch/mips/pci/ops-ddb5477.c
+++ b/arch/mips/pci/ops-ddb5477.c
@@ -253,9 +253,9 @@
 static int prefix##_##rw##_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 star val) \
 { \
 	if (size == 1) \
-     		return rw##_config_byte(pciswap, bus, devfn, where, (u8 star)val); \
+		return rw##_config_byte(pciswap, bus, devfn, where, (u8 star)val); \
 	else if (size == 2) \
-     		return rw##_config_word(pciswap, bus, devfn, where, (u16 star)val); \
+		return rw##_config_word(pciswap, bus, devfn, where, (u16 star)val); \
 	/* Size must be 4 */ \
      	return rw##_config_dword(pciswap, bus, devfn, where, val); \
 }
diff --git a/arch/mips/pci/ops-tx4938.c b/arch/mips/pci/ops-tx4938.c
index 4c0dcfc..0ff0834 100644
--- a/arch/mips/pci/ops-tx4938.c
+++ b/arch/mips/pci/ops-tx4938.c
@@ -34,16 +34,16 @@
 };
 
 struct resource tx4938_pcic1_pci_io_resource = {
-       	.name	= "PCI1 IO",
-       	.start	= 0,
-       	.end	= 0,
-       	.flags	= IORESOURCE_IO
+	.name	= "PCI1 IO",
+	.start	= 0,
+	.end	= 0,
+	.flags	= IORESOURCE_IO
 };
 struct resource tx4938_pcic1_pci_mem_resource = {
-       	.name	= "PCI1 mem",
-       	.start	= 0,
-       	.end	= 0,
-       	.flags	= IORESOURCE_MEM
+	.name	= "PCI1 mem",
+	.start	= 0,
+	.end	= 0,
+	.flags	= IORESOURCE_MEM
 };
 
 static int mkaddr(int bus, int dev_fn, int where, int *flagsp)
diff --git a/arch/mips/pci/pci-bcm1480.c b/arch/mips/pci/pci-bcm1480.c
index ca975e7..f4ef1a3 100644
--- a/arch/mips/pci/pci-bcm1480.c
+++ b/arch/mips/pci/pci-bcm1480.c
@@ -100,7 +100,7 @@
 
 	if (bus->number == 0) {
 		devno = PCI_SLOT(devfn);
- 		if (bcm1480_bus_status & PCI_DEVICE_MODE)
+		if (bcm1480_bus_status & PCI_DEVICE_MODE)
 			return 0;
 		else
 			return 1;
diff --git a/arch/mips/pci/pci-bcm1480ht.c b/arch/mips/pci/pci-bcm1480ht.c
index aca4a2e..a3eebe5 100644
--- a/arch/mips/pci/pci-bcm1480ht.c
+++ b/arch/mips/pci/pci-bcm1480ht.c
@@ -95,7 +95,7 @@
 
 	if (bus->number == 0) {
 		devno = PCI_SLOT(devfn);
- 		if (bcm1480ht_bus_status & PCI_DEVICE_MODE)
+		if (bcm1480ht_bus_status & PCI_DEVICE_MODE)
 			return 0;
 	}
 	return 1;
diff --git a/arch/mips/pci/pci-ip27.c b/arch/mips/pci/pci-ip27.c
index efc96ce..6002d2a 100644
--- a/arch/mips/pci/pci-ip27.c
+++ b/arch/mips/pci/pci-ip27.c
@@ -379,18 +379,18 @@
 	bridge = (bridge_t *) RAW_NODE_SWIN_BASE(nasid, widget_id);
 
 	/*
- 	 * Clear all pending interrupts.
- 	 */
+	 * Clear all pending interrupts.
+	 */
 	bridge->b_int_rst_stat = BRIDGE_IRR_ALL_CLR;
 
 	/*
- 	 * Until otherwise set up, assume all interrupts are from slot 0
- 	 */
+	 * Until otherwise set up, assume all interrupts are from slot 0
+	 */
 	bridge->b_int_device = 0x0;
 
 	/*
- 	 * swap pio's to pci mem and io space (big windows)
- 	 */
+	 * swap pio's to pci mem and io space (big windows)
+	 */
 	bridge->b_wid_control |= BRIDGE_CTRL_IO_SWAP |
 	                         BRIDGE_CTRL_MEM_SWAP;
 
diff --git a/arch/mips/philips/pnx8550/common/int.c b/arch/mips/philips/pnx8550/common/int.c
index 5461449..c500e2d 100644
--- a/arch/mips/philips/pnx8550/common/int.c
+++ b/arch/mips/philips/pnx8550/common/int.c
@@ -251,7 +251,7 @@
 		if (gic_int_line == (PNX8550_INT_GPIO0 - PNX8550_INT_GIC_MIN)) {
 			/* PCI INT through gpio 8, which is setup in
 			 * pnx8550_setup.c and routed to GPIO
- 			 * Interrupt Level 0 (GPIO Connection 58).
+			 * Interrupt Level 0 (GPIO Connection 58).
 			 * Set it active low. */
 
 			PNX8550_GIC_REQ(gic_int_line) = 0x1E020000;
diff --git a/arch/mips/qemu/Makefile b/arch/mips/qemu/Makefile
index 934944a..6a8e8bc 100644
--- a/arch/mips/qemu/Makefile
+++ b/arch/mips/qemu/Makefile
@@ -3,3 +3,5 @@
 #
 
 obj-y		= q-firmware.o q-int.o q-irq.o q-mem.o q-setup.o
+
+obj-$(CONFIG_SMP) += q-smp.o
diff --git a/arch/mips/qemu/q-smp.c b/arch/mips/qemu/q-smp.c
new file mode 100644
index 0000000..5a12354
--- /dev/null
+++ b/arch/mips/qemu/q-smp.c
@@ -0,0 +1,48 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2006 by Ralf Baechle (ralf@linux-mips.org)
+ *
+ * Symmetric Uniprocessor (TM) Support
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+/*
+ * Send inter-processor interrupt
+ */
+void core_send_ipi(int cpu, unsigned int action)
+{
+	panic(KERN_ERR "%s called", __FUNCTION__);
+}
+
+/*
+ *  After we've done initial boot, this function is called to allow the
+ *  board code to clean up state, if needed
+ */
+void prom_init_secondary(void)
+{
+}
+
+void prom_smp_finish(void)
+{
+}
+
+/* Hook for after all CPUs are online */
+void prom_cpus_done(void)
+{
+}
+
+void __init prom_prepare_cpus(unsigned int max_cpus)
+{
+	cpus_clear(phys_cpu_present_map);
+}
+
+/*
+ * Firmware CPU startup hook
+ */
+void prom_boot_secondary(int cpu, struct task_struct *idle)
+{
+}
diff --git a/arch/mips/sgi-ip27/ip27-memory.c b/arch/mips/sgi-ip27/ip27-memory.c
index ef20d9a..ed93a97 100644
--- a/arch/mips/sgi-ip27/ip27-memory.c
+++ b/arch/mips/sgi-ip27/ip27-memory.c
@@ -540,8 +540,8 @@
 		struct page *end, *p;
 
 		/*
-	 	 * This will free up the bootmem, ie, slot 0 memory.
-	 	 */
+		 * This will free up the bootmem, ie, slot 0 memory.
+		 */
 		totalram_pages += free_all_bootmem_node(NODE_DATA(node));
 
 		/*
diff --git a/arch/mips/sgi-ip32/ip32-setup.c b/arch/mips/sgi-ip32/ip32-setup.c
index 2c38770..2f50c79 100644
--- a/arch/mips/sgi-ip32/ip32-setup.c
+++ b/arch/mips/sgi-ip32/ip32-setup.c
@@ -98,7 +98,7 @@
 	board_timer_setup = ip32_timer_setup;
 
 #ifdef CONFIG_SERIAL_8250
- 	{
+	{
 		static struct uart_port o2_serial[2];
 
 		memset(o2_serial, 0, sizeof(o2_serial));
diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_prom.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_prom.c
index e19e2be..efe5056 100644
--- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_prom.c
+++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_prom.c
@@ -70,10 +70,10 @@
 
 	if ((read_c0_prid() & 0xff) == PRID_REV_TX4927) {
 		mips_machtype = MACH_TOSHIBA_RBTX4927;
- 		toshiba_name  = "TX4927";
+		toshiba_name  = "TX4927";
 	} else {
 		mips_machtype = MACH_TOSHIBA_RBTX4937;
- 		toshiba_name  = "TX4937";
+		toshiba_name  = "TX4937";
 	}
 
 	msize = tx4927_get_mem_size();
diff --git a/arch/mips/tx4938/toshiba_rbtx4938/setup.c b/arch/mips/tx4938/toshiba_rbtx4938/setup.c
index 5c7ace9..9166cd4 100644
--- a/arch/mips/tx4938/toshiba_rbtx4938/setup.c
+++ b/arch/mips/tx4938/toshiba_rbtx4938/setup.c
@@ -684,7 +684,7 @@
 	for (i = 0; i < 8; i++) {
 		if (!(tx4938_ebuscptr->cr[i] & 0x8))
 			continue;	/* disabled */
- 		rbtx4938_ce_base[i] = (unsigned long)TX4938_EBUSC_BA(i);
+		rbtx4938_ce_base[i] = (unsigned long)TX4938_EBUSC_BA(i);
 		txboard_add_phys_region(rbtx4938_ce_base[i], TX4938_EBUSC_SIZE(i));
 	}
 
diff --git a/arch/mips/vr41xx/common/bcu.c b/arch/mips/vr41xx/common/bcu.c
index de0c1b3..ff272b2 100644
--- a/arch/mips/vr41xx/common/bcu.c
+++ b/arch/mips/vr41xx/common/bcu.c
@@ -183,11 +183,11 @@
 	switch (current_cpu_data.cputype) {
 	case CPU_VR4111:
 		if (!(clkspeed & DIV2B))
-        		tclock = pclock / 2;
+			tclock = pclock / 2;
 		else if (!(clkspeed & DIV3B))
-        		tclock = pclock / 3;
+			tclock = pclock / 3;
 		else if (!(clkspeed & DIV4B))
-        		tclock = pclock / 4;
+			tclock = pclock / 4;
 		break;
 	case CPU_VR4121:
 		tclock = pclock / DIVT(clkspeed);
diff --git a/arch/v850/kernel/vmlinux.lds.S b/arch/v850/kernel/vmlinux.lds.S
index 5be05f4..5b2ffcc 100644
--- a/arch/v850/kernel/vmlinux.lds.S
+++ b/arch/v850/kernel/vmlinux.lds.S
@@ -64,6 +64,10 @@
 		___start___ksymtab_gpl = .;				      \
 			*(__ksymtab_gpl)				      \
 		___stop___ksymtab_gpl = .;				      \
+		/* Kernel symbol table: GPL-future symbols */		      \
+		___start___ksymtab_gpl_future = .;			      \
+			*(__ksymtab_gpl_future)				      \
+		___stop___ksymtab_gpl_future = .;			      \
 		/* Kernel symbol table: strings */			      \
 			*(__ksymtab_strings)				      \
 		/* Kernel symbol table: Normal symbols */		      \
@@ -74,6 +78,10 @@
 		___start___kcrctab_gpl = .;				      \
 			*(__kcrctab_gpl)				      \
 		___stop___kcrctab_gpl = .;				      \
+		/* Kernel symbol table: GPL-future symbols */		      \
+		___start___kcrctab_gpl_future = .;			      \
+			*(__kcrctab_gpl_future)				      \
+		___stop___kcrctab_gpl_future = .;			      \
 		/* Built-in module parameters */			      \
 		. = ALIGN (4) ;						      \
 		___start___param = .;					      \
diff --git a/block/genhd.c b/block/genhd.c
index db57546..64510fd 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -15,12 +15,13 @@
 #include <linux/kmod.h>
 #include <linux/kobj_map.h>
 #include <linux/buffer_head.h>
+#include <linux/mutex.h>
 
 #define MAX_PROBE_HASH 255	/* random */
 
 static struct subsystem block_subsys;
 
-static DECLARE_MUTEX(block_subsys_sem);
+static DEFINE_MUTEX(block_subsys_lock);
 
 /*
  * Can be deleted altogether. Later.
@@ -46,7 +47,7 @@
 /*
  * iterate over a list of blkdev_info structures.  allows
  * the major_names array to be iterated over from outside this file
- * must be called with the block_subsys_sem held
+ * must be called with the block_subsys_lock held
  */
 void *get_next_blkdev(void *dev)
 {
@@ -85,20 +86,20 @@
 
 void *acquire_blkdev_list(void)
 {
-        down(&block_subsys_sem);
+        mutex_lock(&block_subsys_lock);
         return get_next_blkdev(NULL);
 }
 
 void release_blkdev_list(void *dev)
 {
-        up(&block_subsys_sem);
+        mutex_unlock(&block_subsys_lock);
         kfree(dev);
 }
 
 
 /*
  * Count the number of records in the blkdev_list.
- * must be called with the block_subsys_sem held
+ * must be called with the block_subsys_lock held
  */
 int count_blkdev_list(void)
 {
@@ -118,7 +119,7 @@
 /*
  * extract the major and name values from a blkdev_info struct
  * passed in as a void to *dev.  Must be called with
- * block_subsys_sem held
+ * block_subsys_lock held
  */
 int get_blkdev_info(void *dev, int *major, char **name)
 {
@@ -138,7 +139,7 @@
 	struct blk_major_name **n, *p;
 	int index, ret = 0;
 
-	down(&block_subsys_sem);
+	mutex_lock(&block_subsys_lock);
 
 	/* temporary */
 	if (major == 0) {
@@ -183,7 +184,7 @@
 		kfree(p);
 	}
 out:
-	up(&block_subsys_sem);
+	mutex_unlock(&block_subsys_lock);
 	return ret;
 }
 
@@ -197,7 +198,7 @@
 	int index = major_to_index(major);
 	int ret = 0;
 
-	down(&block_subsys_sem);
+	mutex_lock(&block_subsys_lock);
 	for (n = &major_names[index]; *n; n = &(*n)->next)
 		if ((*n)->major == major)
 			break;
@@ -207,7 +208,7 @@
 		p = *n;
 		*n = p->next;
 	}
-	up(&block_subsys_sem);
+	mutex_unlock(&block_subsys_lock);
 	kfree(p);
 
 	return ret;
@@ -301,7 +302,7 @@
 	struct list_head *p;
 	loff_t l = *pos;
 
-	down(&block_subsys_sem);
+	mutex_lock(&block_subsys_lock);
 	list_for_each(p, &block_subsys.kset.list)
 		if (!l--)
 			return list_entry(p, struct gendisk, kobj.entry);
@@ -318,7 +319,7 @@
 
 static void part_stop(struct seq_file *part, void *v)
 {
-	up(&block_subsys_sem);
+	mutex_unlock(&block_subsys_lock);
 }
 
 static int show_partition(struct seq_file *part, void *v)
@@ -377,7 +378,7 @@
 
 static int __init genhd_device_init(void)
 {
-	bdev_map = kobj_map_init(base_probe, &block_subsys_sem);
+	bdev_map = kobj_map_init(base_probe, &block_subsys_lock);
 	blk_dev_init();
 	subsystem_register(&block_subsys);
 	return 0;
@@ -611,7 +612,7 @@
 	loff_t k = *pos;
 	struct list_head *p;
 
-	down(&block_subsys_sem);
+	mutex_lock(&block_subsys_lock);
 	list_for_each(p, &block_subsys.kset.list)
 		if (!k--)
 			return list_entry(p, struct gendisk, kobj.entry);
@@ -628,7 +629,7 @@
 
 static void diskstats_stop(struct seq_file *part, void *v)
 {
-	up(&block_subsys_sem);
+	mutex_unlock(&block_subsys_lock);
 }
 
 static int diskstats_show(struct seq_file *s, void *v)
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 07a7f97..29f3d75 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -141,7 +141,7 @@
 	return error;
 }
 
-struct sys_device *get_cpu_sysdev(int cpu)
+struct sys_device *get_cpu_sysdev(unsigned cpu)
 {
 	if (cpu < NR_CPUS)
 		return cpu_sys_devices[cpu];
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index e97e911..4723182 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -211,18 +211,20 @@
 fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
 {
 	u8 *new_data;
+	int new_size = fw_priv->alloc_size;
 
 	if (min_size <= fw_priv->alloc_size)
 		return 0;
 
-	new_data = vmalloc(fw_priv->alloc_size + PAGE_SIZE);
+	new_size = ALIGN(min_size, PAGE_SIZE);
+	new_data = vmalloc(new_size);
 	if (!new_data) {
 		printk(KERN_ERR "%s: unable to alloc buffer\n", __FUNCTION__);
 		/* Make sure that we don't keep incomplete data */
 		fw_load_abort(fw_priv);
 		return -ENOMEM;
 	}
-	fw_priv->alloc_size += PAGE_SIZE;
+	fw_priv->alloc_size = new_size;
 	if (fw_priv->fw->data) {
 		memcpy(new_data, fw_priv->fw->data, fw_priv->fw->size);
 		vfree(fw_priv->fw->data);
diff --git a/drivers/base/map.c b/drivers/base/map.c
index b449dae..e87017f 100644
--- a/drivers/base/map.c
+++ b/drivers/base/map.c
@@ -11,6 +11,7 @@
 
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
 #include <linux/kdev_t.h>
 #include <linux/kobject.h>
 #include <linux/kobj_map.h>
@@ -25,7 +26,7 @@
 		int (*lock)(dev_t, void *);
 		void *data;
 	} *probes[255];
-	struct semaphore *sem;
+	struct mutex *lock;
 };
 
 int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range,
@@ -53,7 +54,7 @@
 		p->range = range;
 		p->data = data;
 	}
-	down(domain->sem);
+	mutex_lock(domain->lock);
 	for (i = 0, p -= n; i < n; i++, p++, index++) {
 		struct probe **s = &domain->probes[index % 255];
 		while (*s && (*s)->range < range)
@@ -61,7 +62,7 @@
 		p->next = *s;
 		*s = p;
 	}
-	up(domain->sem);
+	mutex_unlock(domain->lock);
 	return 0;
 }
 
@@ -75,7 +76,7 @@
 	if (n > 255)
 		n = 255;
 
-	down(domain->sem);
+	mutex_lock(domain->lock);
 	for (i = 0; i < n; i++, index++) {
 		struct probe **s;
 		for (s = &domain->probes[index % 255]; *s; s = &(*s)->next) {
@@ -88,7 +89,7 @@
 			}
 		}
 	}
-	up(domain->sem);
+	mutex_unlock(domain->lock);
 	kfree(found);
 }
 
@@ -99,7 +100,7 @@
 	unsigned long best = ~0UL;
 
 retry:
-	down(domain->sem);
+	mutex_lock(domain->lock);
 	for (p = domain->probes[MAJOR(dev) % 255]; p; p = p->next) {
 		struct kobject *(*probe)(dev_t, int *, void *);
 		struct module *owner;
@@ -120,7 +121,7 @@
 			module_put(owner);
 			continue;
 		}
-		up(domain->sem);
+		mutex_unlock(domain->lock);
 		kobj = probe(dev, index, data);
 		/* Currently ->owner protects _only_ ->probe() itself. */
 		module_put(owner);
@@ -128,11 +129,11 @@
 			return kobj;
 		goto retry;
 	}
-	up(domain->sem);
+	mutex_unlock(domain->lock);
 	return NULL;
 }
 
-struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct semaphore *sem)
+struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct mutex *lock)
 {
 	struct kobj_map *p = kmalloc(sizeof(struct kobj_map), GFP_KERNEL);
 	struct probe *base = kzalloc(sizeof(*base), GFP_KERNEL);
@@ -149,6 +150,6 @@
 	base->get = base_probe;
 	for (i = 0; i < 255; i++)
 		p->probes[i] = base;
-	p->sem = sem;
+	p->lock = lock;
 	return p;
 }
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 461554a..89b2683 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -61,7 +61,7 @@
 {
 	struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ, num);
 
-	return r ? r->start : 0;
+	return r ? r->start : -ENXIO;
 }
 EXPORT_SYMBOL_GPL(platform_get_irq);
 
@@ -98,7 +98,7 @@
 {
 	struct resource *r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name);
 
-	return r ? r->start : 0;
+	return r ? r->start : -ENXIO;
 }
 EXPORT_SYMBOL_GPL(platform_get_irq_byname);
 
diff --git a/drivers/block/ub.c b/drivers/block/ub.c
index f04d864..f73446f 100644
--- a/drivers/block/ub.c
+++ b/drivers/block/ub.c
@@ -8,7 +8,6 @@
  * and is not licensed separately. See file COPYING for details.
  *
  * TODO (sorted by decreasing priority)
- *  -- Kill first_open (Al Viro fixed the block layer now)
  *  -- 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)
  *  -- special case some senses, e.g. 3a/0 -> no media present, reduce retries
@@ -181,6 +180,7 @@
 #define UB_DIR_ILLEGAL2	2
 #define UB_DIR_WRITE	3
 
+/* P3 */
 #define UB_DIR_CHAR(c)  (((c)==UB_DIR_WRITE)? 'w': \
 			 (((c)==UB_DIR_READ)? 'r': 'n'))
 
@@ -196,24 +196,11 @@
 	UB_CMDST_DONE			/* Final state */
 };
 
-static char *ub_scsi_cmd_stname[] = {
-	".  ",
-	"Cmd",
-	"dat",
-	"c2s",
-	"sts",
-	"clr",
-	"crs",
-	"Sen",
-	"fin"
-};
-
 struct ub_scsi_cmd {
 	unsigned char cdb[UB_MAX_CDB_SIZE];
 	unsigned char cdb_len;
 
 	unsigned char dir;		/* 0 - none, 1 - read, 3 - write. */
-	unsigned char trace_index;
 	enum ub_scsi_cmd_state state;
 	unsigned int tag;
 	struct ub_scsi_cmd *next;
@@ -250,28 +237,6 @@
 };
 
 /*
- * The SCSI command tracing structure.
- */
-
-#define SCMD_ST_HIST_SZ   8
-#define SCMD_TRACE_SZ    63		/* Less than 4KB of 61-byte lines */
-
-struct ub_scsi_cmd_trace {
-	int hcur;
-	unsigned int tag;
-	unsigned int req_size, act_size;
-	unsigned char op;
-	unsigned char dir;
-	unsigned char key, asc, ascq;
-	char st_hst[SCMD_ST_HIST_SZ];	
-};
-
-struct ub_scsi_trace {
-	int cur;
-	struct ub_scsi_cmd_trace vec[SCMD_TRACE_SZ];
-};
-
-/*
  * 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.
@@ -334,7 +299,6 @@
 	int changed;			/* Media was changed */
 	int removable;
 	int readonly;
-	int first_open;			/* Kludge. See ub_bd_open. */
 
 	struct ub_request urq;
 
@@ -390,7 +354,6 @@
 	wait_queue_head_t reset_wait;
 
 	int sg_stat[6];
-	struct ub_scsi_trace tr;
 };
 
 /*
@@ -460,137 +423,6 @@
 static DEFINE_SPINLOCK(ub_lock);	/* Locks globals and ->openc */
 
 /*
- * The SCSI command tracing procedures.
- */
-
-static void ub_cmdtr_new(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-	int n;
-	struct ub_scsi_cmd_trace *t;
-
-	if ((n = sc->tr.cur + 1) == SCMD_TRACE_SZ) n = 0;
-	t = &sc->tr.vec[n];
-
-	memset(t, 0, sizeof(struct ub_scsi_cmd_trace));
-	t->tag = cmd->tag;
-	t->op = cmd->cdb[0];
-	t->dir = cmd->dir;
-	t->req_size = cmd->len;
-	t->st_hst[0] = cmd->state;
-
-	sc->tr.cur = n;
-	cmd->trace_index = n;
-}
-
-static void ub_cmdtr_state(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-	int n;
-	struct ub_scsi_cmd_trace *t;
-
-	t = &sc->tr.vec[cmd->trace_index];
-	if (t->tag == cmd->tag) {
-		if ((n = t->hcur + 1) == SCMD_ST_HIST_SZ) n = 0;
-		t->st_hst[n] = cmd->state;
-		t->hcur = n;
-	}
-}
-
-static void ub_cmdtr_act_len(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-	struct ub_scsi_cmd_trace *t;
-
-	t = &sc->tr.vec[cmd->trace_index];
-	if (t->tag == cmd->tag)
-		t->act_size = cmd->act_len;
-}
-
-static void ub_cmdtr_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
-    unsigned char *sense)
-{
-	struct ub_scsi_cmd_trace *t;
-
-	t = &sc->tr.vec[cmd->trace_index];
-	if (t->tag == cmd->tag) {
-		t->key = sense[2] & 0x0F;
-		t->asc = sense[12];
-		t->ascq = sense[13];
-	}
-}
-
-static ssize_t ub_diag_show(struct device *dev, struct device_attribute *attr,
-    char *page)
-{
-	struct usb_interface *intf;
-	struct ub_dev *sc;
-	struct list_head *p;
-	struct ub_lun *lun;
-	int cnt;
-	unsigned long flags;
-	int nc, nh;
-	int i, j;
-	struct ub_scsi_cmd_trace *t;
-
-	intf = to_usb_interface(dev);
-	sc = usb_get_intfdata(intf);
-	if (sc == NULL)
-		return 0;
-
-	cnt = 0;
-	spin_lock_irqsave(sc->lock, flags);
-
-	cnt += sprintf(page + cnt,
-	    "poison %d reset %d\n",
-	    atomic_read(&sc->poison), sc->reset);
-	cnt += sprintf(page + cnt,
-	    "qlen %d qmax %d\n",
-	    sc->cmd_queue.qlen, sc->cmd_queue.qmax);
-	cnt += sprintf(page + cnt,
-	    "sg %d %d %d %d %d .. %d\n",
-	    sc->sg_stat[0],
-	    sc->sg_stat[1],
-	    sc->sg_stat[2],
-	    sc->sg_stat[3],
-	    sc->sg_stat[4],
-	    sc->sg_stat[5]);
-
-	list_for_each (p, &sc->luns) {
-		lun = list_entry(p, struct ub_lun, link);
-		cnt += sprintf(page + cnt,
-		    "lun %u changed %d removable %d readonly %d\n",
-		    lun->num, lun->changed, lun->removable, lun->readonly);
-	}
-
-	if ((nc = sc->tr.cur + 1) == SCMD_TRACE_SZ) nc = 0;
-	for (j = 0; j < SCMD_TRACE_SZ; j++) {
-		t = &sc->tr.vec[nc];
-
-		cnt += sprintf(page + cnt, "%08x %02x", t->tag, t->op);
-		if (t->op == REQUEST_SENSE) {
-			cnt += sprintf(page + cnt, " [sense %x %02x %02x]",
-					t->key, t->asc, t->ascq);
-		} else {
-			cnt += sprintf(page + cnt, " %c", UB_DIR_CHAR(t->dir));
-			cnt += sprintf(page + cnt, " [%5d %5d]",
-					t->req_size, t->act_size);
-		}
-		if ((nh = t->hcur + 1) == SCMD_ST_HIST_SZ) nh = 0;
-		for (i = 0; i < SCMD_ST_HIST_SZ; i++) {
-			cnt += sprintf(page + cnt, " %s",
-					ub_scsi_cmd_stname[(int)t->st_hst[nh]]);
-			if (++nh == SCMD_ST_HIST_SZ) nh = 0;
-		}
-		cnt += sprintf(page + cnt, "\n");
-
-		if (++nc == SCMD_TRACE_SZ) nc = 0;
-	}
-
-	spin_unlock_irqrestore(sc->lock, flags);
-	return cnt;
-}
-
-static DEVICE_ATTR(diag, S_IRUGO, ub_diag_show, NULL); /* N.B. World readable */
-
-/*
  * The id allocator.
  *
  * This also stores the host for indexing by minor, which is somewhat dirty.
@@ -1092,7 +924,6 @@
 	add_timer(&sc->work_timer);
 
 	cmd->state = UB_CMDST_CMD;
-	ub_cmdtr_state(sc, cmd);
 	return 0;
 }
 
@@ -1145,12 +976,10 @@
 			ub_cmdq_pop(sc);
 			(*cmd->done)(sc, cmd);
 		} else if (cmd->state == UB_CMDST_INIT) {
-			ub_cmdtr_new(sc, cmd);
 			if ((rc = ub_scsi_cmd_start(sc, cmd)) == 0)
 				break;
 			cmd->error = rc;
 			cmd->state = UB_CMDST_DONE;
-			ub_cmdtr_state(sc, cmd);
 		} else {
 			if (!ub_is_completed(&sc->work_done))
 				break;
@@ -1247,7 +1076,6 @@
 				return;
 			}
 			cmd->state = UB_CMDST_CLEAR;
-			ub_cmdtr_state(sc, cmd);
 			return;
 		case -ESHUTDOWN:	/* unplug */
 		case -EILSEQ:		/* unplug timeout on uhci */
@@ -1279,7 +1107,6 @@
 				return;
 			}
 			cmd->state = UB_CMDST_CLR2STS;
-			ub_cmdtr_state(sc, cmd);
 			return;
 		}
 		if (urb->status == -EOVERFLOW) {
@@ -1304,7 +1131,6 @@
 			if (urb->status != 0 ||
 			    len != cmd->sgv[cmd->current_sg].length) {
 				cmd->act_len += len;
-				ub_cmdtr_act_len(sc, cmd);
 
 				cmd->error = -EIO;
 				ub_state_stat(sc, cmd);
@@ -1331,7 +1157,6 @@
 		}
 
 		cmd->act_len += urb->actual_length;
-		ub_cmdtr_act_len(sc, cmd);
 
 		if (++cmd->current_sg < cmd->nsg) {
 			ub_data_start(sc, cmd);
@@ -1357,7 +1182,6 @@
 			cmd->error = -EIO;		/* A cheap trick... */
 
 			cmd->state = UB_CMDST_CLRRS;
-			ub_cmdtr_state(sc, cmd);
 			return;
 		}
 
@@ -1441,7 +1265,6 @@
 			return;
 		}
 		cmd->state = UB_CMDST_DONE;
-		ub_cmdtr_state(sc, cmd);
 		ub_cmdq_pop(sc);
 		(*cmd->done)(sc, cmd);
 
@@ -1496,7 +1319,6 @@
 	add_timer(&sc->work_timer);
 
 	cmd->state = UB_CMDST_DATA;
-	ub_cmdtr_state(sc, cmd);
 }
 
 /*
@@ -1508,7 +1330,6 @@
 
 	cmd->error = rc;
 	cmd->state = UB_CMDST_DONE;
-	ub_cmdtr_state(sc, cmd);
 	ub_cmdq_pop(sc);
 	(*cmd->done)(sc, cmd);
 }
@@ -1554,7 +1375,6 @@
 
 	cmd->stat_count = 0;
 	cmd->state = UB_CMDST_STAT;
-	ub_cmdtr_state(sc, cmd);
 }
 
 /*
@@ -1573,7 +1393,6 @@
 		return;
 
 	cmd->state = UB_CMDST_STAT;
-	ub_cmdtr_state(sc, cmd);
 }
 
 /*
@@ -1611,7 +1430,6 @@
 	scmd->tag = sc->tagcnt++;
 
 	cmd->state = UB_CMDST_SENSE;
-	ub_cmdtr_state(sc, cmd);
 
 	ub_cmdq_insert(sc, scmd);
 	return;
@@ -1668,11 +1486,6 @@
 	struct ub_scsi_cmd *cmd;
 
 	/*
-	 * Ignoring scmd->act_len, because the buffer was pre-zeroed.
-	 */
-	ub_cmdtr_sense(sc, scmd, sense);
-
-	/*
 	 * Find the command which triggered the unit attention or a check,
 	 * save the sense into it, and advance its state machine.
 	 */
@@ -1693,6 +1506,9 @@
 		return;
 	}
 
+	/*
+	 * Ignoring scmd->act_len, because the buffer was pre-zeroed.
+	 */
 	cmd->key = sense[2] & 0x0F;
 	cmd->asc = sense[12];
 	cmd->ascq = sense[13];
@@ -1849,26 +1665,6 @@
 	sc->openc++;
 	spin_unlock_irqrestore(&ub_lock, flags);
 
-	/*
-	 * This is a workaround for a specific problem in our block layer.
-	 * In 2.6.9, register_disk duplicates the code from rescan_partitions.
-	 * However, if we do add_disk with a device which persistently reports
-	 * a changed media, add_disk calls register_disk, which does do_open,
-	 * which will call rescan_paritions for changed media. After that,
-	 * register_disk attempts to do it all again and causes double kobject
-	 * registration and a eventually an oops on module removal.
-	 *
-	 * The bottom line is, Al Viro says that we should not allow
-	 * bdev->bd_invalidated to be set when doing add_disk no matter what.
-	 */
-	if (lun->first_open) {
-		lun->first_open = 0;
-		if (lun->changed) {
-			rc = -ENOMEDIUM;
-			goto err_open;
-		}
-	}
-
 	if (lun->removable || lun->readonly)
 		check_disk_change(inode->i_bdev);
 
@@ -2007,9 +1803,8 @@
 	init_completion(&compl);
 
 	rc = -ENOMEM;
-	if ((cmd = kmalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
+	if ((cmd = kzalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
 		goto err_alloc;
-	memset(cmd, 0, ALLOC_SIZE);
 
 	cmd->cdb[0] = TEST_UNIT_READY;
 	cmd->cdb_len = 6;
@@ -2062,9 +1857,8 @@
 	init_completion(&compl);
 
 	rc = -ENOMEM;
-	if ((cmd = kmalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
+	if ((cmd = kzalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
 		goto err_alloc;
-	memset(cmd, 0, ALLOC_SIZE);
 	p = (char *)cmd + sizeof(struct ub_scsi_cmd);
 
 	cmd->cdb[0] = 0x25;
@@ -2405,9 +2199,8 @@
 		return -ENXIO;
 
 	rc = -ENOMEM;
-	if ((sc = kmalloc(sizeof(struct ub_dev), GFP_KERNEL)) == NULL)
+	if ((sc = kzalloc(sizeof(struct ub_dev), GFP_KERNEL)) == NULL)
 		goto err_core;
-	memset(sc, 0, sizeof(struct ub_dev));
 	sc->lock = ub_next_lock();
 	INIT_LIST_HEAD(&sc->luns);
 	usb_init_urb(&sc->work_urb);
@@ -2438,9 +2231,6 @@
 	if (ub_get_pipes(sc, sc->dev, intf) != 0)
 		goto err_dev_desc;
 
-	if (device_create_file(&sc->intf->dev, &dev_attr_diag) != 0)
-		goto err_diag;
-
 	/*
 	 * At this point, all USB initialization is done, do upper layer.
 	 * We really hate halfway initialized structures, so from the
@@ -2480,19 +2270,8 @@
 
 	nluns = 1;
 	for (i = 0; i < 3; i++) {
-		if ((rc = ub_sync_getmaxlun(sc)) < 0) {
-			/* 
-			 * This segment is taken from usb-storage. They say
-			 * that ZIP-100 needs this, but my own ZIP-100 works
-			 * fine without this.
-			 * Still, it does not seem to hurt anything.
-			 */
-			if (rc == -EPIPE) {
-				ub_probe_clear_stall(sc, sc->recv_bulk_pipe);
-				ub_probe_clear_stall(sc, sc->send_bulk_pipe);
-			}
+		if ((rc = ub_sync_getmaxlun(sc)) < 0)
 			break;
-		}
 		if (rc != 0) {
 			nluns = rc;
 			break;
@@ -2505,8 +2284,6 @@
 	}
 	return 0;
 
-	/* device_remove_file(&sc->intf->dev, &dev_attr_diag); */
-err_diag:
 err_dev_desc:
 	usb_set_intfdata(intf, NULL);
 	// usb_put_intf(sc->intf);
@@ -2524,9 +2301,8 @@
 	int rc;
 
 	rc = -ENOMEM;
-	if ((lun = kmalloc(sizeof(struct ub_lun), GFP_KERNEL)) == NULL)
+	if ((lun = kzalloc(sizeof(struct ub_lun), GFP_KERNEL)) == NULL)
 		goto err_alloc;
-	memset(lun, 0, sizeof(struct ub_lun));
 	lun->num = lnum;
 
 	rc = -ENOSR;
@@ -2541,7 +2317,6 @@
 
 	lun->removable = 1;		/* XXX Query this from the device */
 	lun->changed = 1;		/* ub_revalidate clears only */
-	lun->first_open = 1;
 	ub_revalidate(sc, lun);
 
 	rc = -ENOMEM;
@@ -2636,7 +2411,6 @@
 		while ((cmd = ub_cmdq_peek(sc)) != NULL) {
 			cmd->error = -ENOTCONN;
 			cmd->state = UB_CMDST_DONE;
-			ub_cmdtr_state(sc, cmd);
 			ub_cmdq_pop(sc);
 			(*cmd->done)(sc, cmd);
 			cnt++;
@@ -2687,7 +2461,6 @@
 	 * and no URBs left in transit.
 	 */
 
-	device_remove_file(&sc->intf->dev, &dev_attr_diag);
 	usb_set_intfdata(intf, NULL);
 	// usb_put_intf(sc->intf);
 	sc->intf = NULL;
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 503dd90..090d154 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -31,7 +31,7 @@
 obj-$(CONFIG_A2232)		+= ser_a2232.o generic_serial.o
 obj-$(CONFIG_ATARI_DSP56K)	+= dsp56k.o
 obj-$(CONFIG_MOXA_SMARTIO)	+= mxser.o
-obj-$(CONFIG_COMPUTONE)		+= ip2.o ip2main.o
+obj-$(CONFIG_COMPUTONE)		+= ip2/
 obj-$(CONFIG_RISCOM8)		+= riscom8.o
 obj-$(CONFIG_ISI)		+= isicom.o
 obj-$(CONFIG_SYNCLINK)		+= synclink.o
diff --git a/drivers/char/drm/Kconfig b/drivers/char/drm/Kconfig
index 56ace9d..5278c38 100644
--- a/drivers/char/drm/Kconfig
+++ b/drivers/char/drm/Kconfig
@@ -37,8 +37,8 @@
 	help
 	  Choose this option if you have an ATI Radeon graphics card.  There
 	  are both PCI and AGP versions.  You don't need to choose this to
-	  run the Radeon in plain VGA mode.  There is a product page at
-	  <http://www.ati.com/na/pages/products/pc/radeon32/index.html>.
+	  run the Radeon in plain VGA mode.
+	  
 	  If M is selected, the module will be called radeon.
 
 config DRM_I810
diff --git a/drivers/char/ip2/Makefile b/drivers/char/ip2/Makefile
new file mode 100644
index 0000000..6bfe254
--- /dev/null
+++ b/drivers/char/ip2/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the Computone IntelliPort Plus Driver
+#
+
+obj-$(CONFIG_COMPUTONE)         += ip2.o ip2main.o
+
+ip2-objs			:= ip2base.o
+
diff --git a/drivers/char/ip2.c b/drivers/char/ip2/ip2base.c
similarity index 94%
rename from drivers/char/ip2.c
rename to drivers/char/ip2/ip2base.c
index 7cadfc6..435ccfc 100644
--- a/drivers/char/ip2.c
+++ b/drivers/char/ip2/ip2base.c
@@ -20,14 +20,14 @@
 #define __initdata
 #endif
 
-#include "./ip2/ip2types.h"		
-#include "./ip2/fip_firm.h"		// the meat
+#include "ip2types.h"		
+#include "fip_firm.h"		// the meat
 
 int
 ip2_loadmain(int *, int  *, unsigned char *, int ); // ref into ip2main.c
 
 /* Note: Add compiled in defaults to these arrays, not to the structure
-	in ip2/ip2.h any longer.  That structure WILL get overridden
+	in ip2.h any longer.  That structure WILL get overridden
 	by these values, or command line values, or insmod values!!!  =mhw=
 */
 static int io[IP2_MAX_BOARDS]= { 0, 0, 0, 0 };
diff --git a/drivers/char/ip2main.c b/drivers/char/ip2/ip2main.c
similarity index 99%
rename from drivers/char/ip2main.c
rename to drivers/char/ip2/ip2main.c
index 48fcfba..03db1cb 100644
--- a/drivers/char/ip2main.c
+++ b/drivers/char/ip2/ip2main.c
@@ -35,7 +35,7 @@
 // Clean up potential NULL pointer dereferences
 // Clean up devfs registration
 // Add kernel command line parsing for io and irq
-//	Compile defaults for io and irq are now set in ip2.c not ip2/ip2.h!
+//	Compile defaults for io and irq are now set in ip2.c not ip2.h!
 // Reworked poll_only hack for explicit parameter setting
 //	You must now EXPLICITLY set poll_only = 1 or set all irqs to 0
 // Merged ip2_loadmain and old_ip2_init
@@ -123,12 +123,12 @@
 
 #include <asm/uaccess.h>
 
-#include "./ip2/ip2types.h"
-#include "./ip2/ip2trace.h"
-#include "./ip2/ip2ioctl.h"
-#include "./ip2/ip2.h"
-#include "./ip2/i2ellis.h"
-#include "./ip2/i2lib.h"
+#include "ip2types.h"
+#include "ip2trace.h"
+#include "ip2ioctl.h"
+#include "ip2.h"
+#include "i2ellis.h"
+#include "i2lib.h"
 
 /*****************
  * /proc/ip2mem  *
@@ -282,9 +282,9 @@
 /* Code */
 /********/
 
-#include "./ip2/i2ellis.c"    /* Extremely low-level interface services */
-#include "./ip2/i2cmd.c"      /* Standard loadware command definitions */
-#include "./ip2/i2lib.c"      /* High level interface services */
+#include "i2ellis.c"    /* Extremely low-level interface services */
+#include "i2cmd.c"      /* Standard loadware command definitions */
+#include "i2lib.c"      /* High level interface services */
 
 /* Configuration area for modprobe */
 
diff --git a/drivers/char/s3c2410-rtc.c b/drivers/char/s3c2410-rtc.c
index 2e30865..b0038b1 100644
--- a/drivers/char/s3c2410-rtc.c
+++ b/drivers/char/s3c2410-rtc.c
@@ -448,13 +448,13 @@
 	/* find the IRQs */
 
 	s3c2410_rtc_tickno = platform_get_irq(pdev, 1);
-	if (s3c2410_rtc_tickno <= 0) {
+	if (s3c2410_rtc_tickno < 0) {
 		dev_err(&pdev->dev, "no irq for rtc tick\n");
 		return -ENOENT;
 	}
 
 	s3c2410_rtc_alarmno = platform_get_irq(pdev, 0);
-	if (s3c2410_rtc_alarmno <= 0) {
+	if (s3c2410_rtc_alarmno < 0) {
 		dev_err(&pdev->dev, "no irq for alarm\n");
 		return -ENOENT;
 	}
diff --git a/drivers/char/watchdog/mpcore_wdt.c b/drivers/char/watchdog/mpcore_wdt.c
index b4d8434..2c2c517 100644
--- a/drivers/char/watchdog/mpcore_wdt.c
+++ b/drivers/char/watchdog/mpcore_wdt.c
@@ -338,6 +338,10 @@
 
 	wdt->dev = &dev->dev;
 	wdt->irq = platform_get_irq(dev, 0);
+	if (wdt->irq < 0) {
+		ret = -ENXIO;
+		goto err_free;
+	}
 	wdt->base = ioremap(res->start, res->end - res->start + 1);
 	if (!wdt->base) {
 		ret = -ENOMEM;
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
index 1414851..d00a02f 100644
--- a/drivers/i2c/busses/i2c-iop3xx.c
+++ b/drivers/i2c/busses/i2c-iop3xx.c
@@ -434,7 +434,7 @@
 iop3xx_i2c_probe(struct platform_device *pdev)
 {
 	struct resource *res;
-	int ret;
+	int ret, irq;
 	struct i2c_adapter *new_adapter;
 	struct i2c_algo_iop3xx_data *adapter_data;
 
@@ -470,7 +470,12 @@
 		goto release_region;
 	}
 
-	ret = request_irq(platform_get_irq(pdev, 0), iop3xx_i2c_irq_handler, 0,
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		ret = -ENXIO;
+		goto unmap;
+	}
+	ret = request_irq(irq, iop3xx_i2c_irq_handler, 0,
 				pdev->name, adapter_data);
 
 	if (ret) {
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 5ccd338..2721e4c 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -302,6 +302,10 @@
 	}
 
 	i2c->irq = platform_get_irq(pdev, 0);
+	if (i2c->irq < 0) {
+		result = -ENXIO;
+		goto fail_get_irq;
+	}
 	i2c->flags = pdata->device_flags;
 	init_waitqueue_head(&i2c->queue);
 
@@ -340,6 +344,7 @@
       fail_irq:
 	iounmap(i2c->base);
       fail_map:
+      fail_get_irq:
 	kfree(i2c);
 	return result;
 };
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index 22781d8..ac5cde1 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -516,6 +516,10 @@
 	drv_data->freq_m = pdata->freq_m;
 	drv_data->freq_n = pdata->freq_n;
 	drv_data->irq = platform_get_irq(pd, 0);
+	if (drv_data->irq < 0) {
+		rc = -ENXIO;
+		goto exit_unmap_regs;
+	}
 	drv_data->adapter.id = I2C_HW_MV64XXX;
 	drv_data->adapter.algo = &mv64xxx_i2c_algo;
 	drv_data->adapter.owner = THIS_MODULE;
diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c
index 32431dc..71f27e9 100644
--- a/drivers/ide/mips/au1xxx-ide.c
+++ b/drivers/ide/mips/au1xxx-ide.c
@@ -674,6 +674,11 @@
 		ret = -ENODEV;
 		goto out;
 	}
+	if (ahwif->irq < 0) {
+		pr_debug("%s %d: no IRQ\n", DRV_NAME, pdev->id);
+		ret = -ENODEV;
+		goto out;
+	}
 
 	if (!request_mem_region (res->start, res->end-res->start, pdev->name)) {
 		pr_debug("%s: request_mem_region failed\n", DRV_NAME);
diff --git a/drivers/infiniband/core/agent.c b/drivers/infiniband/core/agent.c
index 34b724a..ecd1a30 100644
--- a/drivers/infiniband/core/agent.c
+++ b/drivers/infiniband/core/agent.c
@@ -78,25 +78,6 @@
 	return entry;
 }
 
-int smi_check_local_dr_smp(struct ib_smp *smp,
-			   struct ib_device *device,
-			   int port_num)
-{
-	struct ib_agent_port_private *port_priv;
-
-	if (smp->mgmt_class != IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
-		return 1;
-
-	port_priv = ib_get_agent_port(device, port_num);
-	if (!port_priv) {
-		printk(KERN_DEBUG SPFX "smi_check_local_dr_smp %s port %d "
-		       "not open\n", device->name, port_num);
-		return 1;
-	}
-
-	return smi_check_local_smp(port_priv->agent[0], smp);
-}
-
 int agent_send_response(struct ib_mad *mad, struct ib_grh *grh,
 			struct ib_wc *wc, struct ib_device *device,
 			int port_num, int qpn)
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index 2514de3..7cfedb8 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -121,7 +121,7 @@
 
 	struct rb_node service_node;
 	struct rb_node sidr_id_node;
-	spinlock_t lock;
+	spinlock_t lock;	/* Do not acquire inside cm.lock */
 	wait_queue_head_t wait;
 	atomic_t refcount;
 
@@ -1547,28 +1547,6 @@
 		return -EINVAL;
 	}
 
-	cm_id_priv->timewait_info->work.remote_id = rep_msg->local_comm_id;
-	cm_id_priv->timewait_info->remote_ca_guid = rep_msg->local_ca_guid;
-	cm_id_priv->timewait_info->remote_qpn = cm_rep_get_local_qpn(rep_msg);
-
-	spin_lock_irqsave(&cm.lock, flags);
-	/* Check for duplicate REP. */
-	if (cm_insert_remote_id(cm_id_priv->timewait_info)) {
-		spin_unlock_irqrestore(&cm.lock, flags);
-		ret = -EINVAL;
-		goto error;
-	}
-	/* Check for a stale connection. */
-	if (cm_insert_remote_qpn(cm_id_priv->timewait_info)) {
-		spin_unlock_irqrestore(&cm.lock, flags);
-		cm_issue_rej(work->port, work->mad_recv_wc,
-			     IB_CM_REJ_STALE_CONN, CM_MSG_RESPONSE_REP,
-			     NULL, 0);
-		ret = -EINVAL;
-		goto error;
-	}
-	spin_unlock_irqrestore(&cm.lock, flags);
-
 	cm_format_rep_event(work);
 
 	spin_lock_irqsave(&cm_id_priv->lock, flags);
@@ -1581,6 +1559,34 @@
 		ret = -EINVAL;
 		goto error;
 	}
+
+	cm_id_priv->timewait_info->work.remote_id = rep_msg->local_comm_id;
+	cm_id_priv->timewait_info->remote_ca_guid = rep_msg->local_ca_guid;
+	cm_id_priv->timewait_info->remote_qpn = cm_rep_get_local_qpn(rep_msg);
+
+	spin_lock(&cm.lock);
+	/* Check for duplicate REP. */
+	if (cm_insert_remote_id(cm_id_priv->timewait_info)) {
+		spin_unlock(&cm.lock);
+		spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+		ret = -EINVAL;
+		goto error;
+	}
+	/* Check for a stale connection. */
+	if (cm_insert_remote_qpn(cm_id_priv->timewait_info)) {
+		rb_erase(&cm_id_priv->timewait_info->remote_id_node,
+			 &cm.remote_id_table);
+		cm_id_priv->timewait_info->inserted_remote_id = 0;
+		spin_unlock(&cm.lock);
+		spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+		cm_issue_rej(work->port, work->mad_recv_wc,
+			     IB_CM_REJ_STALE_CONN, CM_MSG_RESPONSE_REP,
+			     NULL, 0);
+		ret = -EINVAL;
+		goto error;
+	}
+	spin_unlock(&cm.lock);
+
 	cm_id_priv->id.state = IB_CM_REP_RCVD;
 	cm_id_priv->id.remote_id = rep_msg->local_comm_id;
 	cm_id_priv->remote_qpn = cm_rep_get_local_qpn(rep_msg);
@@ -1603,7 +1609,7 @@
 		cm_deref_id(cm_id_priv);
 	return 0;
 
-error:	cm_cleanup_timewait(cm_id_priv->timewait_info);
+error:
 	cm_deref_id(cm_id_priv);
 	return ret;
 }
diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c
index d34a6f1..838bf54 100644
--- a/drivers/infiniband/core/fmr_pool.c
+++ b/drivers/infiniband/core/fmr_pool.c
@@ -278,9 +278,9 @@
 	{
 		struct ib_pool_fmr *fmr;
 		struct ib_fmr_attr attr = {
-			.max_pages = params->max_pages_per_fmr,
-			.max_maps  = IB_FMR_MAX_REMAPS,
-			.page_size = PAGE_SHIFT
+			.max_pages  = params->max_pages_per_fmr,
+			.max_maps   = IB_FMR_MAX_REMAPS,
+			.page_shift = params->page_shift
 		};
 
 		for (i = 0; i < params->pool_size; ++i) {
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index c82f47a..f7854b6 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -31,7 +31,7 @@
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  *
- * $Id: mad.c 2817 2005-07-07 11:29:26Z halr $
+ * $Id: mad.c 5596 2006-03-03 01:00:07Z sean.hefty $
  */
 #include <linux/dma-mapping.h>
 
@@ -679,8 +679,8 @@
 		goto out;
 	}
 	/* Check to post send on QP or process locally */
-	ret = smi_check_local_dr_smp(smp, device, port_num);
-	if (!ret || !device->process_mad)
+	ret = smi_check_local_smp(smp, device);
+	if (!ret)
 		goto out;
 
 	local = kmalloc(sizeof *local, GFP_ATOMIC);
@@ -765,18 +765,67 @@
 	return ret;
 }
 
-static int get_buf_length(int hdr_len, int data_len)
+static int get_pad_size(int hdr_len, int data_len)
 {
 	int seg_size, pad;
 
 	seg_size = sizeof(struct ib_mad) - hdr_len;
 	if (data_len && seg_size) {
 		pad = seg_size - data_len % seg_size;
-		if (pad == seg_size)
-			pad = 0;
+		return pad == seg_size ? 0 : pad;
 	} else
-		pad = seg_size;
-	return hdr_len + data_len + pad;
+		return seg_size;
+}
+
+static void free_send_rmpp_list(struct ib_mad_send_wr_private *mad_send_wr)
+{
+	struct ib_rmpp_segment *s, *t;
+
+	list_for_each_entry_safe(s, t, &mad_send_wr->rmpp_list, list) {
+		list_del(&s->list);
+		kfree(s);
+	}
+}
+
+static int alloc_send_rmpp_list(struct ib_mad_send_wr_private *send_wr,
+				gfp_t gfp_mask)
+{
+	struct ib_mad_send_buf *send_buf = &send_wr->send_buf;
+	struct ib_rmpp_mad *rmpp_mad = send_buf->mad;
+	struct ib_rmpp_segment *seg = NULL;
+	int left, seg_size, pad;
+
+	send_buf->seg_size = sizeof (struct ib_mad) - send_buf->hdr_len;
+	seg_size = send_buf->seg_size;
+	pad = send_wr->pad;
+
+	/* Allocate data segments. */
+	for (left = send_buf->data_len + pad; left > 0; left -= seg_size) {
+		seg = kmalloc(sizeof (*seg) + seg_size, gfp_mask);
+		if (!seg) {
+			printk(KERN_ERR "alloc_send_rmpp_segs: RMPP mem "
+			       "alloc failed for len %zd, gfp %#x\n",
+			       sizeof (*seg) + seg_size, gfp_mask);
+			free_send_rmpp_list(send_wr);
+			return -ENOMEM;
+		}
+		seg->num = ++send_buf->seg_count;
+		list_add_tail(&seg->list, &send_wr->rmpp_list);
+	}
+
+	/* Zero any padding */
+	if (pad)
+		memset(seg->data + seg_size - pad, 0, pad);
+
+	rmpp_mad->rmpp_hdr.rmpp_version = send_wr->mad_agent_priv->
+					  agent.rmpp_version;
+	rmpp_mad->rmpp_hdr.rmpp_type = IB_MGMT_RMPP_TYPE_DATA;
+	ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE);
+
+	send_wr->cur_seg = container_of(send_wr->rmpp_list.next,
+					struct ib_rmpp_segment, list);
+	send_wr->last_ack_seg = send_wr->cur_seg;
+	return 0;
 }
 
 struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent,
@@ -787,32 +836,40 @@
 {
 	struct ib_mad_agent_private *mad_agent_priv;
 	struct ib_mad_send_wr_private *mad_send_wr;
-	int buf_size;
+	int pad, message_size, ret, size;
 	void *buf;
 
 	mad_agent_priv = container_of(mad_agent, struct ib_mad_agent_private,
 				      agent);
-	buf_size = get_buf_length(hdr_len, data_len);
+	pad = get_pad_size(hdr_len, data_len);
+	message_size = hdr_len + data_len + pad;
 
 	if ((!mad_agent->rmpp_version &&
-	     (rmpp_active || buf_size > sizeof(struct ib_mad))) ||
-	    (!rmpp_active && buf_size > sizeof(struct ib_mad)))
+	     (rmpp_active || message_size > sizeof(struct ib_mad))) ||
+	    (!rmpp_active && message_size > sizeof(struct ib_mad)))
 		return ERR_PTR(-EINVAL);
 
-	buf = kzalloc(sizeof *mad_send_wr + buf_size, gfp_mask);
+	size = rmpp_active ? hdr_len : sizeof(struct ib_mad);
+	buf = kzalloc(sizeof *mad_send_wr + size, gfp_mask);
 	if (!buf)
 		return ERR_PTR(-ENOMEM);
 
-	mad_send_wr = buf + buf_size;
+	mad_send_wr = buf + size;
+	INIT_LIST_HEAD(&mad_send_wr->rmpp_list);
 	mad_send_wr->send_buf.mad = buf;
+	mad_send_wr->send_buf.hdr_len = hdr_len;
+	mad_send_wr->send_buf.data_len = data_len;
+	mad_send_wr->pad = pad;
 
 	mad_send_wr->mad_agent_priv = mad_agent_priv;
-	mad_send_wr->sg_list[0].length = buf_size;
+	mad_send_wr->sg_list[0].length = hdr_len;
 	mad_send_wr->sg_list[0].lkey = mad_agent->mr->lkey;
+	mad_send_wr->sg_list[1].length = sizeof(struct ib_mad) - hdr_len;
+	mad_send_wr->sg_list[1].lkey = mad_agent->mr->lkey;
 
 	mad_send_wr->send_wr.wr_id = (unsigned long) mad_send_wr;
 	mad_send_wr->send_wr.sg_list = mad_send_wr->sg_list;
-	mad_send_wr->send_wr.num_sge = 1;
+	mad_send_wr->send_wr.num_sge = 2;
 	mad_send_wr->send_wr.opcode = IB_WR_SEND;
 	mad_send_wr->send_wr.send_flags = IB_SEND_SIGNALED;
 	mad_send_wr->send_wr.wr.ud.remote_qpn = remote_qpn;
@@ -820,13 +877,11 @@
 	mad_send_wr->send_wr.wr.ud.pkey_index = pkey_index;
 
 	if (rmpp_active) {
-		struct ib_rmpp_mad *rmpp_mad = mad_send_wr->send_buf.mad;
-		rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(hdr_len -
-						   IB_MGMT_RMPP_HDR + data_len);
-		rmpp_mad->rmpp_hdr.rmpp_version = mad_agent->rmpp_version;
-		rmpp_mad->rmpp_hdr.rmpp_type = IB_MGMT_RMPP_TYPE_DATA;
-		ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr,
-				  IB_MGMT_RMPP_FLAG_ACTIVE);
+		ret = alloc_send_rmpp_list(mad_send_wr, gfp_mask);
+		if (ret) {
+			kfree(buf);
+			return ERR_PTR(ret);
+		}
 	}
 
 	mad_send_wr->send_buf.mad_agent = mad_agent;
@@ -835,14 +890,50 @@
 }
 EXPORT_SYMBOL(ib_create_send_mad);
 
+void *ib_get_rmpp_segment(struct ib_mad_send_buf *send_buf, int seg_num)
+{
+	struct ib_mad_send_wr_private *mad_send_wr;
+	struct list_head *list;
+
+	mad_send_wr = container_of(send_buf, struct ib_mad_send_wr_private,
+				   send_buf);
+	list = &mad_send_wr->cur_seg->list;
+
+	if (mad_send_wr->cur_seg->num < seg_num) {
+		list_for_each_entry(mad_send_wr->cur_seg, list, list)
+			if (mad_send_wr->cur_seg->num == seg_num)
+				break;
+	} else if (mad_send_wr->cur_seg->num > seg_num) {
+		list_for_each_entry_reverse(mad_send_wr->cur_seg, list, list)
+			if (mad_send_wr->cur_seg->num == seg_num)
+				break;
+	}
+	return mad_send_wr->cur_seg->data;
+}
+EXPORT_SYMBOL(ib_get_rmpp_segment);
+
+static inline void *ib_get_payload(struct ib_mad_send_wr_private *mad_send_wr)
+{
+	if (mad_send_wr->send_buf.seg_count)
+		return ib_get_rmpp_segment(&mad_send_wr->send_buf,
+					   mad_send_wr->seg_num);
+	else
+		return mad_send_wr->send_buf.mad +
+		       mad_send_wr->send_buf.hdr_len;
+}
+
 void ib_free_send_mad(struct ib_mad_send_buf *send_buf)
 {
 	struct ib_mad_agent_private *mad_agent_priv;
+	struct ib_mad_send_wr_private *mad_send_wr;
 
 	mad_agent_priv = container_of(send_buf->mad_agent,
 				      struct ib_mad_agent_private, agent);
-	kfree(send_buf->mad);
+	mad_send_wr = container_of(send_buf, struct ib_mad_send_wr_private,
+				   send_buf);
 
+	free_send_rmpp_list(mad_send_wr);
+	kfree(send_buf->mad);
 	if (atomic_dec_and_test(&mad_agent_priv->refcount))
 		wake_up(&mad_agent_priv->wait);
 }
@@ -865,10 +956,17 @@
 
 	mad_agent = mad_send_wr->send_buf.mad_agent;
 	sge = mad_send_wr->sg_list;
-	sge->addr = dma_map_single(mad_agent->device->dma_device,
-				   mad_send_wr->send_buf.mad, sge->length,
-				   DMA_TO_DEVICE);
-	pci_unmap_addr_set(mad_send_wr, mapping, sge->addr);
+	sge[0].addr = dma_map_single(mad_agent->device->dma_device,
+				     mad_send_wr->send_buf.mad,
+				     sge[0].length,
+				     DMA_TO_DEVICE);
+	pci_unmap_addr_set(mad_send_wr, header_mapping, sge[0].addr);
+
+	sge[1].addr = dma_map_single(mad_agent->device->dma_device,
+				     ib_get_payload(mad_send_wr),
+				     sge[1].length,
+				     DMA_TO_DEVICE);
+	pci_unmap_addr_set(mad_send_wr, payload_mapping, sge[1].addr);
 
 	spin_lock_irqsave(&qp_info->send_queue.lock, flags);
 	if (qp_info->send_queue.count < qp_info->send_queue.max_active) {
@@ -885,11 +983,14 @@
 		list_add_tail(&mad_send_wr->mad_list.list, list);
 	}
 	spin_unlock_irqrestore(&qp_info->send_queue.lock, flags);
-	if (ret)
+	if (ret) {
 		dma_unmap_single(mad_agent->device->dma_device,
-				 pci_unmap_addr(mad_send_wr, mapping),
-				 sge->length, DMA_TO_DEVICE);
-
+				 pci_unmap_addr(mad_send_wr, header_mapping),
+				 sge[0].length, DMA_TO_DEVICE);
+		dma_unmap_single(mad_agent->device->dma_device,
+				 pci_unmap_addr(mad_send_wr, payload_mapping),
+				 sge[1].length, DMA_TO_DEVICE);
+	}
 	return ret;
 }
 
@@ -1661,9 +1762,7 @@
 					    port_priv->device->node_type,
 					    port_priv->port_num))
 			goto out;
-		if (!smi_check_local_dr_smp(&recv->mad.smp,
-					    port_priv->device,
-					    port_priv->port_num))
+		if (!smi_check_local_smp(&recv->mad.smp, port_priv->device))
 			goto out;
 	}
 
@@ -1862,8 +1961,11 @@
 
 retry:
 	dma_unmap_single(mad_send_wr->send_buf.mad_agent->device->dma_device,
-			 pci_unmap_addr(mad_send_wr, mapping),
+			 pci_unmap_addr(mad_send_wr, header_mapping),
 			 mad_send_wr->sg_list[0].length, DMA_TO_DEVICE);
+	dma_unmap_single(mad_send_wr->send_buf.mad_agent->device->dma_device,
+			 pci_unmap_addr(mad_send_wr, payload_mapping),
+			 mad_send_wr->sg_list[1].length, DMA_TO_DEVICE);
 	queued_send_wr = NULL;
 	spin_lock_irqsave(&send_queue->lock, flags);
 	list_del(&mad_list->list);
@@ -2262,8 +2364,12 @@
 static void ib_mad_thread_completion_handler(struct ib_cq *cq, void *arg)
 {
 	struct ib_mad_port_private *port_priv = cq->cq_context;
+	unsigned long flags;
 
-	queue_work(port_priv->wq, &port_priv->work);
+	spin_lock_irqsave(&ib_mad_port_list_lock, flags);
+	if (!list_empty(&port_priv->port_list))
+		queue_work(port_priv->wq, &port_priv->work);
+	spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
 }
 
 /*
@@ -2575,18 +2681,23 @@
 	}
 	INIT_WORK(&port_priv->work, ib_mad_completion_handler, port_priv);
 
+	spin_lock_irqsave(&ib_mad_port_list_lock, flags);
+	list_add_tail(&port_priv->port_list, &ib_mad_port_list);
+	spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
+
 	ret = ib_mad_port_start(port_priv);
 	if (ret) {
 		printk(KERN_ERR PFX "Couldn't start port\n");
 		goto error9;
 	}
 
-	spin_lock_irqsave(&ib_mad_port_list_lock, flags);
-	list_add_tail(&port_priv->port_list, &ib_mad_port_list);
-	spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
 	return 0;
 
 error9:
+	spin_lock_irqsave(&ib_mad_port_list_lock, flags);
+	list_del_init(&port_priv->port_list);
+	spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
+
 	destroy_workqueue(port_priv->wq);
 error8:
 	destroy_mad_qp(&port_priv->qp_info[1]);
@@ -2623,11 +2734,9 @@
 		printk(KERN_ERR PFX "Port %d not found\n", port_num);
 		return -ENODEV;
 	}
-	list_del(&port_priv->port_list);
+	list_del_init(&port_priv->port_list);
 	spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
 
-	/* Stop processing completions. */
-	flush_workqueue(port_priv->wq);
 	destroy_workqueue(port_priv->wq);
 	destroy_mad_qp(&port_priv->qp_info[1]);
 	destroy_mad_qp(&port_priv->qp_info[0]);
diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h
index 570f786..a7125d4 100644
--- a/drivers/infiniband/core/mad_priv.h
+++ b/drivers/infiniband/core/mad_priv.h
@@ -31,7 +31,7 @@
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  *
- * $Id: mad_priv.h 2730 2005-06-28 16:43:03Z sean.hefty $
+ * $Id: mad_priv.h 5596 2006-03-03 01:00:07Z sean.hefty $
  */
 
 #ifndef __IB_MAD_PRIV_H__
@@ -85,6 +85,12 @@
 	} mad;
 } __attribute__ ((packed));
 
+struct ib_rmpp_segment {
+	struct list_head list;
+	u32 num;
+	u8 data[0];
+};
+
 struct ib_mad_agent_private {
 	struct list_head agent_list;
 	struct ib_mad_agent agent;
@@ -119,7 +125,8 @@
 	struct list_head agent_list;
 	struct ib_mad_agent_private *mad_agent_priv;
 	struct ib_mad_send_buf send_buf;
-	DECLARE_PCI_UNMAP_ADDR(mapping)
+	DECLARE_PCI_UNMAP_ADDR(header_mapping)
+	DECLARE_PCI_UNMAP_ADDR(payload_mapping)
 	struct ib_send_wr send_wr;
 	struct ib_sge sg_list[IB_MAD_SEND_REQ_MAX_SG];
 	__be64 tid;
@@ -130,11 +137,12 @@
 	enum ib_wc_status status;
 
 	/* RMPP control */
+	struct list_head rmpp_list;
+	struct ib_rmpp_segment *last_ack_seg;
+	struct ib_rmpp_segment *cur_seg;
 	int last_ack;
 	int seg_num;
 	int newwin;
-	int total_seg;
-	int data_offset;
 	int pad;
 };
 
diff --git a/drivers/infiniband/core/mad_rmpp.c b/drivers/infiniband/core/mad_rmpp.c
index 3249e1d..bacfdd5 100644
--- a/drivers/infiniband/core/mad_rmpp.c
+++ b/drivers/infiniband/core/mad_rmpp.c
@@ -111,14 +111,14 @@
 		return IB_MGMT_RMPP_HDR;
 }
 
-static void format_ack(struct ib_rmpp_mad *ack,
+static void format_ack(struct ib_mad_send_buf *msg,
 		       struct ib_rmpp_mad *data,
 		       struct mad_rmpp_recv *rmpp_recv)
 {
+	struct ib_rmpp_mad *ack = msg->mad;
 	unsigned long flags;
 
-	memcpy(&ack->mad_hdr, &data->mad_hdr,
-	       data_offset(data->mad_hdr.mgmt_class));
+	memcpy(ack, &data->mad_hdr, msg->hdr_len);
 
 	ack->mad_hdr.method ^= IB_MGMT_METHOD_RESP;
 	ack->rmpp_hdr.rmpp_type = IB_MGMT_RMPP_TYPE_ACK;
@@ -135,16 +135,16 @@
 		     struct ib_mad_recv_wc *recv_wc)
 {
 	struct ib_mad_send_buf *msg;
-	int ret;
+	int ret, hdr_len;
 
+	hdr_len = data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class);
 	msg = ib_create_send_mad(&rmpp_recv->agent->agent, recv_wc->wc->src_qp,
-				 recv_wc->wc->pkey_index, 1, IB_MGMT_RMPP_HDR,
-				 IB_MGMT_RMPP_DATA, GFP_KERNEL);
+				 recv_wc->wc->pkey_index, 1, hdr_len,
+				 0, GFP_KERNEL);
 	if (!msg)
 		return;
 
-	format_ack(msg->mad, (struct ib_rmpp_mad *) recv_wc->recv_buf.mad,
-		   rmpp_recv);
+	format_ack(msg, (struct ib_rmpp_mad *) recv_wc->recv_buf.mad, rmpp_recv);
 	msg->ah = rmpp_recv->ah;
 	ret = ib_post_send_mad(msg, NULL);
 	if (ret)
@@ -156,16 +156,17 @@
 {
 	struct ib_mad_send_buf *msg;
 	struct ib_ah *ah;
+	int hdr_len;
 
 	ah = ib_create_ah_from_wc(agent->qp->pd, recv_wc->wc,
 				  recv_wc->recv_buf.grh, agent->port_num);
 	if (IS_ERR(ah))
 		return (void *) ah;
 
+	hdr_len = data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class);
 	msg = ib_create_send_mad(agent, recv_wc->wc->src_qp,
 				 recv_wc->wc->pkey_index, 1,
-				 IB_MGMT_RMPP_HDR, IB_MGMT_RMPP_DATA,
-				 GFP_KERNEL);
+				 hdr_len, 0, GFP_KERNEL);
 	if (IS_ERR(msg))
 		ib_destroy_ah(ah);
 	else
@@ -195,8 +196,7 @@
 		return;
 
 	rmpp_mad = msg->mad;
-	memcpy(rmpp_mad, recv_wc->recv_buf.mad,
-	       data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class));
+	memcpy(rmpp_mad, recv_wc->recv_buf.mad, msg->hdr_len);
 
 	rmpp_mad->mad_hdr.method ^= IB_MGMT_METHOD_RESP;
 	rmpp_mad->rmpp_hdr.rmpp_version = IB_MGMT_RMPP_VERSION;
@@ -433,44 +433,6 @@
 	return rmpp_wc;
 }
 
-void ib_coalesce_recv_mad(struct ib_mad_recv_wc *mad_recv_wc, void *buf)
-{
-	struct ib_mad_recv_buf *seg_buf;
-	struct ib_rmpp_mad *rmpp_mad;
-	void *data;
-	int size, len, offset;
-	u8 flags;
-
-	len = mad_recv_wc->mad_len;
-	if (len <= sizeof(struct ib_mad)) {
-		memcpy(buf, mad_recv_wc->recv_buf.mad, len);
-		return;
-	}
-
-	offset = data_offset(mad_recv_wc->recv_buf.mad->mad_hdr.mgmt_class);
-
-	list_for_each_entry(seg_buf, &mad_recv_wc->rmpp_list, list) {
-		rmpp_mad = (struct ib_rmpp_mad *)seg_buf->mad;
-		flags = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr);
-
-		if (flags & IB_MGMT_RMPP_FLAG_FIRST) {
-			data = rmpp_mad;
-			size = sizeof(*rmpp_mad);
-		} else {
-			data = (void *) rmpp_mad + offset;
-			if (flags & IB_MGMT_RMPP_FLAG_LAST)
-				size = len;
-			else
-				size = sizeof(*rmpp_mad) - offset;
-		}
-
-		memcpy(buf, data, size);
-		len -= size;
-		buf += size;
-	}
-}
-EXPORT_SYMBOL(ib_coalesce_recv_mad);
-
 static struct ib_mad_recv_wc *
 continue_rmpp(struct ib_mad_agent_private *agent,
 	      struct ib_mad_recv_wc *mad_recv_wc)
@@ -570,50 +532,33 @@
 	return mad_recv_wc;
 }
 
-static inline u64 get_seg_addr(struct ib_mad_send_wr_private *mad_send_wr)
-{
-	return mad_send_wr->sg_list[0].addr + mad_send_wr->data_offset +
-	       (sizeof(struct ib_rmpp_mad) - mad_send_wr->data_offset) *
-	       (mad_send_wr->seg_num - 1);
-}
-
 static int send_next_seg(struct ib_mad_send_wr_private *mad_send_wr)
 {
 	struct ib_rmpp_mad *rmpp_mad;
 	int timeout;
-	u32 paylen;
+	u32 paylen = 0;
 
 	rmpp_mad = mad_send_wr->send_buf.mad;
 	ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE);
-	rmpp_mad->rmpp_hdr.seg_num = cpu_to_be32(mad_send_wr->seg_num);
+	rmpp_mad->rmpp_hdr.seg_num = cpu_to_be32(++mad_send_wr->seg_num);
 
 	if (mad_send_wr->seg_num == 1) {
 		rmpp_mad->rmpp_hdr.rmpp_rtime_flags |= IB_MGMT_RMPP_FLAG_FIRST;
-		paylen = mad_send_wr->total_seg * IB_MGMT_RMPP_DATA -
+		paylen = mad_send_wr->send_buf.seg_count * IB_MGMT_RMPP_DATA -
 			 mad_send_wr->pad;
-		rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(paylen);
-		mad_send_wr->sg_list[0].length = sizeof(struct ib_rmpp_mad);
-	} else {
-		mad_send_wr->send_wr.num_sge = 2;
-		mad_send_wr->sg_list[0].length = mad_send_wr->data_offset;
-		mad_send_wr->sg_list[1].addr = get_seg_addr(mad_send_wr);
-		mad_send_wr->sg_list[1].length = sizeof(struct ib_rmpp_mad) -
-						 mad_send_wr->data_offset;
-		mad_send_wr->sg_list[1].lkey = mad_send_wr->sg_list[0].lkey;
-		rmpp_mad->rmpp_hdr.paylen_newwin = 0;
 	}
 
-	if (mad_send_wr->seg_num == mad_send_wr->total_seg) {
+	if (mad_send_wr->seg_num == mad_send_wr->send_buf.seg_count) {
 		rmpp_mad->rmpp_hdr.rmpp_rtime_flags |= IB_MGMT_RMPP_FLAG_LAST;
 		paylen = IB_MGMT_RMPP_DATA - mad_send_wr->pad;
-		rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(paylen);
 	}
+	rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(paylen);
 
 	/* 2 seconds for an ACK until we can find the packet lifetime */
 	timeout = mad_send_wr->send_buf.timeout_ms;
 	if (!timeout || timeout > 2000)
 		mad_send_wr->timeout = msecs_to_jiffies(2000);
-	mad_send_wr->seg_num++;
+
 	return ib_send_mad(mad_send_wr);
 }
 
@@ -629,7 +574,7 @@
 	if (!mad_send_wr)
 		goto out;	/* Unmatched send */
 
-	if ((mad_send_wr->last_ack == mad_send_wr->total_seg) ||
+	if ((mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) ||
 	    (!mad_send_wr->timeout) || (mad_send_wr->status != IB_WC_SUCCESS))
 		goto out;	/* Send is already done */
 
@@ -645,6 +590,18 @@
 	spin_unlock_irqrestore(&agent->lock, flags);
 }
 
+static inline void adjust_last_ack(struct ib_mad_send_wr_private *wr,
+				   int seg_num)
+{
+	struct list_head *list;
+
+	wr->last_ack = seg_num;
+	list = &wr->last_ack_seg->list;
+	list_for_each_entry(wr->last_ack_seg, list, list)
+		if (wr->last_ack_seg->num == seg_num)
+			break;
+}
+
 static void process_rmpp_ack(struct ib_mad_agent_private *agent,
 			     struct ib_mad_recv_wc *mad_recv_wc)
 {
@@ -675,11 +632,12 @@
 	if (!mad_send_wr)
 		goto out;	/* Unmatched ACK */
 
-	if ((mad_send_wr->last_ack == mad_send_wr->total_seg) ||
+	if ((mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) ||
 	    (!mad_send_wr->timeout) || (mad_send_wr->status != IB_WC_SUCCESS))
 		goto out;	/* Send is already done */
 
-	if (seg_num > mad_send_wr->total_seg || seg_num > mad_send_wr->newwin) {
+	if (seg_num > mad_send_wr->send_buf.seg_count ||
+	    seg_num > mad_send_wr->newwin) {
 		spin_unlock_irqrestore(&agent->lock, flags);
 		abort_send(agent, rmpp_mad->mad_hdr.tid,
 			   IB_MGMT_RMPP_STATUS_S2B);
@@ -691,11 +649,11 @@
 		goto out;	/* Old ACK */
 
 	if (seg_num > mad_send_wr->last_ack) {
-		mad_send_wr->last_ack = seg_num;
+		adjust_last_ack(mad_send_wr, seg_num);
 		mad_send_wr->retries = mad_send_wr->send_buf.retries;
 	}
 	mad_send_wr->newwin = newwin;
-	if (mad_send_wr->last_ack == mad_send_wr->total_seg) {
+	if (mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) {
 		/* If no response is expected, the ACK completes the send */
 		if (!mad_send_wr->send_buf.timeout_ms) {
 			struct ib_mad_send_wc wc;
@@ -714,7 +672,7 @@
 					     mad_send_wr->send_buf.timeout_ms);
 	} else if (mad_send_wr->refcount == 1 &&
 		   mad_send_wr->seg_num < mad_send_wr->newwin &&
-		   mad_send_wr->seg_num <= mad_send_wr->total_seg) {
+		   mad_send_wr->seg_num < mad_send_wr->send_buf.seg_count) {
 		/* Send failure will just result in a timeout/retry */
 		ret = send_next_seg(mad_send_wr);
 		if (ret)
@@ -838,31 +796,19 @@
 int ib_send_rmpp_mad(struct ib_mad_send_wr_private *mad_send_wr)
 {
 	struct ib_rmpp_mad *rmpp_mad;
-	int i, total_len, ret;
+	int ret;
 
 	rmpp_mad = mad_send_wr->send_buf.mad;
 	if (!(ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
 	      IB_MGMT_RMPP_FLAG_ACTIVE))
 		return IB_RMPP_RESULT_UNHANDLED;
 
-	if (rmpp_mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_DATA)
+	if (rmpp_mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_DATA) {
+		mad_send_wr->seg_num = 1;
 		return IB_RMPP_RESULT_INTERNAL;
+	}
 
-	if (mad_send_wr->send_wr.num_sge > 1)
-		return -EINVAL;		/* TODO: support num_sge > 1 */
-
-	mad_send_wr->seg_num = 1;
 	mad_send_wr->newwin = 1;
-	mad_send_wr->data_offset = data_offset(rmpp_mad->mad_hdr.mgmt_class);
-
-	total_len = 0;
-	for (i = 0; i < mad_send_wr->send_wr.num_sge; i++)
-		total_len += mad_send_wr->send_wr.sg_list[i].length;
-
-        mad_send_wr->total_seg = (total_len - mad_send_wr->data_offset) /
-			(sizeof(struct ib_rmpp_mad) - mad_send_wr->data_offset);
-	mad_send_wr->pad = total_len - IB_MGMT_RMPP_HDR -
-			   be32_to_cpu(rmpp_mad->rmpp_hdr.paylen_newwin);
 
 	/* We need to wait for the final ACK even if there isn't a response */
 	mad_send_wr->refcount += (mad_send_wr->timeout == 0);
@@ -893,14 +839,14 @@
 	if (!mad_send_wr->timeout)
 		return IB_RMPP_RESULT_PROCESSED; /* Response received */
 
-	if (mad_send_wr->last_ack == mad_send_wr->total_seg) {
+	if (mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) {
 		mad_send_wr->timeout =
 			msecs_to_jiffies(mad_send_wr->send_buf.timeout_ms);
 		return IB_RMPP_RESULT_PROCESSED; /* Send done */
 	}
 
-	if (mad_send_wr->seg_num > mad_send_wr->newwin ||
-	    mad_send_wr->seg_num > mad_send_wr->total_seg)
+	if (mad_send_wr->seg_num == mad_send_wr->newwin ||
+	    mad_send_wr->seg_num == mad_send_wr->send_buf.seg_count)
 		return IB_RMPP_RESULT_PROCESSED; /* Wait for ACK */
 
 	ret = send_next_seg(mad_send_wr);
@@ -921,10 +867,12 @@
 	      IB_MGMT_RMPP_FLAG_ACTIVE))
 		return IB_RMPP_RESULT_UNHANDLED; /* RMPP not active */
 
-	if (mad_send_wr->last_ack == mad_send_wr->total_seg)
+	if (mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count)
 		return IB_RMPP_RESULT_PROCESSED;
 
-	mad_send_wr->seg_num = mad_send_wr->last_ack + 1;
+	mad_send_wr->seg_num = mad_send_wr->last_ack;
+	mad_send_wr->cur_seg = mad_send_wr->last_ack_seg;
+
 	ret = send_next_seg(mad_send_wr);
 	if (ret)
 		return IB_RMPP_RESULT_PROCESSED;
diff --git a/drivers/infiniband/core/smi.h b/drivers/infiniband/core/smi.h
index 2b3c401..3011bfd 100644
--- a/drivers/infiniband/core/smi.h
+++ b/drivers/infiniband/core/smi.h
@@ -49,19 +49,16 @@
 extern int smi_handle_dr_smp_send(struct ib_smp *smp,
 				  u8 node_type,
 				  int port_num);
-extern int smi_check_local_dr_smp(struct ib_smp *smp,
-				  struct ib_device *device,
-				  int port_num);
 
 /*
  * Return 1 if the SMP should be handled by the local SMA/SM via process_mad
  */
-static inline int smi_check_local_smp(struct ib_mad_agent *mad_agent,
-                         	      struct ib_smp *smp)
+static inline int smi_check_local_smp(struct ib_smp *smp,
+				      struct ib_device *device)
 {
 	/* C14-9:3 -- We're at the end of the DR segment of path */
 	/* C14-9:4 -- Hop Pointer = Hop Count + 1 -> give to SMA/SM */
-	return ((mad_agent->device->process_mad &&
+	return ((device->process_mad &&
 		!ib_get_smp_direction(smp) &&
 		(smp->hop_ptr == smp->hop_cnt + 1)));
 }
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
index 5982d68..15121cb 100644
--- a/drivers/infiniband/core/sysfs.c
+++ b/drivers/infiniband/core/sysfs.c
@@ -112,7 +112,7 @@
 		return ret;
 
 	return sprintf(buf, "%d: %s\n", attr.state,
-		       attr.state >= 0 && attr.state <= ARRAY_SIZE(state_name) ?
+		       attr.state >= 0 && attr.state < ARRAY_SIZE(state_name) ?
 		       state_name[attr.state] : "UNKNOWN");
 }
 
@@ -472,8 +472,10 @@
 			goto err;
 
 		if (snprintf(element->name, sizeof(element->name),
-			     "%d", i) >= sizeof(element->name))
+			     "%d", i) >= sizeof(element->name)) {
+			kfree(element);
 			goto err;
+		}
 
 		element->attr.attr.name  = element->name;
 		element->attr.attr.mode  = S_IRUGO;
@@ -628,14 +630,42 @@
 		       be16_to_cpu(((__be16 *) &dev->node_guid)[3]));
 }
 
+static ssize_t show_node_desc(struct class_device *cdev, char *buf)
+{
+	struct ib_device *dev = container_of(cdev, struct ib_device, class_dev);
+
+	return sprintf(buf, "%.64s\n", dev->node_desc);
+}
+
+static ssize_t set_node_desc(struct class_device *cdev, const char *buf,
+			      size_t count)
+{
+	struct ib_device *dev = container_of(cdev, struct ib_device, class_dev);
+	struct ib_device_modify desc = {};
+	int ret;
+
+	if (!dev->modify_device)
+		return -EIO;
+
+	memcpy(desc.node_desc, buf, min_t(int, count, 64));
+	ret = ib_modify_device(dev, IB_DEVICE_MODIFY_NODE_DESC, &desc);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
 static CLASS_DEVICE_ATTR(node_type, S_IRUGO, show_node_type, NULL);
 static CLASS_DEVICE_ATTR(sys_image_guid, S_IRUGO, show_sys_image_guid, NULL);
 static CLASS_DEVICE_ATTR(node_guid, S_IRUGO, show_node_guid, NULL);
+static CLASS_DEVICE_ATTR(node_desc, S_IRUGO | S_IWUSR, show_node_desc,
+			 set_node_desc);
 
 static struct class_device_attribute *ib_class_attributes[] = {
 	&class_device_attr_node_type,
 	&class_device_attr_sys_image_guid,
-	&class_device_attr_node_guid
+	&class_device_attr_node_guid,
+	&class_device_attr_node_desc
 };
 
 static struct class ib_class = {
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
index c908de8..fb6cd42 100644
--- a/drivers/infiniband/core/user_mad.c
+++ b/drivers/infiniband/core/user_mad.c
@@ -31,7 +31,7 @@
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  *
- * $Id: user_mad.c 4010 2005-11-09 23:11:56Z roland $
+ * $Id: user_mad.c 5596 2006-03-03 01:00:07Z sean.hefty $
  */
 
 #include <linux/module.h>
@@ -121,6 +121,7 @@
 
 struct ib_umad_packet {
 	struct ib_mad_send_buf *msg;
+	struct ib_mad_recv_wc  *recv_wc;
 	struct list_head   list;
 	int		   length;
 	struct ib_user_mad mad;
@@ -176,31 +177,32 @@
 	return ret;
 }
 
+static int data_offset(u8 mgmt_class)
+{
+	if (mgmt_class == IB_MGMT_CLASS_SUBN_ADM)
+		return IB_MGMT_SA_HDR;
+	else if ((mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) &&
+		 (mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END))
+		return IB_MGMT_VENDOR_HDR;
+	else
+		return IB_MGMT_RMPP_HDR;
+}
+
 static void send_handler(struct ib_mad_agent *agent,
 			 struct ib_mad_send_wc *send_wc)
 {
 	struct ib_umad_file *file = agent->context;
-	struct ib_umad_packet *timeout;
 	struct ib_umad_packet *packet = send_wc->send_buf->context[0];
 
 	ib_destroy_ah(packet->msg->ah);
 	ib_free_send_mad(packet->msg);
 
 	if (send_wc->status == IB_WC_RESP_TIMEOUT_ERR) {
-		timeout = kzalloc(sizeof *timeout + IB_MGMT_MAD_HDR, GFP_KERNEL);
-		if (!timeout)
-			goto out;
-
-		timeout->length 	= IB_MGMT_MAD_HDR;
-		timeout->mad.hdr.id 	= packet->mad.hdr.id;
-		timeout->mad.hdr.status = ETIMEDOUT;
-		memcpy(timeout->mad.data, packet->mad.data,
-		       sizeof (struct ib_mad_hdr));
-
-		if (queue_packet(file, agent, timeout))
-			kfree(timeout);
+		packet->length = IB_MGMT_MAD_HDR;
+		packet->mad.hdr.status = ETIMEDOUT;
+		if (!queue_packet(file, agent, packet))
+			return;
 	}
-out:
 	kfree(packet);
 }
 
@@ -209,22 +211,20 @@
 {
 	struct ib_umad_file *file = agent->context;
 	struct ib_umad_packet *packet;
-	int length;
 
 	if (mad_recv_wc->wc->status != IB_WC_SUCCESS)
-		goto out;
+		goto err1;
 
-	length = mad_recv_wc->mad_len;
-	packet = kzalloc(sizeof *packet + length, GFP_KERNEL);
+	packet = kzalloc(sizeof *packet, GFP_KERNEL);
 	if (!packet)
-		goto out;
+		goto err1;
 
-	packet->length = length;
-
-	ib_coalesce_recv_mad(mad_recv_wc, packet->mad.data);
+	packet->length = mad_recv_wc->mad_len;
+	packet->recv_wc = mad_recv_wc;
 
 	packet->mad.hdr.status    = 0;
-	packet->mad.hdr.length    = length + sizeof (struct ib_user_mad);
+	packet->mad.hdr.length    = sizeof (struct ib_user_mad) +
+				    mad_recv_wc->mad_len;
 	packet->mad.hdr.qpn 	  = cpu_to_be32(mad_recv_wc->wc->src_qp);
 	packet->mad.hdr.lid 	  = cpu_to_be16(mad_recv_wc->wc->slid);
 	packet->mad.hdr.sl  	  = mad_recv_wc->wc->sl;
@@ -240,12 +240,79 @@
 	}
 
 	if (queue_packet(file, agent, packet))
-		kfree(packet);
+		goto err2;
+	return;
 
-out:
+err2:
+	kfree(packet);
+err1:
 	ib_free_recv_mad(mad_recv_wc);
 }
 
+static ssize_t copy_recv_mad(char __user *buf, struct ib_umad_packet *packet,
+			     size_t count)
+{
+	struct ib_mad_recv_buf *recv_buf;
+	int left, seg_payload, offset, max_seg_payload;
+
+	/* We need enough room to copy the first (or only) MAD segment. */
+	recv_buf = &packet->recv_wc->recv_buf;
+	if ((packet->length <= sizeof (*recv_buf->mad) &&
+	     count < sizeof (packet->mad) + packet->length) ||
+	    (packet->length > sizeof (*recv_buf->mad) &&
+	     count < sizeof (packet->mad) + sizeof (*recv_buf->mad)))
+		return -EINVAL;
+
+	if (copy_to_user(buf, &packet->mad, sizeof (packet->mad)))
+		return -EFAULT;
+
+	buf += sizeof (packet->mad);
+	seg_payload = min_t(int, packet->length, sizeof (*recv_buf->mad));
+	if (copy_to_user(buf, recv_buf->mad, seg_payload))
+		return -EFAULT;
+
+	if (seg_payload < packet->length) {
+		/*
+		 * Multipacket RMPP MAD message. Copy remainder of message.
+		 * Note that last segment may have a shorter payload.
+		 */
+		if (count < sizeof (packet->mad) + packet->length) {
+			/*
+			 * The buffer is too small, return the first RMPP segment,
+			 * which includes the RMPP message length.
+			 */
+			return -ENOSPC;
+		}
+		offset = data_offset(recv_buf->mad->mad_hdr.mgmt_class);
+		max_seg_payload = sizeof (struct ib_mad) - offset;
+
+		for (left = packet->length - seg_payload, buf += seg_payload;
+		     left; left -= seg_payload, buf += seg_payload) {
+			recv_buf = container_of(recv_buf->list.next,
+						struct ib_mad_recv_buf, list);
+			seg_payload = min(left, max_seg_payload);
+			if (copy_to_user(buf, ((void *) recv_buf->mad) + offset,
+					 seg_payload))
+				return -EFAULT;
+		}
+	}
+	return sizeof (packet->mad) + packet->length;
+}
+
+static ssize_t copy_send_mad(char __user *buf, struct ib_umad_packet *packet,
+			     size_t count)
+{
+	ssize_t size = sizeof (packet->mad) + packet->length;
+
+	if (count < size)
+		return -EINVAL;
+
+	if (copy_to_user(buf, &packet->mad, size))
+		return -EFAULT;
+
+	return size;
+}
+
 static ssize_t ib_umad_read(struct file *filp, char __user *buf,
 			    size_t count, loff_t *pos)
 {
@@ -253,7 +320,7 @@
 	struct ib_umad_packet *packet;
 	ssize_t ret;
 
-	if (count < sizeof (struct ib_user_mad) + sizeof (struct ib_mad))
+	if (count < sizeof (struct ib_user_mad))
 		return -EINVAL;
 
 	spin_lock_irq(&file->recv_lock);
@@ -276,28 +343,44 @@
 
 	spin_unlock_irq(&file->recv_lock);
 
-	if (count < packet->length + sizeof (struct ib_user_mad)) {
-		/* Return length needed (and first RMPP segment) if too small */
-		if (copy_to_user(buf, &packet->mad,
-				 sizeof (struct ib_user_mad) + sizeof (struct ib_mad)))
-			ret = -EFAULT;
-		else
-			ret = -ENOSPC;
-	} else if (copy_to_user(buf, &packet->mad,
-				packet->length + sizeof (struct ib_user_mad)))
-		ret = -EFAULT;
+	if (packet->recv_wc)
+		ret = copy_recv_mad(buf, packet, count);
 	else
-		ret = packet->length + sizeof (struct ib_user_mad);
+		ret = copy_send_mad(buf, packet, count);
+
 	if (ret < 0) {
 		/* Requeue packet */
 		spin_lock_irq(&file->recv_lock);
 		list_add(&packet->list, &file->recv_list);
 		spin_unlock_irq(&file->recv_lock);
-	} else
+	} else {
+		if (packet->recv_wc)
+			ib_free_recv_mad(packet->recv_wc);
 		kfree(packet);
+	}
 	return ret;
 }
 
+static int copy_rmpp_mad(struct ib_mad_send_buf *msg, const char __user *buf)
+{
+	int left, seg;
+
+	/* Copy class specific header */
+	if ((msg->hdr_len > IB_MGMT_RMPP_HDR) &&
+	    copy_from_user(msg->mad + IB_MGMT_RMPP_HDR, buf + IB_MGMT_RMPP_HDR,
+			   msg->hdr_len - IB_MGMT_RMPP_HDR))
+		return -EFAULT;
+
+	/* All headers are in place.  Copy data segments. */
+	for (seg = 1, left = msg->data_len, buf += msg->hdr_len; left > 0;
+	     seg++, left -= msg->seg_size, buf += msg->seg_size) {
+		if (copy_from_user(ib_get_rmpp_segment(msg, seg), buf,
+				   min(left, msg->seg_size)))
+			return -EFAULT;
+	}
+	return 0;
+}
+
 static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
 			     size_t count, loff_t *pos)
 {
@@ -309,14 +392,12 @@
 	struct ib_rmpp_mad *rmpp_mad;
 	u8 method;
 	__be64 *tid;
-	int ret, length, hdr_len, copy_offset;
-	int rmpp_active, has_rmpp_header;
+	int ret, data_len, hdr_len, copy_offset, rmpp_active;
 
 	if (count < sizeof (struct ib_user_mad) + IB_MGMT_RMPP_HDR)
 		return -EINVAL;
 
-	length = count - sizeof (struct ib_user_mad);
-	packet = kmalloc(sizeof *packet + IB_MGMT_RMPP_HDR, GFP_KERNEL);
+	packet = kzalloc(sizeof *packet + IB_MGMT_RMPP_HDR, GFP_KERNEL);
 	if (!packet)
 		return -ENOMEM;
 
@@ -363,35 +444,25 @@
 	if (rmpp_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_ADM) {
 		hdr_len = IB_MGMT_SA_HDR;
 		copy_offset = IB_MGMT_RMPP_HDR;
-		has_rmpp_header = 1;
+		rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
+			      IB_MGMT_RMPP_FLAG_ACTIVE;
 	} else if (rmpp_mad->mad_hdr.mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START &&
 		   rmpp_mad->mad_hdr.mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END) {
-			hdr_len = IB_MGMT_VENDOR_HDR;
-			copy_offset = IB_MGMT_RMPP_HDR;
-			has_rmpp_header = 1;
+		hdr_len = IB_MGMT_VENDOR_HDR;
+		copy_offset = IB_MGMT_RMPP_HDR;
+		rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
+			      IB_MGMT_RMPP_FLAG_ACTIVE;
 	} else {
 		hdr_len = IB_MGMT_MAD_HDR;
 		copy_offset = IB_MGMT_MAD_HDR;
-		has_rmpp_header = 0;
-	}
-
-	if (has_rmpp_header)
-		rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
-			      IB_MGMT_RMPP_FLAG_ACTIVE;
-	else
 		rmpp_active = 0;
-
-	/* Validate that the management class can support RMPP */
-	if (rmpp_active && !agent->rmpp_version) {
-		ret = -EINVAL;
-		goto err_ah;
 	}
 
+	data_len = count - sizeof (struct ib_user_mad) - hdr_len;
 	packet->msg = ib_create_send_mad(agent,
 					 be32_to_cpu(packet->mad.hdr.qpn),
-					 0, rmpp_active,
-					 hdr_len, length - hdr_len,
-					 GFP_KERNEL);
+					 0, rmpp_active, hdr_len,
+					 data_len, GFP_KERNEL);
 	if (IS_ERR(packet->msg)) {
 		ret = PTR_ERR(packet->msg);
 		goto err_ah;
@@ -402,14 +473,21 @@
 	packet->msg->retries 	= packet->mad.hdr.retries;
 	packet->msg->context[0] = packet;
 
-	/* Copy MAD headers (RMPP header in place) */
+	/* Copy MAD header.  Any RMPP header is already in place. */
 	memcpy(packet->msg->mad, packet->mad.data, IB_MGMT_MAD_HDR);
-	/* Now, copy rest of message from user into send buffer */
-	if (copy_from_user(packet->msg->mad + copy_offset,
-			   buf + sizeof (struct ib_user_mad) + copy_offset,
-			   length - copy_offset)) {
-		ret = -EFAULT;
-		goto err_msg;
+	buf += sizeof (struct ib_user_mad);
+
+	if (!rmpp_active) {
+		if (copy_from_user(packet->msg->mad + copy_offset,
+				   buf + copy_offset,
+				   hdr_len + data_len - copy_offset)) {
+			ret = -EFAULT;
+			goto err_msg;
+		}
+	} else {
+		ret = copy_rmpp_mad(packet->msg, buf);
+		if (ret)
+			goto err_msg;
 	}
 
 	/*
@@ -433,18 +511,14 @@
 		goto err_msg;
 
 	up_read(&file->port->mutex);
-
 	return count;
 
 err_msg:
 	ib_free_send_mad(packet->msg);
-
 err_ah:
 	ib_destroy_ah(ah);
-
 err_up:
 	up_read(&file->port->mutex);
-
 err:
 	kfree(packet);
 	return ret;
@@ -627,8 +701,11 @@
 	already_dead = file->agents_dead;
 	file->agents_dead = 1;
 
-	list_for_each_entry_safe(packet, tmp, &file->recv_list, list)
+	list_for_each_entry_safe(packet, tmp, &file->recv_list, list) {
+		if (packet->recv_wc)
+			ib_free_recv_mad(packet->recv_wc);
 		kfree(packet);
+	}
 
 	list_del(&file->port_list);
 
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
index f7eecbc..3372d67 100644
--- a/drivers/infiniband/core/uverbs.h
+++ b/drivers/infiniband/core/uverbs.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
  * Copyright (c) 2005 PathScale, Inc. All rights reserved.
@@ -178,10 +178,12 @@
 IB_UVERBS_DECLARE_CMD(dereg_mr);
 IB_UVERBS_DECLARE_CMD(create_comp_channel);
 IB_UVERBS_DECLARE_CMD(create_cq);
+IB_UVERBS_DECLARE_CMD(resize_cq);
 IB_UVERBS_DECLARE_CMD(poll_cq);
 IB_UVERBS_DECLARE_CMD(req_notify_cq);
 IB_UVERBS_DECLARE_CMD(destroy_cq);
 IB_UVERBS_DECLARE_CMD(create_qp);
+IB_UVERBS_DECLARE_CMD(query_qp);
 IB_UVERBS_DECLARE_CMD(modify_qp);
 IB_UVERBS_DECLARE_CMD(destroy_qp);
 IB_UVERBS_DECLARE_CMD(post_send);
@@ -193,6 +195,7 @@
 IB_UVERBS_DECLARE_CMD(detach_mcast);
 IB_UVERBS_DECLARE_CMD(create_srq);
 IB_UVERBS_DECLARE_CMD(modify_srq);
+IB_UVERBS_DECLARE_CMD(query_srq);
 IB_UVERBS_DECLARE_CMD(destroy_srq);
 
 #endif /* UVERBS_H */
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 407b628..9f69bd48 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -1,7 +1,8 @@
 /*
  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  * Copyright (c) 2005 PathScale, Inc.  All rights reserved.
+ * Copyright (c) 2006 Mellanox Technologies.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -675,6 +676,46 @@
 	return ret;
 }
 
+ssize_t ib_uverbs_resize_cq(struct ib_uverbs_file *file,
+			    const char __user *buf, int in_len,
+			    int out_len)
+{
+	struct ib_uverbs_resize_cq	cmd;
+	struct ib_uverbs_resize_cq_resp	resp;
+	struct ib_udata                 udata;
+	struct ib_cq			*cq;
+	int				ret = -EINVAL;
+
+	if (copy_from_user(&cmd, buf, sizeof cmd))
+		return -EFAULT;
+
+	INIT_UDATA(&udata, buf + sizeof cmd,
+		   (unsigned long) cmd.response + sizeof resp,
+		   in_len - sizeof cmd, out_len - sizeof resp);
+
+	mutex_lock(&ib_uverbs_idr_mutex);
+
+	cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle);
+	if (!cq || cq->uobject->context != file->ucontext || !cq->device->resize_cq)
+		goto out;
+
+	ret = cq->device->resize_cq(cq, cmd.cqe, &udata);
+	if (ret)
+		goto out;
+
+	memset(&resp, 0, sizeof resp);
+	resp.cqe = cq->cqe;
+
+	if (copy_to_user((void __user *) (unsigned long) cmd.response,
+			 &resp, sizeof resp))
+		ret = -EFAULT;
+
+out:
+	mutex_unlock(&ib_uverbs_idr_mutex);
+
+	return ret ? ret : in_len;
+}
+
 ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
 			  const char __user *buf, int in_len,
 			  int out_len)
@@ -956,6 +997,106 @@
 	return ret;
 }
 
+ssize_t ib_uverbs_query_qp(struct ib_uverbs_file *file,
+			   const char __user *buf, int in_len,
+			   int out_len)
+{
+	struct ib_uverbs_query_qp      cmd;
+	struct ib_uverbs_query_qp_resp resp;
+	struct ib_qp                   *qp;
+	struct ib_qp_attr              *attr;
+	struct ib_qp_init_attr         *init_attr;
+	int                            ret;
+
+	if (copy_from_user(&cmd, buf, sizeof cmd))
+		return -EFAULT;
+
+	attr      = kmalloc(sizeof *attr, GFP_KERNEL);
+	init_attr = kmalloc(sizeof *init_attr, GFP_KERNEL);
+	if (!attr || !init_attr) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	mutex_lock(&ib_uverbs_idr_mutex);
+
+	qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
+	if (qp && qp->uobject->context == file->ucontext)
+		ret = ib_query_qp(qp, attr, cmd.attr_mask, init_attr);
+	else
+		ret = -EINVAL;
+
+	mutex_unlock(&ib_uverbs_idr_mutex);
+
+	if (ret)
+		goto out;
+
+	memset(&resp, 0, sizeof resp);
+
+	resp.qp_state               = attr->qp_state;
+	resp.cur_qp_state           = attr->cur_qp_state;
+	resp.path_mtu               = attr->path_mtu;
+	resp.path_mig_state         = attr->path_mig_state;
+	resp.qkey                   = attr->qkey;
+	resp.rq_psn                 = attr->rq_psn;
+	resp.sq_psn                 = attr->sq_psn;
+	resp.dest_qp_num            = attr->dest_qp_num;
+	resp.qp_access_flags        = attr->qp_access_flags;
+	resp.pkey_index             = attr->pkey_index;
+	resp.alt_pkey_index         = attr->alt_pkey_index;
+	resp.en_sqd_async_notify    = attr->en_sqd_async_notify;
+	resp.max_rd_atomic          = attr->max_rd_atomic;
+	resp.max_dest_rd_atomic     = attr->max_dest_rd_atomic;
+	resp.min_rnr_timer          = attr->min_rnr_timer;
+	resp.port_num               = attr->port_num;
+	resp.timeout                = attr->timeout;
+	resp.retry_cnt              = attr->retry_cnt;
+	resp.rnr_retry              = attr->rnr_retry;
+	resp.alt_port_num           = attr->alt_port_num;
+	resp.alt_timeout            = attr->alt_timeout;
+
+	memcpy(resp.dest.dgid, attr->ah_attr.grh.dgid.raw, 16);
+	resp.dest.flow_label        = attr->ah_attr.grh.flow_label;
+	resp.dest.sgid_index        = attr->ah_attr.grh.sgid_index;
+	resp.dest.hop_limit         = attr->ah_attr.grh.hop_limit;
+	resp.dest.traffic_class     = attr->ah_attr.grh.traffic_class;
+	resp.dest.dlid              = attr->ah_attr.dlid;
+	resp.dest.sl                = attr->ah_attr.sl;
+	resp.dest.src_path_bits     = attr->ah_attr.src_path_bits;
+	resp.dest.static_rate       = attr->ah_attr.static_rate;
+	resp.dest.is_global         = !!(attr->ah_attr.ah_flags & IB_AH_GRH);
+	resp.dest.port_num          = attr->ah_attr.port_num;
+
+	memcpy(resp.alt_dest.dgid, attr->alt_ah_attr.grh.dgid.raw, 16);
+	resp.alt_dest.flow_label    = attr->alt_ah_attr.grh.flow_label;
+	resp.alt_dest.sgid_index    = attr->alt_ah_attr.grh.sgid_index;
+	resp.alt_dest.hop_limit     = attr->alt_ah_attr.grh.hop_limit;
+	resp.alt_dest.traffic_class = attr->alt_ah_attr.grh.traffic_class;
+	resp.alt_dest.dlid          = attr->alt_ah_attr.dlid;
+	resp.alt_dest.sl            = attr->alt_ah_attr.sl;
+	resp.alt_dest.src_path_bits = attr->alt_ah_attr.src_path_bits;
+	resp.alt_dest.static_rate   = attr->alt_ah_attr.static_rate;
+	resp.alt_dest.is_global     = !!(attr->alt_ah_attr.ah_flags & IB_AH_GRH);
+	resp.alt_dest.port_num      = attr->alt_ah_attr.port_num;
+
+	resp.max_send_wr            = init_attr->cap.max_send_wr;
+	resp.max_recv_wr            = init_attr->cap.max_recv_wr;
+	resp.max_send_sge           = init_attr->cap.max_send_sge;
+	resp.max_recv_sge           = init_attr->cap.max_recv_sge;
+	resp.max_inline_data        = init_attr->cap.max_inline_data;
+	resp.sq_sig_all             = init_attr->sq_sig_type == IB_SIGNAL_ALL_WR;
+
+	if (copy_to_user((void __user *) (unsigned long) cmd.response,
+			 &resp, sizeof resp))
+		ret = -EFAULT;
+
+out:
+	kfree(attr);
+	kfree(init_attr);
+
+	return ret ? ret : in_len;
+}
+
 ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
 			    const char __user *buf, int in_len,
 			    int out_len)
@@ -990,7 +1131,7 @@
 	attr->dest_qp_num 	  = cmd.dest_qp_num;
 	attr->qp_access_flags 	  = cmd.qp_access_flags;
 	attr->pkey_index 	  = cmd.pkey_index;
-	attr->alt_pkey_index 	  = cmd.pkey_index;
+	attr->alt_pkey_index 	  = cmd.alt_pkey_index;
 	attr->en_sqd_async_notify = cmd.en_sqd_async_notify;
 	attr->max_rd_atomic 	  = cmd.max_rd_atomic;
 	attr->max_dest_rd_atomic  = cmd.max_dest_rd_atomic;
@@ -1094,8 +1235,8 @@
 }
 
 ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
-                            const char __user *buf, int in_len,
-                            int out_len)
+			    const char __user *buf, int in_len,
+			    int out_len)
 {
 	struct ib_uverbs_post_send      cmd;
 	struct ib_uverbs_post_send_resp resp;
@@ -1323,8 +1464,8 @@
 }
 
 ssize_t ib_uverbs_post_recv(struct ib_uverbs_file *file,
-                            const char __user *buf, int in_len,
-                            int out_len)
+			    const char __user *buf, int in_len,
+			    int out_len)
 {
 	struct ib_uverbs_post_recv      cmd;
 	struct ib_uverbs_post_recv_resp resp;
@@ -1374,8 +1515,8 @@
 }
 
 ssize_t ib_uverbs_post_srq_recv(struct ib_uverbs_file *file,
-                            const char __user *buf, int in_len,
-                            int out_len)
+				const char __user *buf, int in_len,
+				int out_len)
 {
 	struct ib_uverbs_post_srq_recv      cmd;
 	struct ib_uverbs_post_srq_recv_resp resp;
@@ -1723,6 +1864,8 @@
 		goto err_destroy;
 
 	resp.srq_handle = uobj->uobject.id;
+	resp.max_wr     = attr.attr.max_wr;
+	resp.max_sge    = attr.attr.max_sge;
 
 	if (copy_to_user((void __user *) (unsigned long) cmd.response,
 			 &resp, sizeof resp)) {
@@ -1783,6 +1926,49 @@
 	return ret ? ret : in_len;
 }
 
+ssize_t ib_uverbs_query_srq(struct ib_uverbs_file *file,
+			    const char __user *buf,
+			    int in_len, int out_len)
+{
+	struct ib_uverbs_query_srq      cmd;
+	struct ib_uverbs_query_srq_resp resp;
+	struct ib_srq_attr              attr;
+	struct ib_srq                   *srq;
+	int                             ret;
+
+	if (out_len < sizeof resp)
+		return -ENOSPC;
+
+	if (copy_from_user(&cmd, buf, sizeof cmd))
+		return -EFAULT;
+
+	mutex_lock(&ib_uverbs_idr_mutex);
+
+	srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle);
+	if (srq && srq->uobject->context == file->ucontext)
+		ret = ib_query_srq(srq, &attr);
+	else
+		ret = -EINVAL;
+
+	mutex_unlock(&ib_uverbs_idr_mutex);
+
+	if (ret)
+		goto out;
+
+	memset(&resp, 0, sizeof resp);
+
+	resp.max_wr    = attr.max_wr;
+	resp.max_sge   = attr.max_sge;
+	resp.srq_limit = attr.srq_limit;
+
+	if (copy_to_user((void __user *) (unsigned long) cmd.response,
+			 &resp, sizeof resp))
+		ret = -EFAULT;
+
+out:
+	return ret ? ret : in_len;
+}
+
 ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file,
 			      const char __user *buf, int in_len,
 			      int out_len)
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index 903f85a..ff092a0 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
  * Copyright (c) 2005 PathScale, Inc. All rights reserved.
@@ -91,10 +91,12 @@
 	[IB_USER_VERBS_CMD_DEREG_MR]      	= ib_uverbs_dereg_mr,
 	[IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL] = ib_uverbs_create_comp_channel,
 	[IB_USER_VERBS_CMD_CREATE_CQ]     	= ib_uverbs_create_cq,
+	[IB_USER_VERBS_CMD_RESIZE_CQ]     	= ib_uverbs_resize_cq,
 	[IB_USER_VERBS_CMD_POLL_CQ]     	= ib_uverbs_poll_cq,
 	[IB_USER_VERBS_CMD_REQ_NOTIFY_CQ]     	= ib_uverbs_req_notify_cq,
 	[IB_USER_VERBS_CMD_DESTROY_CQ]    	= ib_uverbs_destroy_cq,
 	[IB_USER_VERBS_CMD_CREATE_QP]     	= ib_uverbs_create_qp,
+	[IB_USER_VERBS_CMD_QUERY_QP]     	= ib_uverbs_query_qp,
 	[IB_USER_VERBS_CMD_MODIFY_QP]     	= ib_uverbs_modify_qp,
 	[IB_USER_VERBS_CMD_DESTROY_QP]    	= ib_uverbs_destroy_qp,
 	[IB_USER_VERBS_CMD_POST_SEND]    	= ib_uverbs_post_send,
@@ -106,6 +108,7 @@
 	[IB_USER_VERBS_CMD_DETACH_MCAST]  	= ib_uverbs_detach_mcast,
 	[IB_USER_VERBS_CMD_CREATE_SRQ]    	= ib_uverbs_create_srq,
 	[IB_USER_VERBS_CMD_MODIFY_SRQ]    	= ib_uverbs_modify_srq,
+	[IB_USER_VERBS_CMD_QUERY_SRQ]     	= ib_uverbs_query_srq,
 	[IB_USER_VERBS_CMD_DESTROY_SRQ]   	= ib_uverbs_destroy_srq,
 };
 
@@ -461,7 +464,6 @@
 	ib_uverbs_async_handler(uobj->uverbs_file, uobj->uobject.user_handle,
 				event->event, &uobj->async_list,
 				&uobj->async_events_reported);
-				
 }
 
 void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr)
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
index c857361..cae0845 100644
--- a/drivers/infiniband/core/verbs.c
+++ b/drivers/infiniband/core/verbs.c
@@ -5,7 +5,7 @@
  * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
  * Copyright (c) 2004 Voltaire Corporation.  All rights reserved.
  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -245,6 +245,258 @@
 }
 EXPORT_SYMBOL(ib_create_qp);
 
+static const struct {
+	int			valid;
+	enum ib_qp_attr_mask	req_param[IB_QPT_RAW_ETY + 1];
+	enum ib_qp_attr_mask	opt_param[IB_QPT_RAW_ETY + 1];
+} qp_state_table[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = {
+	[IB_QPS_RESET] = {
+		[IB_QPS_RESET] = { .valid = 1 },
+		[IB_QPS_ERR]   = { .valid = 1 },
+		[IB_QPS_INIT]  = {
+			.valid = 1,
+			.req_param = {
+				[IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
+						IB_QP_PORT			|
+						IB_QP_QKEY),
+				[IB_QPT_UC]  = (IB_QP_PKEY_INDEX		|
+						IB_QP_PORT			|
+						IB_QP_ACCESS_FLAGS),
+				[IB_QPT_RC]  = (IB_QP_PKEY_INDEX		|
+						IB_QP_PORT			|
+						IB_QP_ACCESS_FLAGS),
+				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
+						IB_QP_QKEY),
+				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
+						IB_QP_QKEY),
+			}
+		},
+	},
+	[IB_QPS_INIT]  = {
+		[IB_QPS_RESET] = { .valid = 1 },
+		[IB_QPS_ERR] =   { .valid = 1 },
+		[IB_QPS_INIT]  = {
+			.valid = 1,
+			.opt_param = {
+				[IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
+						IB_QP_PORT			|
+						IB_QP_QKEY),
+				[IB_QPT_UC]  = (IB_QP_PKEY_INDEX		|
+						IB_QP_PORT			|
+						IB_QP_ACCESS_FLAGS),
+				[IB_QPT_RC]  = (IB_QP_PKEY_INDEX		|
+						IB_QP_PORT			|
+						IB_QP_ACCESS_FLAGS),
+				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
+						IB_QP_QKEY),
+				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
+						IB_QP_QKEY),
+			}
+		},
+		[IB_QPS_RTR]   = {
+			.valid = 1,
+			.req_param = {
+				[IB_QPT_UC]  = (IB_QP_AV			|
+						IB_QP_PATH_MTU			|
+						IB_QP_DEST_QPN			|
+						IB_QP_RQ_PSN),
+				[IB_QPT_RC]  = (IB_QP_AV			|
+						IB_QP_PATH_MTU			|
+						IB_QP_DEST_QPN			|
+						IB_QP_RQ_PSN			|
+						IB_QP_MAX_DEST_RD_ATOMIC	|
+						IB_QP_MIN_RNR_TIMER),
+			},
+			.opt_param = {
+				 [IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
+						 IB_QP_QKEY),
+				 [IB_QPT_UC]  = (IB_QP_ALT_PATH			|
+						 IB_QP_ACCESS_FLAGS		|
+						 IB_QP_PKEY_INDEX),
+				 [IB_QPT_RC]  = (IB_QP_ALT_PATH			|
+						 IB_QP_ACCESS_FLAGS		|
+						 IB_QP_PKEY_INDEX),
+				 [IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
+						 IB_QP_QKEY),
+				 [IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
+						 IB_QP_QKEY),
+			 }
+		}
+	},
+	[IB_QPS_RTR]   = {
+		[IB_QPS_RESET] = { .valid = 1 },
+		[IB_QPS_ERR] =   { .valid = 1 },
+		[IB_QPS_RTS]   = {
+			.valid = 1,
+			.req_param = {
+				[IB_QPT_UD]  = IB_QP_SQ_PSN,
+				[IB_QPT_UC]  = IB_QP_SQ_PSN,
+				[IB_QPT_RC]  = (IB_QP_TIMEOUT			|
+						IB_QP_RETRY_CNT			|
+						IB_QP_RNR_RETRY			|
+						IB_QP_SQ_PSN			|
+						IB_QP_MAX_QP_RD_ATOMIC),
+				[IB_QPT_SMI] = IB_QP_SQ_PSN,
+				[IB_QPT_GSI] = IB_QP_SQ_PSN,
+			},
+			.opt_param = {
+				 [IB_QPT_UD]  = (IB_QP_CUR_STATE		|
+						 IB_QP_QKEY),
+				 [IB_QPT_UC]  = (IB_QP_CUR_STATE		|
+						 IB_QP_ALT_PATH			|
+						 IB_QP_ACCESS_FLAGS		|
+						 IB_QP_PATH_MIG_STATE),
+				 [IB_QPT_RC]  = (IB_QP_CUR_STATE		|
+						 IB_QP_ALT_PATH			|
+						 IB_QP_ACCESS_FLAGS		|
+						 IB_QP_MIN_RNR_TIMER		|
+						 IB_QP_PATH_MIG_STATE),
+				 [IB_QPT_SMI] = (IB_QP_CUR_STATE		|
+						 IB_QP_QKEY),
+				 [IB_QPT_GSI] = (IB_QP_CUR_STATE		|
+						 IB_QP_QKEY),
+			 }
+		}
+	},
+	[IB_QPS_RTS]   = {
+		[IB_QPS_RESET] = { .valid = 1 },
+		[IB_QPS_ERR] =   { .valid = 1 },
+		[IB_QPS_RTS]   = {
+			.valid = 1,
+			.opt_param = {
+				[IB_QPT_UD]  = (IB_QP_CUR_STATE			|
+						IB_QP_QKEY),
+				[IB_QPT_UC]  = (IB_QP_CUR_STATE			|
+						IB_QP_ACCESS_FLAGS		|
+						IB_QP_ALT_PATH			|
+						IB_QP_PATH_MIG_STATE),
+				[IB_QPT_RC]  = (IB_QP_CUR_STATE			|
+						IB_QP_ACCESS_FLAGS		|
+						IB_QP_ALT_PATH			|
+						IB_QP_PATH_MIG_STATE		|
+						IB_QP_MIN_RNR_TIMER),
+				[IB_QPT_SMI] = (IB_QP_CUR_STATE			|
+						IB_QP_QKEY),
+				[IB_QPT_GSI] = (IB_QP_CUR_STATE			|
+						IB_QP_QKEY),
+			}
+		},
+		[IB_QPS_SQD]   = {
+			.valid = 1,
+			.opt_param = {
+				[IB_QPT_UD]  = IB_QP_EN_SQD_ASYNC_NOTIFY,
+				[IB_QPT_UC]  = IB_QP_EN_SQD_ASYNC_NOTIFY,
+				[IB_QPT_RC]  = IB_QP_EN_SQD_ASYNC_NOTIFY,
+				[IB_QPT_SMI] = IB_QP_EN_SQD_ASYNC_NOTIFY,
+				[IB_QPT_GSI] = IB_QP_EN_SQD_ASYNC_NOTIFY
+			}
+		},
+	},
+	[IB_QPS_SQD]   = {
+		[IB_QPS_RESET] = { .valid = 1 },
+		[IB_QPS_ERR] =   { .valid = 1 },
+		[IB_QPS_RTS]   = {
+			.valid = 1,
+			.opt_param = {
+				[IB_QPT_UD]  = (IB_QP_CUR_STATE			|
+						IB_QP_QKEY),
+				[IB_QPT_UC]  = (IB_QP_CUR_STATE			|
+						IB_QP_ALT_PATH			|
+						IB_QP_ACCESS_FLAGS		|
+						IB_QP_PATH_MIG_STATE),
+				[IB_QPT_RC]  = (IB_QP_CUR_STATE			|
+						IB_QP_ALT_PATH			|
+						IB_QP_ACCESS_FLAGS		|
+						IB_QP_MIN_RNR_TIMER		|
+						IB_QP_PATH_MIG_STATE),
+				[IB_QPT_SMI] = (IB_QP_CUR_STATE			|
+						IB_QP_QKEY),
+				[IB_QPT_GSI] = (IB_QP_CUR_STATE			|
+						IB_QP_QKEY),
+			}
+		},
+		[IB_QPS_SQD]   = {
+			.valid = 1,
+			.opt_param = {
+				[IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
+						IB_QP_QKEY),
+				[IB_QPT_UC]  = (IB_QP_AV			|
+						IB_QP_ALT_PATH			|
+						IB_QP_ACCESS_FLAGS		|
+						IB_QP_PKEY_INDEX		|
+						IB_QP_PATH_MIG_STATE),
+				[IB_QPT_RC]  = (IB_QP_PORT			|
+						IB_QP_AV			|
+						IB_QP_TIMEOUT			|
+						IB_QP_RETRY_CNT			|
+						IB_QP_RNR_RETRY			|
+						IB_QP_MAX_QP_RD_ATOMIC		|
+						IB_QP_MAX_DEST_RD_ATOMIC	|
+						IB_QP_ALT_PATH			|
+						IB_QP_ACCESS_FLAGS		|
+						IB_QP_PKEY_INDEX		|
+						IB_QP_MIN_RNR_TIMER		|
+						IB_QP_PATH_MIG_STATE),
+				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
+						IB_QP_QKEY),
+				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
+						IB_QP_QKEY),
+			}
+		}
+	},
+	[IB_QPS_SQE]   = {
+		[IB_QPS_RESET] = { .valid = 1 },
+		[IB_QPS_ERR] =   { .valid = 1 },
+		[IB_QPS_RTS]   = {
+			.valid = 1,
+			.opt_param = {
+				[IB_QPT_UD]  = (IB_QP_CUR_STATE			|
+						IB_QP_QKEY),
+				[IB_QPT_UC]  = (IB_QP_CUR_STATE			|
+						IB_QP_ACCESS_FLAGS),
+				[IB_QPT_SMI] = (IB_QP_CUR_STATE			|
+						IB_QP_QKEY),
+				[IB_QPT_GSI] = (IB_QP_CUR_STATE			|
+						IB_QP_QKEY),
+			}
+		}
+	},
+	[IB_QPS_ERR] = {
+		[IB_QPS_RESET] = { .valid = 1 },
+		[IB_QPS_ERR] =   { .valid = 1 }
+	}
+};
+
+int ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state,
+		       enum ib_qp_type type, enum ib_qp_attr_mask mask)
+{
+	enum ib_qp_attr_mask req_param, opt_param;
+
+	if (cur_state  < 0 || cur_state  > IB_QPS_ERR ||
+	    next_state < 0 || next_state > IB_QPS_ERR)
+		return 0;
+
+	if (mask & IB_QP_CUR_STATE  &&
+	    cur_state != IB_QPS_RTR && cur_state != IB_QPS_RTS &&
+	    cur_state != IB_QPS_SQD && cur_state != IB_QPS_SQE)
+		return 0;
+
+	if (!qp_state_table[cur_state][next_state].valid)
+		return 0;
+
+	req_param = qp_state_table[cur_state][next_state].req_param[type];
+	opt_param = qp_state_table[cur_state][next_state].opt_param[type];
+
+	if ((mask & req_param) != req_param)
+		return 0;
+
+	if (mask & ~(req_param | opt_param | IB_QP_STATE))
+		return 0;
+
+	return 1;
+}
+EXPORT_SYMBOL(ib_modify_qp_is_ok);
+
 int ib_modify_qp(struct ib_qp *qp,
 		 struct ib_qp_attr *qp_attr,
 		 int qp_attr_mask)
@@ -322,11 +574,10 @@
 }
 EXPORT_SYMBOL(ib_destroy_cq);
 
-int ib_resize_cq(struct ib_cq *cq,
-                 int           cqe)
+int ib_resize_cq(struct ib_cq *cq, int cqe)
 {
 	return cq->device->resize_cq ?
-		cq->device->resize_cq(cq, cqe) : -ENOSYS;
+		cq->device->resize_cq(cq, cqe, NULL) : -ENOSYS;
 }
 EXPORT_SYMBOL(ib_resize_cq);
 
diff --git a/drivers/infiniband/hw/mthca/mthca_av.c b/drivers/infiniband/hw/mthca/mthca_av.c
index a19e0ed..f023d39 100644
--- a/drivers/infiniband/hw/mthca/mthca_av.c
+++ b/drivers/infiniband/hw/mthca/mthca_av.c
@@ -147,7 +147,7 @@
 	switch (ah->type) {
 	case MTHCA_AH_ON_HCA:
 		mthca_free(&dev->av_table.alloc,
- 			   (ah->avdma - dev->av_table.ddr_av_base) /
+			   (ah->avdma - dev->av_table.ddr_av_base) /
 			   MTHCA_AV_SIZE);
 		break;
 
@@ -193,6 +193,37 @@
 	return 0;
 }
 
+int mthca_ah_query(struct ib_ah *ibah, struct ib_ah_attr *attr)
+{
+	struct mthca_ah *ah   = to_mah(ibah);
+	struct mthca_dev *dev = to_mdev(ibah->device);
+
+	/* Only implement for MAD and memfree ah for now. */
+	if (ah->type == MTHCA_AH_ON_HCA)
+		return -ENOSYS;
+
+	memset(attr, 0, sizeof *attr);
+	attr->dlid          = be16_to_cpu(ah->av->dlid);
+	attr->sl            = be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 28;
+	attr->static_rate   = ah->av->msg_sr & 0x7;
+	attr->src_path_bits = ah->av->g_slid & 0x7F;
+	attr->port_num      = be32_to_cpu(ah->av->port_pd) >> 24;
+	attr->ah_flags      = mthca_ah_grh_present(ah) ? IB_AH_GRH : 0;
+
+	if (attr->ah_flags) {
+		attr->grh.traffic_class =
+			be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 20;
+		attr->grh.flow_label =
+			be32_to_cpu(ah->av->sl_tclass_flowlabel) & 0xfffff;
+		attr->grh.hop_limit  = ah->av->hop_limit;
+		attr->grh.sgid_index = ah->av->gid_index &
+				       (dev->limits.gid_table_len - 1);
+		memcpy(attr->grh.dgid.raw, ah->av->dgid, 16);
+	}
+
+	return 0;
+}
+
 int __devinit mthca_init_av_table(struct mthca_dev *dev)
 {
 	int err;
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c
index 2825615..343eca5 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.c
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.c
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
- * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -182,25 +182,58 @@
 	u8                status;
 };
 
+static int fw_cmd_doorbell = 1;
+module_param(fw_cmd_doorbell, int, 0644);
+MODULE_PARM_DESC(fw_cmd_doorbell, "post FW commands through doorbell page if nonzero "
+		 "(and supported by FW)");
+
 static inline int go_bit(struct mthca_dev *dev)
 {
 	return readl(dev->hcr + HCR_STATUS_OFFSET) &
 		swab32(1 << HCR_GO_BIT);
 }
 
-static int mthca_cmd_post(struct mthca_dev *dev,
-			  u64 in_param,
-			  u64 out_param,
-			  u32 in_modifier,
-			  u8 op_modifier,
-			  u16 op,
-			  u16 token,
-			  int event)
+static void mthca_cmd_post_dbell(struct mthca_dev *dev,
+				 u64 in_param,
+				 u64 out_param,
+				 u32 in_modifier,
+				 u8 op_modifier,
+				 u16 op,
+				 u16 token)
 {
-	int err = 0;
+	void __iomem *ptr = dev->cmd.dbell_map;
+	u16 *offs = dev->cmd.dbell_offsets;
 
-	mutex_lock(&dev->cmd.hcr_mutex);
+	__raw_writel((__force u32) cpu_to_be32(in_param >> 32),           ptr + offs[0]);
+	wmb();
+	__raw_writel((__force u32) cpu_to_be32(in_param & 0xfffffffful),  ptr + offs[1]);
+	wmb();
+	__raw_writel((__force u32) cpu_to_be32(in_modifier),              ptr + offs[2]);
+	wmb();
+	__raw_writel((__force u32) cpu_to_be32(out_param >> 32),          ptr + offs[3]);
+	wmb();
+	__raw_writel((__force u32) cpu_to_be32(out_param & 0xfffffffful), ptr + offs[4]);
+	wmb();
+	__raw_writel((__force u32) cpu_to_be32(token << 16),              ptr + offs[5]);
+	wmb();
+	__raw_writel((__force u32) cpu_to_be32((1 << HCR_GO_BIT)                |
+					       (1 << HCA_E_BIT)                 |
+					       (op_modifier << HCR_OPMOD_SHIFT) |
+					        op),                      ptr + offs[6]);
+	wmb();
+	__raw_writel((__force u32) 0,                                     ptr + offs[7]);
+	wmb();
+}
 
+static int mthca_cmd_post_hcr(struct mthca_dev *dev,
+			      u64 in_param,
+			      u64 out_param,
+			      u32 in_modifier,
+			      u8 op_modifier,
+			      u16 op,
+			      u16 token,
+			      int event)
+{
 	if (event) {
 		unsigned long end = jiffies + GO_BIT_TIMEOUT;
 
@@ -210,10 +243,8 @@
 		}
 	}
 
-	if (go_bit(dev)) {
-		err = -EAGAIN;
-		goto out;
-	}
+	if (go_bit(dev))
+		return -EAGAIN;
 
 	/*
 	 * We use writel (instead of something like memcpy_toio)
@@ -236,7 +267,29 @@
 					       (op_modifier << HCR_OPMOD_SHIFT) |
 					       op),                       dev->hcr + 6 * 4);
 
-out:
+	return 0;
+}
+
+static int mthca_cmd_post(struct mthca_dev *dev,
+			  u64 in_param,
+			  u64 out_param,
+			  u32 in_modifier,
+			  u8 op_modifier,
+			  u16 op,
+			  u16 token,
+			  int event)
+{
+	int err = 0;
+
+	mutex_lock(&dev->cmd.hcr_mutex);
+
+	if (event && dev->cmd.flags & MTHCA_CMD_POST_DOORBELLS && fw_cmd_doorbell)
+		mthca_cmd_post_dbell(dev, in_param, out_param, in_modifier,
+					   op_modifier, op, token);
+	else
+		err = mthca_cmd_post_hcr(dev, in_param, out_param, in_modifier,
+					 op_modifier, op, token, event);
+
 	mutex_unlock(&dev->cmd.hcr_mutex);
 	return err;
 }
@@ -275,7 +328,7 @@
 	}
 
 	if (out_is_imm)
-		*out_param = 
+		*out_param =
 			(u64) be32_to_cpu((__force __be32)
 					  __raw_readl(dev->hcr + HCR_OUT_PARAM_OFFSET)) << 32 |
 			(u64) be32_to_cpu((__force __be32)
@@ -386,7 +439,7 @@
 			 unsigned long timeout,
 			 u8 *status)
 {
-	if (dev->cmd.use_events)
+	if (dev->cmd.flags & MTHCA_CMD_USE_EVENTS)
 		return mthca_cmd_wait(dev, in_param, &out_param, 0,
 				      in_modifier, op_modifier, op,
 				      timeout, status);
@@ -423,7 +476,7 @@
 			 unsigned long timeout,
 			 u8 *status)
 {
-	if (dev->cmd.use_events)
+	if (dev->cmd.flags & MTHCA_CMD_USE_EVENTS)
 		return mthca_cmd_wait(dev, in_param, out_param, 1,
 				      in_modifier, op_modifier, op,
 				      timeout, status);
@@ -437,7 +490,7 @@
 {
 	mutex_init(&dev->cmd.hcr_mutex);
 	sema_init(&dev->cmd.poll_sem, 1);
-	dev->cmd.use_events = 0;
+	dev->cmd.flags = 0;
 
 	dev->hcr = ioremap(pci_resource_start(dev->pdev, 0) + MTHCA_HCR_BASE,
 			   MTHCA_HCR_SIZE);
@@ -461,6 +514,8 @@
 {
 	pci_pool_destroy(dev->cmd.pool);
 	iounmap(dev->hcr);
+	if (dev->cmd.flags & MTHCA_CMD_POST_DOORBELLS)
+		iounmap(dev->cmd.dbell_map);
 }
 
 /*
@@ -498,7 +553,8 @@
 		; /* nothing */
 	--dev->cmd.token_mask;
 
-	dev->cmd.use_events = 1;
+	dev->cmd.flags |= MTHCA_CMD_USE_EVENTS;
+
 	down(&dev->cmd.poll_sem);
 
 	return 0;
@@ -511,7 +567,7 @@
 {
 	int i;
 
-	dev->cmd.use_events = 0;
+	dev->cmd.flags &= ~MTHCA_CMD_USE_EVENTS;
 
 	for (i = 0; i < dev->cmd.max_cmds; ++i)
 		down(&dev->cmd.event_sem);
@@ -596,8 +652,9 @@
 		 * address or size and use that as our log2 size.
 		 */
 		lg = ffs(mthca_icm_addr(&iter) | mthca_icm_size(&iter)) - 1;
-		if (lg < 12) {
-			mthca_warn(dev, "Got FW area not aligned to 4K (%llx/%lx).\n",
+		if (lg < MTHCA_ICM_PAGE_SHIFT) {
+			mthca_warn(dev, "Got FW area not aligned to %d (%llx/%lx).\n",
+				   MTHCA_ICM_PAGE_SIZE,
 				   (unsigned long long) mthca_icm_addr(&iter),
 				   mthca_icm_size(&iter));
 			err = -EINVAL;
@@ -609,8 +666,9 @@
 				virt += 1 << lg;
 			}
 
-			pages[nent * 2 + 1] = cpu_to_be64((mthca_icm_addr(&iter) +
-							   (i << lg)) | (lg - 12));
+			pages[nent * 2 + 1] =
+				cpu_to_be64((mthca_icm_addr(&iter) + (i << lg)) |
+					    (lg - MTHCA_ICM_PAGE_SHIFT));
 			ts += 1 << (lg - 10);
 			++tc;
 
@@ -661,12 +719,41 @@
 	return mthca_cmd(dev, 0, 0, 0, CMD_RUN_FW, CMD_TIME_CLASS_A, status);
 }
 
+static void mthca_setup_cmd_doorbells(struct mthca_dev *dev, u64 base)
+{
+	unsigned long addr;
+	u16 max_off = 0;
+	int i;
+
+	for (i = 0; i < 8; ++i)
+		max_off = max(max_off, dev->cmd.dbell_offsets[i]);
+
+	if ((base & PAGE_MASK) != ((base + max_off) & PAGE_MASK)) {
+		mthca_warn(dev, "Firmware doorbell region at 0x%016llx, "
+			   "length 0x%x crosses a page boundary\n",
+			   (unsigned long long) base, max_off);
+		return;
+	}
+
+	addr = pci_resource_start(dev->pdev, 2) +
+		((pci_resource_len(dev->pdev, 2) - 1) & base);
+	dev->cmd.dbell_map = ioremap(addr, max_off + sizeof(u32));
+	if (!dev->cmd.dbell_map)
+		return;
+
+	dev->cmd.flags |= MTHCA_CMD_POST_DOORBELLS;
+	mthca_dbg(dev, "Mapped doorbell page for posting FW commands\n");
+}
+
 int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
 {
 	struct mthca_mailbox *mailbox;
 	u32 *outbox;
+	u64 base;
+	u32 tmp;
 	int err = 0;
 	u8 lg;
+	int i;
 
 #define QUERY_FW_OUT_SIZE             0x100
 #define QUERY_FW_VER_OFFSET            0x00
@@ -674,6 +761,10 @@
 #define QUERY_FW_ERR_START_OFFSET      0x30
 #define QUERY_FW_ERR_SIZE_OFFSET       0x38
 
+#define QUERY_FW_CMD_DB_EN_OFFSET      0x10
+#define QUERY_FW_CMD_DB_OFFSET         0x50
+#define QUERY_FW_CMD_DB_BASE           0x60
+
 #define QUERY_FW_START_OFFSET          0x20
 #define QUERY_FW_END_OFFSET            0x28
 
@@ -702,16 +793,29 @@
 		((dev->fw_ver & 0xffff0000ull) >> 16) |
 		((dev->fw_ver & 0x0000ffffull) << 16);
 
+	mthca_dbg(dev, "FW version %012llx, max commands %d\n",
+		  (unsigned long long) dev->fw_ver, dev->cmd.max_cmds);
+
 	MTHCA_GET(lg, outbox, QUERY_FW_MAX_CMD_OFFSET);
 	dev->cmd.max_cmds = 1 << lg;
 	MTHCA_GET(dev->catas_err.addr, outbox, QUERY_FW_ERR_START_OFFSET);
 	MTHCA_GET(dev->catas_err.size, outbox, QUERY_FW_ERR_SIZE_OFFSET);
 
-	mthca_dbg(dev, "FW version %012llx, max commands %d\n",
-		  (unsigned long long) dev->fw_ver, dev->cmd.max_cmds);
 	mthca_dbg(dev, "Catastrophic error buffer at 0x%llx, size 0x%x\n",
 		  (unsigned long long) dev->catas_err.addr, dev->catas_err.size);
 
+	MTHCA_GET(tmp, outbox, QUERY_FW_CMD_DB_EN_OFFSET);
+	if (tmp & 0x1) {
+		mthca_dbg(dev, "FW supports commands through doorbells\n");
+
+		MTHCA_GET(base, outbox, QUERY_FW_CMD_DB_BASE);
+		for (i = 0; i < MTHCA_CMD_NUM_DBELL_DWORDS; ++i)
+			MTHCA_GET(dev->cmd.dbell_offsets[i], outbox,
+				  QUERY_FW_CMD_DB_OFFSET + (i << 1));
+
+		mthca_setup_cmd_doorbells(dev, base);
+	}
+
 	if (mthca_is_memfree(dev)) {
 		MTHCA_GET(dev->fw.arbel.fw_pages,       outbox, QUERY_FW_SIZE_OFFSET);
 		MTHCA_GET(dev->fw.arbel.clr_int_base,   outbox, QUERY_FW_CLR_INT_BASE_OFFSET);
@@ -720,12 +824,12 @@
 		mthca_dbg(dev, "FW size %d KB\n", dev->fw.arbel.fw_pages << 2);
 
 		/*
-		 * Arbel page size is always 4 KB; round up number of
-		 * system pages needed.
+		 * Round up number of system pages needed in case
+		 * MTHCA_ICM_PAGE_SIZE < PAGE_SIZE.
 		 */
 		dev->fw.arbel.fw_pages =
-			ALIGN(dev->fw.arbel.fw_pages, PAGE_SIZE >> 12) >>
-				(PAGE_SHIFT - 12);
+			ALIGN(dev->fw.arbel.fw_pages, PAGE_SIZE / MTHCA_ICM_PAGE_SIZE) >>
+				(PAGE_SHIFT - MTHCA_ICM_PAGE_SHIFT);
 
 		mthca_dbg(dev, "Clear int @ %llx, EQ arm @ %llx, EQ set CI @ %llx\n",
 			  (unsigned long long) dev->fw.arbel.clr_int_base,
@@ -1173,7 +1277,8 @@
 	int err;
 
 #define INIT_HCA_IN_SIZE             	 0x200
-#define INIT_HCA_FLAGS_OFFSET        	 0x014
+#define INIT_HCA_FLAGS1_OFFSET           0x00c
+#define INIT_HCA_FLAGS2_OFFSET           0x014
 #define INIT_HCA_QPC_OFFSET          	 0x020
 #define  INIT_HCA_QPC_BASE_OFFSET    	 (INIT_HCA_QPC_OFFSET + 0x10)
 #define  INIT_HCA_LOG_QP_OFFSET      	 (INIT_HCA_QPC_OFFSET + 0x17)
@@ -1216,15 +1321,18 @@
 
 	memset(inbox, 0, INIT_HCA_IN_SIZE);
 
+	if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT)
+		MTHCA_PUT(inbox, 0x1, INIT_HCA_FLAGS1_OFFSET);
+
 #if defined(__LITTLE_ENDIAN)
-	*(inbox + INIT_HCA_FLAGS_OFFSET / 4) &= ~cpu_to_be32(1 << 1);
+	*(inbox + INIT_HCA_FLAGS2_OFFSET / 4) &= ~cpu_to_be32(1 << 1);
 #elif defined(__BIG_ENDIAN)
-	*(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 1);
+	*(inbox + INIT_HCA_FLAGS2_OFFSET / 4) |= cpu_to_be32(1 << 1);
 #else
 #error Host endianness not defined
 #endif
 	/* Check port for UD address vector: */
-	*(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1);
+	*(inbox + INIT_HCA_FLAGS2_OFFSET / 4) |= cpu_to_be32(1);
 
 	/* We leave wqe_quota, responder_exu, etc as 0 (default) */
 
@@ -1438,11 +1546,11 @@
 		return ret;
 
 	/*
-	 * Arbel page size is always 4 KB; round up number of system
-	 * pages needed.
+	 * Round up number of system pages needed in case
+	 * MTHCA_ICM_PAGE_SIZE < PAGE_SIZE.
 	 */
-	*aux_pages = (*aux_pages + (1 << (PAGE_SHIFT - 12)) - 1) >> (PAGE_SHIFT - 12);
-	*aux_pages = ALIGN(*aux_pages, PAGE_SIZE >> 12) >> (PAGE_SHIFT - 12);
+	*aux_pages = ALIGN(*aux_pages, PAGE_SIZE / MTHCA_ICM_PAGE_SIZE) >>
+		(PAGE_SHIFT - MTHCA_ICM_PAGE_SHIFT);
 
 	return 0;
 }
@@ -1514,6 +1622,37 @@
 			     CMD_TIME_CLASS_A, status);
 }
 
+int mthca_RESIZE_CQ(struct mthca_dev *dev, int cq_num, u32 lkey, u8 log_size,
+		    u8 *status)
+{
+	struct mthca_mailbox *mailbox;
+	__be32 *inbox;
+	int err;
+
+#define RESIZE_CQ_IN_SIZE		0x40
+#define RESIZE_CQ_LOG_SIZE_OFFSET	0x0c
+#define RESIZE_CQ_LKEY_OFFSET		0x1c
+
+	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+	if (IS_ERR(mailbox))
+		return PTR_ERR(mailbox);
+	inbox = mailbox->buf;
+
+	memset(inbox, 0, RESIZE_CQ_IN_SIZE);
+	/*
+	 * Leave start address fields zeroed out -- mthca assumes that
+	 * MRs for CQs always start at virtual address 0.
+	 */
+	MTHCA_PUT(inbox, log_size, RESIZE_CQ_LOG_SIZE_OFFSET);
+	MTHCA_PUT(inbox, lkey,     RESIZE_CQ_LKEY_OFFSET);
+
+	err = mthca_cmd(dev, mailbox->dma, cq_num, 1, CMD_RESIZE_CQ,
+			CMD_TIME_CLASS_B, status);
+
+	mthca_free_mailbox(dev, mailbox);
+	return err;
+}
+
 int mthca_SW2HW_SRQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 		    int srq_num, u8 *status)
 {
@@ -1529,37 +1668,69 @@
 			     CMD_TIME_CLASS_A, status);
 }
 
+int mthca_QUERY_SRQ(struct mthca_dev *dev, u32 num,
+		    struct mthca_mailbox *mailbox, u8 *status)
+{
+	return mthca_cmd_box(dev, 0, mailbox->dma, num, 0,
+			     CMD_QUERY_SRQ, CMD_TIME_CLASS_A, status);
+}
+
 int mthca_ARM_SRQ(struct mthca_dev *dev, int srq_num, int limit, u8 *status)
 {
 	return mthca_cmd(dev, limit, srq_num, 0, CMD_ARM_SRQ,
 			 CMD_TIME_CLASS_B, status);
 }
 
-int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
-		    int is_ee, struct mthca_mailbox *mailbox, u32 optmask,
+int mthca_MODIFY_QP(struct mthca_dev *dev, enum ib_qp_state cur,
+		    enum ib_qp_state next, u32 num, int is_ee,
+		    struct mthca_mailbox *mailbox, u32 optmask,
 		    u8 *status)
 {
-	static const u16 op[] = {
-		[MTHCA_TRANS_RST2INIT]  = CMD_RST2INIT_QPEE,
-		[MTHCA_TRANS_INIT2INIT] = CMD_INIT2INIT_QPEE,
-		[MTHCA_TRANS_INIT2RTR]  = CMD_INIT2RTR_QPEE,
-		[MTHCA_TRANS_RTR2RTS]   = CMD_RTR2RTS_QPEE,
-		[MTHCA_TRANS_RTS2RTS]   = CMD_RTS2RTS_QPEE,
-		[MTHCA_TRANS_SQERR2RTS] = CMD_SQERR2RTS_QPEE,
-		[MTHCA_TRANS_ANY2ERR]   = CMD_2ERR_QPEE,
-		[MTHCA_TRANS_RTS2SQD]   = CMD_RTS2SQD_QPEE,
-		[MTHCA_TRANS_SQD2SQD]   = CMD_SQD2SQD_QPEE,
-		[MTHCA_TRANS_SQD2RTS]   = CMD_SQD2RTS_QPEE,
-		[MTHCA_TRANS_ANY2RST]   = CMD_ERR2RST_QPEE
+	static const u16 op[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = {
+		[IB_QPS_RESET] = {
+			[IB_QPS_RESET]	= CMD_ERR2RST_QPEE,
+			[IB_QPS_ERR]	= CMD_2ERR_QPEE,
+			[IB_QPS_INIT]	= CMD_RST2INIT_QPEE,
+		},
+		[IB_QPS_INIT]  = {
+			[IB_QPS_RESET]	= CMD_ERR2RST_QPEE,
+			[IB_QPS_ERR]	= CMD_2ERR_QPEE,
+			[IB_QPS_INIT]	= CMD_INIT2INIT_QPEE,
+			[IB_QPS_RTR]	= CMD_INIT2RTR_QPEE,
+		},
+		[IB_QPS_RTR]   = {
+			[IB_QPS_RESET]	= CMD_ERR2RST_QPEE,
+			[IB_QPS_ERR]	= CMD_2ERR_QPEE,
+			[IB_QPS_RTS]	= CMD_RTR2RTS_QPEE,
+		},
+		[IB_QPS_RTS]   = {
+			[IB_QPS_RESET]	= CMD_ERR2RST_QPEE,
+			[IB_QPS_ERR]	= CMD_2ERR_QPEE,
+			[IB_QPS_RTS]	= CMD_RTS2RTS_QPEE,
+			[IB_QPS_SQD]	= CMD_RTS2SQD_QPEE,
+		},
+		[IB_QPS_SQD] = {
+			[IB_QPS_RESET]	= CMD_ERR2RST_QPEE,
+			[IB_QPS_ERR]	= CMD_2ERR_QPEE,
+			[IB_QPS_RTS]	= CMD_SQD2RTS_QPEE,
+			[IB_QPS_SQD]	= CMD_SQD2SQD_QPEE,
+		},
+		[IB_QPS_SQE] = {
+			[IB_QPS_RESET]	= CMD_ERR2RST_QPEE,
+			[IB_QPS_ERR]	= CMD_2ERR_QPEE,
+			[IB_QPS_RTS]	= CMD_SQERR2RTS_QPEE,
+		},
+		[IB_QPS_ERR] = {
+			[IB_QPS_RESET]	= CMD_ERR2RST_QPEE,
+			[IB_QPS_ERR]	= CMD_2ERR_QPEE,
+		}
 	};
+
 	u8 op_mod = 0;
 	int my_mailbox = 0;
 	int err;
 
-	if (trans < 0 || trans >= ARRAY_SIZE(op))
-		return -EINVAL;
-
-	if (trans == MTHCA_TRANS_ANY2RST) {
+	if (op[cur][next] == CMD_ERR2RST_QPEE) {
 		op_mod = 3;	/* don't write outbox, any->reset */
 
 		/* For debugging */
@@ -1571,26 +1742,10 @@
 			} else
 				mailbox = NULL;
 		}
-	} else {
-		if (0) {
-			int i;
-			mthca_dbg(dev, "Dumping QP context:\n");
-			printk("  opt param mask: %08x\n", be32_to_cpup(mailbox->buf));
-			for (i = 0; i < 0x100 / 4; ++i) {
-				if (i % 8 == 0)
-					printk("  [%02x] ", i * 4);
-				printk(" %08x",
-				       be32_to_cpu(((__be32 *) mailbox->buf)[i + 2]));
-				if ((i + 1) % 8 == 0)
-					printk("\n");
-			}
-		}
-	}
 
-	if (trans == MTHCA_TRANS_ANY2RST) {
 		err = mthca_cmd_box(dev, 0, mailbox ? mailbox->dma : 0,
 				    (!!is_ee << 24) | num, op_mod,
-				    op[trans], CMD_TIME_CLASS_C, status);
+				    op[cur][next], CMD_TIME_CLASS_C, status);
 
 		if (0 && mailbox) {
 			int i;
@@ -1606,12 +1761,26 @@
 			}
 		}
 
-	} else
-		err = mthca_cmd(dev, mailbox->dma, (!!is_ee << 24) | num,
-				op_mod, op[trans], CMD_TIME_CLASS_C, status);
+		if (my_mailbox)
+			mthca_free_mailbox(dev, mailbox);
+	} else {
+		if (0) {
+			int i;
+			mthca_dbg(dev, "Dumping QP context:\n");
+			printk("  opt param mask: %08x\n", be32_to_cpup(mailbox->buf));
+			for (i = 0; i < 0x100 / 4; ++i) {
+				if (i % 8 == 0)
+					printk("  [%02x] ", i * 4);
+				printk(" %08x",
+				       be32_to_cpu(((__be32 *) mailbox->buf)[i + 2]));
+				if ((i + 1) % 8 == 0)
+					printk("\n");
+			}
+		}
 
-	if (my_mailbox)
-		mthca_free_mailbox(dev, mailbox);
+		err = mthca_cmd(dev, mailbox->dma, optmask | (!!is_ee << 24) | num,
+				op_mod, op[cur][next], CMD_TIME_CLASS_C, status);
+	}
 
 	return err;
 }
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.h b/drivers/infiniband/hw/mthca/mthca_cmd.h
index 18175be..e4ec35c 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.h
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.h
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2006 Cisco Systems.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -73,9 +74,9 @@
 	MTHCA_CMD_STAT_REG_BOUND      = 0x21,
 	/* HCA local attached memory not present: */
 	MTHCA_CMD_STAT_LAM_NOT_PRE    = 0x22,
-        /* Bad management packet (silently discarded): */
+	/* Bad management packet (silently discarded): */
 	MTHCA_CMD_STAT_BAD_PKT 	      = 0x30,
-        /* More outstanding CQEs in CQ than new CQ size: */
+	/* More outstanding CQEs in CQ than new CQ size: */
 	MTHCA_CMD_STAT_BAD_SIZE       = 0x40
 };
 
@@ -298,13 +299,18 @@
 		   int cq_num, u8 *status);
 int mthca_HW2SW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 		   int cq_num, u8 *status);
+int mthca_RESIZE_CQ(struct mthca_dev *dev, int cq_num, u32 lkey, u8 log_size,
+		    u8 *status);
 int mthca_SW2HW_SRQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 		    int srq_num, u8 *status);
 int mthca_HW2SW_SRQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 		    int srq_num, u8 *status);
+int mthca_QUERY_SRQ(struct mthca_dev *dev, u32 num,
+		    struct mthca_mailbox *mailbox, u8 *status);
 int mthca_ARM_SRQ(struct mthca_dev *dev, int srq_num, int limit, u8 *status);
-int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
-		    int is_ee, struct mthca_mailbox *mailbox, u32 optmask,
+int mthca_MODIFY_QP(struct mthca_dev *dev, enum ib_qp_state cur,
+		    enum ib_qp_state next, u32 num, int is_ee,
+		    struct mthca_mailbox *mailbox, u32 optmask,
 		    u8 *status);
 int mthca_QUERY_QP(struct mthca_dev *dev, u32 num, int is_ee,
 		   struct mthca_mailbox *mailbox, u8 *status);
diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c
index 96f1a86..76aabc5 100644
--- a/drivers/infiniband/hw/mthca/mthca_cq.c
+++ b/drivers/infiniband/hw/mthca/mthca_cq.c
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
- * Copyright (c) 2005 Cisco Systems, Inc. All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
  *
@@ -150,24 +150,29 @@
 #define MTHCA_ARBEL_CQ_DB_REQ_NOT      (2 << 24)
 #define MTHCA_ARBEL_CQ_DB_REQ_NOT_MULT (3 << 24)
 
-static inline struct mthca_cqe *get_cqe(struct mthca_cq *cq, int entry)
+static inline struct mthca_cqe *get_cqe_from_buf(struct mthca_cq_buf *buf,
+						 int entry)
 {
-	if (cq->is_direct)
-		return cq->queue.direct.buf + (entry * MTHCA_CQ_ENTRY_SIZE);
+	if (buf->is_direct)
+		return buf->queue.direct.buf + (entry * MTHCA_CQ_ENTRY_SIZE);
 	else
-		return cq->queue.page_list[entry * MTHCA_CQ_ENTRY_SIZE / PAGE_SIZE].buf
+		return buf->queue.page_list[entry * MTHCA_CQ_ENTRY_SIZE / PAGE_SIZE].buf
 			+ (entry * MTHCA_CQ_ENTRY_SIZE) % PAGE_SIZE;
 }
 
-static inline struct mthca_cqe *cqe_sw(struct mthca_cq *cq, int i)
+static inline struct mthca_cqe *get_cqe(struct mthca_cq *cq, int entry)
 {
-	struct mthca_cqe *cqe = get_cqe(cq, i);
+	return get_cqe_from_buf(&cq->buf, entry);
+}
+
+static inline struct mthca_cqe *cqe_sw(struct mthca_cqe *cqe)
+{
 	return MTHCA_CQ_ENTRY_OWNER_HW & cqe->owner ? NULL : cqe;
 }
 
 static inline struct mthca_cqe *next_cqe_sw(struct mthca_cq *cq)
 {
-	return cqe_sw(cq, cq->cons_index & cq->ibcq.cqe);
+	return cqe_sw(get_cqe(cq, cq->cons_index & cq->ibcq.cqe));
 }
 
 static inline void set_cqe_hw(struct mthca_cqe *cqe)
@@ -289,7 +294,7 @@
 	 * from our QP and therefore don't need to be checked.
 	 */
 	for (prod_index = cq->cons_index;
-	     cqe_sw(cq, prod_index & cq->ibcq.cqe);
+	     cqe_sw(get_cqe(cq, prod_index & cq->ibcq.cqe));
 	     ++prod_index)
 		if (prod_index == cq->cons_index + cq->ibcq.cqe)
 			break;
@@ -324,12 +329,58 @@
 		wake_up(&cq->wait);
 }
 
-static int handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq,
-			    struct mthca_qp *qp, int wqe_index, int is_send,
-			    struct mthca_err_cqe *cqe,
-			    struct ib_wc *entry, int *free_cqe)
+void mthca_cq_resize_copy_cqes(struct mthca_cq *cq)
 {
-	int err;
+	int i;
+
+	/*
+	 * In Tavor mode, the hardware keeps the consumer and producer
+	 * indices mod the CQ size.  Since we might be making the CQ
+	 * bigger, we need to deal with the case where the producer
+	 * index wrapped around before the CQ was resized.
+	 */
+	if (!mthca_is_memfree(to_mdev(cq->ibcq.device)) &&
+	    cq->ibcq.cqe < cq->resize_buf->cqe) {
+		cq->cons_index &= cq->ibcq.cqe;
+		if (cqe_sw(get_cqe(cq, cq->ibcq.cqe)))
+			cq->cons_index -= cq->ibcq.cqe + 1;
+	}
+
+	for (i = cq->cons_index; cqe_sw(get_cqe(cq, i & cq->ibcq.cqe)); ++i)
+		memcpy(get_cqe_from_buf(&cq->resize_buf->buf,
+					i & cq->resize_buf->cqe),
+		       get_cqe(cq, i & cq->ibcq.cqe), MTHCA_CQ_ENTRY_SIZE);
+}
+
+int mthca_alloc_cq_buf(struct mthca_dev *dev, struct mthca_cq_buf *buf, int nent)
+{
+	int ret;
+	int i;
+
+	ret = mthca_buf_alloc(dev, nent * MTHCA_CQ_ENTRY_SIZE,
+			      MTHCA_MAX_DIRECT_CQ_SIZE,
+			      &buf->queue, &buf->is_direct,
+			      &dev->driver_pd, 1, &buf->mr);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < nent; ++i)
+		set_cqe_hw(get_cqe_from_buf(buf, i));
+
+	return 0;
+}
+
+void mthca_free_cq_buf(struct mthca_dev *dev, struct mthca_cq_buf *buf, int cqe)
+{
+	mthca_buf_free(dev, (cqe + 1) * MTHCA_CQ_ENTRY_SIZE, &buf->queue,
+		       buf->is_direct, &buf->mr);
+}
+
+static void handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq,
+			     struct mthca_qp *qp, int wqe_index, int is_send,
+			     struct mthca_err_cqe *cqe,
+			     struct ib_wc *entry, int *free_cqe)
+{
 	int dbd;
 	__be32 new_wqe;
 
@@ -412,11 +463,9 @@
 	 * error case, so we don't have to check the doorbell count, etc.
 	 */
 	if (mthca_is_memfree(dev))
-		return 0;
+		return;
 
-	err = mthca_free_err_wqe(dev, qp, is_send, wqe_index, &dbd, &new_wqe);
-	if (err)
-		return err;
+	mthca_free_err_wqe(dev, qp, is_send, wqe_index, &dbd, &new_wqe);
 
 	/*
 	 * If we're at the end of the WQE chain, or we've used up our
@@ -424,15 +473,13 @@
 	 * the next poll operation.
 	 */
 	if (!(new_wqe & cpu_to_be32(0x3f)) || (!cqe->db_cnt && dbd))
-		return 0;
+		return;
 
 	cqe->db_cnt   = cpu_to_be16(be16_to_cpu(cqe->db_cnt) - dbd);
 	cqe->wqe      = new_wqe;
 	cqe->syndrome = SYNDROME_WR_FLUSH_ERR;
 
 	*free_cqe = 0;
-
-	return 0;
 }
 
 static inline int mthca_poll_one(struct mthca_dev *dev,
@@ -518,9 +565,9 @@
 	}
 
 	if (is_error) {
-		err = handle_error_cqe(dev, cq, *cur_qp, wqe_index, is_send,
-				       (struct mthca_err_cqe *) cqe,
-				       entry, &free_cqe);
+		handle_error_cqe(dev, cq, *cur_qp, wqe_index, is_send,
+				 (struct mthca_err_cqe *) cqe,
+				 entry, &free_cqe);
 		goto out;
 	}
 
@@ -614,11 +661,14 @@
 
 	spin_lock_irqsave(&cq->lock, flags);
 
-	for (npolled = 0; npolled < num_entries; ++npolled) {
+	npolled = 0;
+repoll:
+	while (npolled < num_entries) {
 		err = mthca_poll_one(dev, cq, &qp,
 				     &freed, entry + npolled);
 		if (err)
 			break;
+		++npolled;
 	}
 
 	if (freed) {
@@ -626,6 +676,42 @@
 		update_cons_index(dev, cq, freed);
 	}
 
+	/*
+	 * If a CQ resize is in progress and we discovered that the
+	 * old buffer is empty, then peek in the new buffer, and if
+	 * it's not empty, switch to the new buffer and continue
+	 * polling there.
+	 */
+	if (unlikely(err == -EAGAIN && cq->resize_buf &&
+		     cq->resize_buf->state == CQ_RESIZE_READY)) {
+		/*
+		 * In Tavor mode, the hardware keeps the producer
+		 * index modulo the CQ size.  Since we might be making
+		 * the CQ bigger, we need to mask our consumer index
+		 * using the size of the old CQ buffer before looking
+		 * in the new CQ buffer.
+		 */
+		if (!mthca_is_memfree(dev))
+			cq->cons_index &= cq->ibcq.cqe;
+
+		if (cqe_sw(get_cqe_from_buf(&cq->resize_buf->buf,
+					    cq->cons_index & cq->resize_buf->cqe))) {
+			struct mthca_cq_buf tbuf;
+			int tcqe;
+
+			tbuf         = cq->buf;
+			tcqe         = cq->ibcq.cqe;
+			cq->buf      = cq->resize_buf->buf;
+			cq->ibcq.cqe = cq->resize_buf->cqe;
+
+			cq->resize_buf->buf   = tbuf;
+			cq->resize_buf->cqe   = tcqe;
+			cq->resize_buf->state = CQ_RESIZE_SWAPPED;
+
+			goto repoll;
+		}
+	}
+
 	spin_unlock_irqrestore(&cq->lock, flags);
 
 	return err == 0 || err == -EAGAIN ? npolled : err;
@@ -684,24 +770,14 @@
 	return 0;
 }
 
-static void mthca_free_cq_buf(struct mthca_dev *dev, struct mthca_cq *cq)
-{
-	mthca_buf_free(dev, (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE,
-		       &cq->queue, cq->is_direct, &cq->mr);
-}
-
 int mthca_init_cq(struct mthca_dev *dev, int nent,
 		  struct mthca_ucontext *ctx, u32 pdn,
 		  struct mthca_cq *cq)
 {
-	int size = nent * MTHCA_CQ_ENTRY_SIZE;
 	struct mthca_mailbox *mailbox;
 	struct mthca_cq_context *cq_context;
 	int err = -ENOMEM;
 	u8 status;
-	int i;
-
-	might_sleep();
 
 	cq->ibcq.cqe  = nent - 1;
 	cq->is_kernel = !ctx;
@@ -739,14 +815,9 @@
 	cq_context = mailbox->buf;
 
 	if (cq->is_kernel) {
-		err = mthca_buf_alloc(dev, size, MTHCA_MAX_DIRECT_CQ_SIZE,
-				      &cq->queue, &cq->is_direct,
-				      &dev->driver_pd, 1, &cq->mr);
+		err = mthca_alloc_cq_buf(dev, &cq->buf, nent);
 		if (err)
 			goto err_out_mailbox;
-
-		for (i = 0; i < nent; ++i)
-			set_cqe_hw(get_cqe(cq, i));
 	}
 
 	spin_lock_init(&cq->lock);
@@ -765,7 +836,7 @@
 	cq_context->error_eqn       = cpu_to_be32(dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn);
 	cq_context->comp_eqn        = cpu_to_be32(dev->eq_table.eq[MTHCA_EQ_COMP].eqn);
 	cq_context->pd              = cpu_to_be32(pdn);
-	cq_context->lkey            = cpu_to_be32(cq->mr.ibmr.lkey);
+	cq_context->lkey            = cpu_to_be32(cq->buf.mr.ibmr.lkey);
 	cq_context->cqn             = cpu_to_be32(cq->cqn);
 
 	if (mthca_is_memfree(dev)) {
@@ -803,7 +874,7 @@
 
 err_out_free_mr:
 	if (cq->is_kernel)
-		mthca_free_cq_buf(dev, cq);
+		mthca_free_cq_buf(dev, &cq->buf, cq->ibcq.cqe);
 
 err_out_mailbox:
 	mthca_free_mailbox(dev, mailbox);
@@ -832,8 +903,6 @@
 	int err;
 	u8 status;
 
-	might_sleep();
-
 	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 	if (IS_ERR(mailbox)) {
 		mthca_warn(dev, "No memory for mailbox to free CQ.\n");
@@ -871,7 +940,7 @@
 	wait_event(cq->wait, !atomic_read(&cq->refcount));
 
 	if (cq->is_kernel) {
-		mthca_free_cq_buf(dev, cq);
+		mthca_free_cq_buf(dev, &cq->buf, cq->ibcq.cqe);
 		if (mthca_is_memfree(dev)) {
 			mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM,    cq->arm_db_index);
 			mthca_free_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, cq->set_ci_db_index);
diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h
index e4810372..ad52edb 100644
--- a/drivers/infiniband/hw/mthca/mthca_dev.h
+++ b/drivers/infiniband/hw/mthca/mthca_dev.h
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
  *
@@ -53,8 +53,8 @@
 
 #define DRV_NAME	"ib_mthca"
 #define PFX		DRV_NAME ": "
-#define DRV_VERSION	"0.07"
-#define DRV_RELDATE	"February 13, 2006"
+#define DRV_VERSION	"0.08"
+#define DRV_RELDATE	"February 14, 2006"
 
 enum {
 	MTHCA_FLAG_DDR_HIDDEN = 1 << 1,
@@ -64,7 +64,8 @@
 	MTHCA_FLAG_NO_LAM     = 1 << 5,
 	MTHCA_FLAG_FMR        = 1 << 6,
 	MTHCA_FLAG_MEMFREE    = 1 << 7,
-	MTHCA_FLAG_PCIE       = 1 << 8
+	MTHCA_FLAG_PCIE       = 1 << 8,
+	MTHCA_FLAG_SINAI_OPT  = 1 << 9
 };
 
 enum {
@@ -110,9 +111,17 @@
 	MTHCA_OPCODE_INVALID        = 0xff
 };
 
+enum {
+	MTHCA_CMD_USE_EVENTS         = 1 << 0,
+	MTHCA_CMD_POST_DOORBELLS     = 1 << 1
+};
+
+enum {
+	MTHCA_CMD_NUM_DBELL_DWORDS = 8
+};
+
 struct mthca_cmd {
 	struct pci_pool          *pool;
-	int                       use_events;
 	struct mutex              hcr_mutex;
 	struct semaphore 	  poll_sem;
 	struct semaphore 	  event_sem;
@@ -121,6 +130,9 @@
 	int                       free_head;
 	struct mthca_cmd_context *context;
 	u16                       token_mask;
+	u32                       flags;
+	void __iomem             *dbell_map;
+	u16                       dbell_offsets[MTHCA_CMD_NUM_DBELL_DWORDS];
 };
 
 struct mthca_limits {
@@ -470,12 +482,16 @@
 		    enum ib_event_type event_type);
 void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn,
 		    struct mthca_srq *srq);
+void mthca_cq_resize_copy_cqes(struct mthca_cq *cq);
+int mthca_alloc_cq_buf(struct mthca_dev *dev, struct mthca_cq_buf *buf, int nent);
+void mthca_free_cq_buf(struct mthca_dev *dev, struct mthca_cq_buf *buf, int cqe);
 
 int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd,
 		    struct ib_srq_attr *attr, struct mthca_srq *srq);
 void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq);
 int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
 		     enum ib_srq_attr_mask attr_mask);
+int mthca_query_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr);
 void mthca_srq_event(struct mthca_dev *dev, u32 srqn,
 		     enum ib_event_type event_type);
 void mthca_free_srq_wqe(struct mthca_srq *srq, u32 wqe_addr);
@@ -486,6 +502,8 @@
 
 void mthca_qp_event(struct mthca_dev *dev, u32 qpn,
 		    enum ib_event_type event_type);
+int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask,
+		   struct ib_qp_init_attr *qp_init_attr);
 int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask);
 int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
 			  struct ib_send_wr **bad_wr);
@@ -495,8 +513,8 @@
 			  struct ib_send_wr **bad_wr);
 int mthca_arbel_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
 			     struct ib_recv_wr **bad_wr);
-int mthca_free_err_wqe(struct mthca_dev *dev, struct mthca_qp *qp, int is_send,
-		       int index, int *dbd, __be32 *new_wqe);
+void mthca_free_err_wqe(struct mthca_dev *dev, struct mthca_qp *qp, int is_send,
+			int index, int *dbd, __be32 *new_wqe);
 int mthca_alloc_qp(struct mthca_dev *dev,
 		   struct mthca_pd *pd,
 		   struct mthca_cq *send_cq,
@@ -522,6 +540,7 @@
 int mthca_destroy_ah(struct mthca_dev *dev, struct mthca_ah *ah);
 int mthca_read_ah(struct mthca_dev *dev, struct mthca_ah *ah,
 		  struct ib_ud_header *header);
+int mthca_ah_query(struct ib_ah *ibah, struct ib_ah_attr *attr);
 int mthca_ah_grh_present(struct mthca_ah *ah);
 
 int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid);
diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c
index 2eabb27..cbdc348 100644
--- a/drivers/infiniband/hw/mthca/mthca_eq.c
+++ b/drivers/infiniband/hw/mthca/mthca_eq.c
@@ -497,7 +497,7 @@
 
 	eq->dev  = dev;
 	eq->nent = roundup_pow_of_two(max(nent, 2));
- 	npages = ALIGN(eq->nent * MTHCA_EQ_ENTRY_SIZE, PAGE_SIZE) / PAGE_SIZE;
+	npages = ALIGN(eq->nent * MTHCA_EQ_ENTRY_SIZE, PAGE_SIZE) / PAGE_SIZE;
 
 	eq->page_list = kmalloc(npages * sizeof *eq->page_list,
 				GFP_KERNEL);
@@ -825,7 +825,7 @@
 {
 	u8 status;
 
-	mthca_UNMAP_ICM(dev, dev->eq_table.icm_virt, PAGE_SIZE / 4096, &status);
+	mthca_UNMAP_ICM(dev, dev->eq_table.icm_virt, 1, &status);
 	pci_unmap_page(dev->pdev, dev->eq_table.icm_dma, PAGE_SIZE,
 		       PCI_DMA_BIDIRECTIONAL);
 	__free_page(dev->eq_table.icm_page);
@@ -928,7 +928,7 @@
 		mthca_warn(dev, "MAP_EQ for cmd EQ %d returned status 0x%02x\n",
 			   dev->eq_table.eq[MTHCA_EQ_CMD].eqn, status);
 
-	for (i = 0; i < MTHCA_EQ_CMD; ++i)
+	for (i = 0; i < MTHCA_NUM_EQ; ++i)
 		if (mthca_is_memfree(dev))
 			arbel_eq_req_not(dev, dev->eq_table.eq[i].eqn_mask);
 		else
diff --git a/drivers/infiniband/hw/mthca/mthca_mad.c b/drivers/infiniband/hw/mthca/mthca_mad.c
index 1229c60..4ace6a3 100644
--- a/drivers/infiniband/hw/mthca/mthca_mad.c
+++ b/drivers/infiniband/hw/mthca/mthca_mad.c
@@ -109,6 +109,19 @@
 	}
 }
 
+static void node_desc_override(struct ib_device *dev,
+			       struct ib_mad *mad)
+{
+	if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||
+	     mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) &&
+	    mad->mad_hdr.method == IB_MGMT_METHOD_GET_RESP &&
+	    mad->mad_hdr.attr_id == IB_SMP_ATTR_NODE_DESC) {
+		mutex_lock(&to_mdev(dev)->cap_mask_mutex);
+		memcpy(((struct ib_smp *) mad)->data, dev->node_desc, 64);
+		mutex_unlock(&to_mdev(dev)->cap_mask_mutex);
+	}
+}
+
 static void forward_trap(struct mthca_dev *dev,
 			 u8 port_num,
 			 struct ib_mad *mad)
@@ -207,8 +220,10 @@
 		return IB_MAD_RESULT_FAILURE;
 	}
 
-	if (!out_mad->mad_hdr.status)
+	if (!out_mad->mad_hdr.status) {
 		smp_snoop(ibdev, port_num, in_mad);
+		node_desc_override(ibdev, out_mad);
+	}
 
 	/* set return bit in status of directed route responses */
 	if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c
index 9c849d2..266f347 100644
--- a/drivers/infiniband/hw/mthca/mthca_main.c
+++ b/drivers/infiniband/hw/mthca/mthca_main.c
@@ -935,13 +935,19 @@
 
 static struct {
 	u64 latest_fw;
-	int is_memfree;
-	int is_pcie;
+	u32 flags;
 } mthca_hca_table[] = {
-	[TAVOR]        = { .latest_fw = MTHCA_FW_VER(3, 3, 3), .is_memfree = 0, .is_pcie = 0 },
-	[ARBEL_COMPAT] = { .latest_fw = MTHCA_FW_VER(4, 7, 0), .is_memfree = 0, .is_pcie = 1 },
-	[ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 1, 0), .is_memfree = 1, .is_pcie = 1 },
-	[SINAI]        = { .latest_fw = MTHCA_FW_VER(1, 0, 1), .is_memfree = 1, .is_pcie = 1 }
+	[TAVOR]        = { .latest_fw = MTHCA_FW_VER(3, 4, 0),
+			   .flags     = 0 },
+	[ARBEL_COMPAT] = { .latest_fw = MTHCA_FW_VER(4, 7, 400),
+			   .flags     = MTHCA_FLAG_PCIE },
+	[ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 1, 0),
+			   .flags     = MTHCA_FLAG_MEMFREE |
+					MTHCA_FLAG_PCIE },
+	[SINAI]        = { .latest_fw = MTHCA_FW_VER(1, 0, 800),
+			   .flags     = MTHCA_FLAG_MEMFREE |
+					MTHCA_FLAG_PCIE    |
+					MTHCA_FLAG_SINAI_OPT }
 };
 
 static int __devinit mthca_init_one(struct pci_dev *pdev,
@@ -1031,12 +1037,9 @@
 
 	mdev->pdev = pdev;
 
+	mdev->mthca_flags = mthca_hca_table[id->driver_data].flags;
 	if (ddr_hidden)
 		mdev->mthca_flags |= MTHCA_FLAG_DDR_HIDDEN;
-	if (mthca_hca_table[id->driver_data].is_memfree)
-		mdev->mthca_flags |= MTHCA_FLAG_MEMFREE;
-	if (mthca_hca_table[id->driver_data].is_pcie)
-		mdev->mthca_flags |= MTHCA_FLAG_PCIE;
 
 	/*
 	 * Now reset the HCA before we touch the PCI capabilities or
diff --git a/drivers/infiniband/hw/mthca/mthca_mcg.c b/drivers/infiniband/hw/mthca/mthca_mcg.c
index 321f11e..9965bda 100644
--- a/drivers/infiniband/hw/mthca/mthca_mcg.c
+++ b/drivers/infiniband/hw/mthca/mthca_mcg.c
@@ -187,7 +187,7 @@
 
 	for (i = 0; i < MTHCA_QP_PER_MGM; ++i)
 		if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31))) {
-			mthca_dbg(dev, "QP %06x already a member of MGM\n", 
+			mthca_dbg(dev, "QP %06x already a member of MGM\n",
 				  ibqp->qp_num);
 			err = 0;
 			goto out;
diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c
index d709cb1..15cc2f6 100644
--- a/drivers/infiniband/hw/mthca/mthca_memfree.c
+++ b/drivers/infiniband/hw/mthca/mthca_memfree.c
@@ -202,7 +202,8 @@
 
 	if (--table->icm[i]->refcount == 0) {
 		mthca_UNMAP_ICM(dev, table->virt + i * MTHCA_TABLE_CHUNK_SIZE,
-				MTHCA_TABLE_CHUNK_SIZE >> 12, &status);
+				MTHCA_TABLE_CHUNK_SIZE / MTHCA_ICM_PAGE_SIZE,
+				&status);
 		mthca_free_icm(dev, table->icm[i]);
 		table->icm[i] = NULL;
 	}
@@ -336,7 +337,8 @@
 	for (i = 0; i < num_icm; ++i)
 		if (table->icm[i]) {
 			mthca_UNMAP_ICM(dev, virt + i * MTHCA_TABLE_CHUNK_SIZE,
-					MTHCA_TABLE_CHUNK_SIZE >> 12, &status);
+					MTHCA_TABLE_CHUNK_SIZE / MTHCA_ICM_PAGE_SIZE,
+				        &status);
 			mthca_free_icm(dev, table->icm[i]);
 		}
 
@@ -353,7 +355,8 @@
 	for (i = 0; i < table->num_icm; ++i)
 		if (table->icm[i]) {
 			mthca_UNMAP_ICM(dev, table->virt + i * MTHCA_TABLE_CHUNK_SIZE,
-					MTHCA_TABLE_CHUNK_SIZE >> 12, &status);
+					MTHCA_TABLE_CHUNK_SIZE / MTHCA_ICM_PAGE_SIZE,
+					&status);
 			mthca_free_icm(dev, table->icm[i]);
 		}
 
@@ -364,7 +367,7 @@
 {
 	return dev->uar_table.uarc_base +
 		uar->index * dev->uar_table.uarc_size +
-		page * 4096;
+		page * MTHCA_ICM_PAGE_SIZE;
 }
 
 int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
@@ -401,7 +404,7 @@
 	if (ret < 0)
 		goto out;
 
-	db_tab->page[i].mem.length = 4096;
+	db_tab->page[i].mem.length = MTHCA_ICM_PAGE_SIZE;
 	db_tab->page[i].mem.offset = uaddr & ~PAGE_MASK;
 
 	ret = pci_map_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE);
@@ -455,7 +458,7 @@
 	if (!mthca_is_memfree(dev))
 		return NULL;
 
-	npages = dev->uar_table.uarc_size / 4096;
+	npages = dev->uar_table.uarc_size / MTHCA_ICM_PAGE_SIZE;
 	db_tab = kmalloc(sizeof *db_tab + npages * sizeof *db_tab->page, GFP_KERNEL);
 	if (!db_tab)
 		return ERR_PTR(-ENOMEM);
@@ -478,7 +481,7 @@
 	if (!mthca_is_memfree(dev))
 		return;
 
-	for (i = 0; i < dev->uar_table.uarc_size / 4096; ++i) {
+	for (i = 0; i < dev->uar_table.uarc_size / MTHCA_ICM_PAGE_SIZE; ++i) {
 		if (db_tab->page[i].uvirt) {
 			mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, uar, i), 1, &status);
 			pci_unmap_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE);
@@ -551,20 +554,20 @@
 	page = dev->db_tab->page + end;
 
 alloc:
-	page->db_rec = dma_alloc_coherent(&dev->pdev->dev, 4096,
+	page->db_rec = dma_alloc_coherent(&dev->pdev->dev, MTHCA_ICM_PAGE_SIZE,
 					  &page->mapping, GFP_KERNEL);
 	if (!page->db_rec) {
 		ret = -ENOMEM;
 		goto out;
 	}
-	memset(page->db_rec, 0, 4096);
+	memset(page->db_rec, 0, MTHCA_ICM_PAGE_SIZE);
 
 	ret = mthca_MAP_ICM_page(dev, page->mapping,
 				 mthca_uarc_virt(dev, &dev->driver_uar, i), &status);
 	if (!ret && status)
 		ret = -EINVAL;
 	if (ret) {
-		dma_free_coherent(&dev->pdev->dev, 4096,
+		dma_free_coherent(&dev->pdev->dev, MTHCA_ICM_PAGE_SIZE,
 				  page->db_rec, page->mapping);
 		goto out;
 	}
@@ -612,7 +615,7 @@
 	    i >= dev->db_tab->max_group1 - 1) {
 		mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, &dev->driver_uar, i), 1, &status);
 
-		dma_free_coherent(&dev->pdev->dev, 4096,
+		dma_free_coherent(&dev->pdev->dev, MTHCA_ICM_PAGE_SIZE,
 				  page->db_rec, page->mapping);
 		page->db_rec = NULL;
 
@@ -640,7 +643,7 @@
 
 	mutex_init(&dev->db_tab->mutex);
 
-	dev->db_tab->npages     = dev->uar_table.uarc_size / 4096;
+	dev->db_tab->npages     = dev->uar_table.uarc_size / MTHCA_ICM_PAGE_SIZE;
 	dev->db_tab->max_group1 = 0;
 	dev->db_tab->min_group2 = dev->db_tab->npages - 1;
 
@@ -681,7 +684,7 @@
 
 		mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, &dev->driver_uar, i), 1, &status);
 
-		dma_free_coherent(&dev->pdev->dev, 4096,
+		dma_free_coherent(&dev->pdev->dev, MTHCA_ICM_PAGE_SIZE,
 				  dev->db_tab->page[i].db_rec,
 				  dev->db_tab->page[i].mapping);
 	}
diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.h b/drivers/infiniband/hw/mthca/mthca_memfree.h
index 36f1141..6d42947 100644
--- a/drivers/infiniband/hw/mthca/mthca_memfree.h
+++ b/drivers/infiniband/hw/mthca/mthca_memfree.h
@@ -45,6 +45,12 @@
 	((256 - sizeof (struct list_head) - 2 * sizeof (int)) /		\
 	 (sizeof (struct scatterlist)))
 
+enum {
+	MTHCA_ICM_PAGE_SHIFT	= 12,
+	MTHCA_ICM_PAGE_SIZE	= 1 << MTHCA_ICM_PAGE_SHIFT,
+	MTHCA_DB_REC_PER_PAGE	= MTHCA_ICM_PAGE_SIZE / 8
+};
+
 struct mthca_icm_chunk {
 	struct list_head   list;
 	int                npages;
@@ -131,10 +137,6 @@
 	return sg_dma_len(&iter->chunk->mem[iter->page_idx]);
 }
 
-enum {
-	MTHCA_DB_REC_PER_PAGE = 4096 / 8
-};
-
 struct mthca_db_page {
 	DECLARE_BITMAP(used, MTHCA_DB_REC_PER_PAGE);
 	__be64    *db_rec;
diff --git a/drivers/infiniband/hw/mthca/mthca_mr.c b/drivers/infiniband/hw/mthca/mthca_mr.c
index e995e2a..698b621 100644
--- a/drivers/infiniband/hw/mthca/mthca_mr.c
+++ b/drivers/infiniband/hw/mthca/mthca_mr.c
@@ -76,6 +76,8 @@
 #define MTHCA_MPT_STATUS_SW 0xF0
 #define MTHCA_MPT_STATUS_HW 0x00
 
+#define SINAI_FMR_KEY_INC 0x1000000
+
 /*
  * Buddy allocator for MTT segments (currently not very efficient
  * since it doesn't keep a free list and just searches linearly
@@ -330,6 +332,14 @@
 		return tavor_key_to_hw_index(key);
 }
 
+static inline u32 adjust_key(struct mthca_dev *dev, u32 key)
+{
+	if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT)
+		return ((key << 20) & 0x800000) | (key & 0x7fffff);
+	else
+		return key;
+}
+
 int mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift,
 		   u64 iova, u64 total_size, u32 access, struct mthca_mr *mr)
 {
@@ -340,13 +350,12 @@
 	int err;
 	u8 status;
 
-	might_sleep();
-
 	WARN_ON(buffer_size_shift >= 32);
 
 	key = mthca_alloc(&dev->mr_table.mpt_alloc);
 	if (key == -1)
 		return -ENOMEM;
+	key = adjust_key(dev, key);
 	mr->ibmr.rkey = mr->ibmr.lkey = hw_index_to_key(dev, key);
 
 	if (mthca_is_memfree(dev)) {
@@ -467,8 +476,6 @@
 	int err;
 	u8 status;
 
-	might_sleep();
-
 	err = mthca_HW2SW_MPT(dev, NULL,
 			      key_to_hw_index(dev, mr->ibmr.lkey) &
 			      (dev->limits.num_mpts - 1),
@@ -495,9 +502,7 @@
 	int err = -ENOMEM;
 	int i;
 
-	might_sleep();
-
-	if (mr->attr.page_size < 12 || mr->attr.page_size >= 32)
+	if (mr->attr.page_shift < 12 || mr->attr.page_shift >= 32)
 		return -EINVAL;
 
 	/* For Arbel, all MTTs must fit in the same page. */
@@ -510,6 +515,7 @@
 	key = mthca_alloc(&dev->mr_table.mpt_alloc);
 	if (key == -1)
 		return -ENOMEM;
+	key = adjust_key(dev, key);
 
 	idx = key & (dev->limits.num_mpts - 1);
 	mr->ibmr.rkey = mr->ibmr.lkey = hw_index_to_key(dev, key);
@@ -523,7 +529,7 @@
 		BUG_ON(!mr->mem.arbel.mpt);
 	} else
 		mr->mem.tavor.mpt = dev->mr_table.tavor_fmr.mpt_base +
-		       	sizeof *(mr->mem.tavor.mpt) * idx;
+			sizeof *(mr->mem.tavor.mpt) * idx;
 
 	mr->mtt = __mthca_alloc_mtt(dev, list_len, dev->mr_table.fmr_mtt_buddy);
 	if (IS_ERR(mr->mtt))
@@ -549,7 +555,7 @@
 				       MTHCA_MPT_FLAG_REGION      |
 				       access);
 
-	mpt_entry->page_size = cpu_to_be32(mr->attr.page_size - 12);
+	mpt_entry->page_size = cpu_to_be32(mr->attr.page_shift - 12);
 	mpt_entry->key       = cpu_to_be32(key);
 	mpt_entry->pd        = cpu_to_be32(pd);
 	memset(&mpt_entry->start, 0,
@@ -617,7 +623,7 @@
 	if (list_len > fmr->attr.max_pages)
 		return -EINVAL;
 
-	page_mask = (1 << fmr->attr.page_size) - 1;
+	page_mask = (1 << fmr->attr.page_shift) - 1;
 
 	/* We are getting page lists, so va must be page aligned. */
 	if (iova & page_mask)
@@ -665,7 +671,7 @@
 	}
 
 	mpt_entry.lkey   = cpu_to_be32(key);
-	mpt_entry.length = cpu_to_be64(list_len * (1ull << fmr->attr.page_size));
+	mpt_entry.length = cpu_to_be64(list_len * (1ull << fmr->attr.page_shift));
 	mpt_entry.start  = cpu_to_be64(iova);
 
 	__raw_writel((__force u32) mpt_entry.lkey, &fmr->mem.tavor.mpt->key);
@@ -693,7 +699,10 @@
 	++fmr->maps;
 
 	key = arbel_key_to_hw_index(fmr->ibmr.lkey);
-	key += dev->limits.num_mpts;
+	if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT)
+		key += SINAI_FMR_KEY_INC;
+	else
+		key += dev->limits.num_mpts;
 	fmr->ibmr.lkey = fmr->ibmr.rkey = arbel_hw_index_to_key(key);
 
 	*(u8 *) fmr->mem.arbel.mpt = MTHCA_MPT_STATUS_SW;
@@ -706,7 +715,7 @@
 
 	fmr->mem.arbel.mpt->key    = cpu_to_be32(key);
 	fmr->mem.arbel.mpt->lkey   = cpu_to_be32(key);
-	fmr->mem.arbel.mpt->length = cpu_to_be64(list_len * (1ull << fmr->attr.page_size));
+	fmr->mem.arbel.mpt->length = cpu_to_be64(list_len * (1ull << fmr->attr.page_shift));
 	fmr->mem.arbel.mpt->start  = cpu_to_be64(iova);
 
 	wmb();
@@ -766,6 +775,9 @@
 	else
 		dev->mthca_flags |= MTHCA_FLAG_FMR;
 
+	if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT)
+		mthca_dbg(dev, "Memory key throughput optimization activated.\n");
+
 	err = mthca_buddy_init(&dev->mr_table.mtt_buddy,
 			       fls(dev->limits.num_mtt_segs - 1));
 
@@ -785,7 +797,7 @@
 		}
 
 		dev->mr_table.tavor_fmr.mpt_base =
-		       	ioremap(dev->mr_table.mpt_base,
+			ioremap(dev->mr_table.mpt_base,
 				(1 << i) * sizeof (struct mthca_mpt_entry));
 
 		if (!dev->mr_table.tavor_fmr.mpt_base) {
@@ -813,7 +825,7 @@
 			goto err_reserve_fmr;
 
 		dev->mr_table.fmr_mtt_buddy =
-		       	&dev->mr_table.tavor_fmr.mtt_buddy;
+			&dev->mr_table.tavor_fmr.mtt_buddy;
 	} else
 		dev->mr_table.fmr_mtt_buddy = &dev->mr_table.mtt_buddy;
 
diff --git a/drivers/infiniband/hw/mthca/mthca_pd.c b/drivers/infiniband/hw/mthca/mthca_pd.c
index 3dbf06a..105fc5f 100644
--- a/drivers/infiniband/hw/mthca/mthca_pd.c
+++ b/drivers/infiniband/hw/mthca/mthca_pd.c
@@ -43,8 +43,6 @@
 {
 	int err = 0;
 
-	might_sleep();
-
 	pd->privileged = privileged;
 
 	atomic_set(&pd->sqp_count, 0);
@@ -66,7 +64,6 @@
 
 void mthca_pd_free(struct mthca_dev *dev, struct mthca_pd *pd)
 {
-	might_sleep();
 	if (pd->privileged)
 		mthca_free_mr(dev, &pd->ntmr);
 	mthca_free(&dev->pd_table.alloc, pd->pd_num);
diff --git a/drivers/infiniband/hw/mthca/mthca_profile.c b/drivers/infiniband/hw/mthca/mthca_profile.c
index 08a9093..58d44aa 100644
--- a/drivers/infiniband/hw/mthca/mthca_profile.c
+++ b/drivers/infiniband/hw/mthca/mthca_profile.c
@@ -152,7 +152,7 @@
 		}
 		if (total_size > mem_avail) {
 			mthca_err(dev, "Profile requires 0x%llx bytes; "
-				  "won't in 0x%llx bytes of context memory.\n",
+				  "won't fit in 0x%llx bytes of context memory.\n",
 				  (unsigned long long) total_size,
 				  (unsigned long long) mem_avail);
 			kfree(profile);
@@ -262,6 +262,14 @@
 	 */
 	dev->limits.num_pds = MTHCA_NUM_PDS;
 
+	if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT &&
+	    init_hca->log_mpt_sz > 23) {
+		mthca_warn(dev, "MPT table too large (requested size 2^%d >= 2^24)\n",
+			   init_hca->log_mpt_sz);
+		mthca_warn(dev, "Disabling memory key throughput optimization.\n");
+		dev->mthca_flags &= ~MTHCA_FLAG_SINAI_OPT;
+	}
+
 	/*
 	 * For Tavor, FMRs use ioremapped PCI memory. For 32 bit
 	 * systems it may use too much vmalloc space to map all MTT
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
index e88e39a..2c250bc 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
- * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
  *
@@ -108,12 +108,12 @@
 	props->max_srq_wr          = mdev->limits.max_srq_wqes;
 	props->max_srq_sge         = mdev->limits.max_sg;
 	props->local_ca_ack_delay  = mdev->limits.local_ca_ack_delay;
-	props->atomic_cap          = mdev->limits.flags & DEV_LIM_FLAG_ATOMIC ? 
+	props->atomic_cap          = mdev->limits.flags & DEV_LIM_FLAG_ATOMIC ?
 					IB_ATOMIC_HCA : IB_ATOMIC_NONE;
 	props->max_pkeys           = mdev->limits.pkey_table_len;
 	props->max_mcast_grp       = mdev->limits.num_mgms + mdev->limits.num_amgms;
 	props->max_mcast_qp_attach = MTHCA_QP_PER_MGM;
-	props->max_total_mcast_qp_attach = props->max_mcast_qp_attach * 
+	props->max_total_mcast_qp_attach = props->max_mcast_qp_attach *
 					   props->max_mcast_grp;
 
 	err = 0;
@@ -176,6 +176,23 @@
 	return err;
 }
 
+static int mthca_modify_device(struct ib_device *ibdev,
+			       int mask,
+			       struct ib_device_modify *props)
+{
+	if (mask & ~IB_DEVICE_MODIFY_NODE_DESC)
+		return -EOPNOTSUPP;
+
+	if (mask & IB_DEVICE_MODIFY_NODE_DESC) {
+		if (mutex_lock_interruptible(&to_mdev(ibdev)->cap_mask_mutex))
+			return -ERESTARTSYS;
+		memcpy(ibdev->node_desc, props->node_desc, 64);
+		mutex_unlock(&to_mdev(ibdev)->cap_mask_mutex);
+	}
+
+	return 0;
+}
+
 static int mthca_modify_port(struct ib_device *ibdev,
 			     u8 port, int port_modify_mask,
 			     struct ib_port_modify *props)
@@ -669,9 +686,9 @@
 	}
 
 	if (context) {
-		cq->mr.ibmr.lkey    = ucmd.lkey;
-		cq->set_ci_db_index = ucmd.set_db_index;
-		cq->arm_db_index    = ucmd.arm_db_index;
+		cq->buf.mr.ibmr.lkey = ucmd.lkey;
+		cq->set_ci_db_index  = ucmd.set_db_index;
+		cq->arm_db_index     = ucmd.arm_db_index;
 	}
 
 	for (nent = 1; nent <= entries; nent <<= 1)
@@ -689,6 +706,8 @@
 		goto err_free;
 	}
 
+	cq->resize_buf = NULL;
+
 	return &cq->ibcq;
 
 err_free:
@@ -707,6 +726,121 @@
 	return ERR_PTR(err);
 }
 
+static int mthca_alloc_resize_buf(struct mthca_dev *dev, struct mthca_cq *cq,
+				  int entries)
+{
+	int ret;
+
+	spin_lock_irq(&cq->lock);
+	if (cq->resize_buf) {
+		ret = -EBUSY;
+		goto unlock;
+	}
+
+	cq->resize_buf = kmalloc(sizeof *cq->resize_buf, GFP_ATOMIC);
+	if (!cq->resize_buf) {
+		ret = -ENOMEM;
+		goto unlock;
+	}
+
+	cq->resize_buf->state = CQ_RESIZE_ALLOC;
+
+	ret = 0;
+
+unlock:
+	spin_unlock_irq(&cq->lock);
+
+	if (ret)
+		return ret;
+
+	ret = mthca_alloc_cq_buf(dev, &cq->resize_buf->buf, entries);
+	if (ret) {
+		spin_lock_irq(&cq->lock);
+		kfree(cq->resize_buf);
+		cq->resize_buf = NULL;
+		spin_unlock_irq(&cq->lock);
+		return ret;
+	}
+
+	cq->resize_buf->cqe = entries - 1;
+
+	spin_lock_irq(&cq->lock);
+	cq->resize_buf->state = CQ_RESIZE_READY;
+	spin_unlock_irq(&cq->lock);
+
+	return 0;
+}
+
+static int mthca_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)
+{
+	struct mthca_dev *dev = to_mdev(ibcq->device);
+	struct mthca_cq *cq = to_mcq(ibcq);
+	struct mthca_resize_cq ucmd;
+	u32 lkey;
+	u8 status;
+	int ret;
+
+	if (entries < 1 || entries > dev->limits.max_cqes)
+		return -EINVAL;
+
+	entries = roundup_pow_of_two(entries + 1);
+	if (entries == ibcq->cqe + 1)
+		return 0;
+
+	if (cq->is_kernel) {
+		ret = mthca_alloc_resize_buf(dev, cq, entries);
+		if (ret)
+			return ret;
+		lkey = cq->resize_buf->buf.mr.ibmr.lkey;
+	} else {
+		if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd))
+			return -EFAULT;
+		lkey = ucmd.lkey;
+	}
+
+	ret = mthca_RESIZE_CQ(dev, cq->cqn, lkey, long_log2(entries), &status);
+	if (status)
+		ret = -EINVAL;
+
+	if (ret) {
+		if (cq->resize_buf) {
+			mthca_free_cq_buf(dev, &cq->resize_buf->buf,
+					  cq->resize_buf->cqe);
+			kfree(cq->resize_buf);
+			spin_lock_irq(&cq->lock);
+			cq->resize_buf = NULL;
+			spin_unlock_irq(&cq->lock);
+		}
+		return ret;
+	}
+
+	if (cq->is_kernel) {
+		struct mthca_cq_buf tbuf;
+		int tcqe;
+
+		spin_lock_irq(&cq->lock);
+		if (cq->resize_buf->state == CQ_RESIZE_READY) {
+			mthca_cq_resize_copy_cqes(cq);
+			tbuf         = cq->buf;
+			tcqe         = cq->ibcq.cqe;
+			cq->buf      = cq->resize_buf->buf;
+			cq->ibcq.cqe = cq->resize_buf->cqe;
+		} else {
+			tbuf = cq->resize_buf->buf;
+			tcqe = cq->resize_buf->cqe;
+		}
+
+		kfree(cq->resize_buf);
+		cq->resize_buf = NULL;
+		spin_unlock_irq(&cq->lock);
+
+		mthca_free_cq_buf(dev, &tbuf, tcqe);
+	} else
+		ibcq->cqe = entries - 1;
+
+	return 0;
+}
+
 static int mthca_destroy_cq(struct ib_cq *cq)
 {
 	if (cq->uobject) {
@@ -1070,6 +1204,20 @@
 		goto out;
 
 	init_query_mad(in_mad);
+	in_mad->attr_id = IB_SMP_ATTR_NODE_DESC;
+
+	err = mthca_MAD_IFC(dev, 1, 1,
+			    1, NULL, NULL, in_mad, out_mad,
+			    &status);
+	if (err)
+		goto out;
+	if (status) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	memcpy(dev->ib_dev.node_desc, out_mad->data, 64);
+
 	in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;
 
 	err = mthca_MAD_IFC(dev, 1, 1,
@@ -1113,14 +1261,17 @@
 		(1ull << IB_USER_VERBS_CMD_DEREG_MR)		|
 		(1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL)	|
 		(1ull << IB_USER_VERBS_CMD_CREATE_CQ)		|
+		(1ull << IB_USER_VERBS_CMD_RESIZE_CQ)		|
 		(1ull << IB_USER_VERBS_CMD_DESTROY_CQ)		|
 		(1ull << IB_USER_VERBS_CMD_CREATE_QP)		|
+		(1ull << IB_USER_VERBS_CMD_QUERY_QP)		|
 		(1ull << IB_USER_VERBS_CMD_MODIFY_QP)		|
 		(1ull << IB_USER_VERBS_CMD_DESTROY_QP)		|
 		(1ull << IB_USER_VERBS_CMD_ATTACH_MCAST)	|
 		(1ull << IB_USER_VERBS_CMD_DETACH_MCAST)	|
 		(1ull << IB_USER_VERBS_CMD_CREATE_SRQ)		|
 		(1ull << IB_USER_VERBS_CMD_MODIFY_SRQ)		|
+		(1ull << IB_USER_VERBS_CMD_QUERY_SRQ)		|
 		(1ull << IB_USER_VERBS_CMD_DESTROY_SRQ);
 	dev->ib_dev.node_type            = IB_NODE_CA;
 	dev->ib_dev.phys_port_cnt        = dev->limits.num_ports;
@@ -1128,6 +1279,7 @@
 	dev->ib_dev.class_dev.dev        = &dev->pdev->dev;
 	dev->ib_dev.query_device         = mthca_query_device;
 	dev->ib_dev.query_port           = mthca_query_port;
+	dev->ib_dev.modify_device        = mthca_modify_device;
 	dev->ib_dev.modify_port          = mthca_modify_port;
 	dev->ib_dev.query_pkey           = mthca_query_pkey;
 	dev->ib_dev.query_gid            = mthca_query_gid;
@@ -1137,11 +1289,13 @@
 	dev->ib_dev.alloc_pd             = mthca_alloc_pd;
 	dev->ib_dev.dealloc_pd           = mthca_dealloc_pd;
 	dev->ib_dev.create_ah            = mthca_ah_create;
+	dev->ib_dev.query_ah             = mthca_ah_query;
 	dev->ib_dev.destroy_ah           = mthca_ah_destroy;
 
 	if (dev->mthca_flags & MTHCA_FLAG_SRQ) {
 		dev->ib_dev.create_srq           = mthca_create_srq;
-		dev->ib_dev.modify_srq		 = mthca_modify_srq;
+		dev->ib_dev.modify_srq           = mthca_modify_srq;
+		dev->ib_dev.query_srq            = mthca_query_srq;
 		dev->ib_dev.destroy_srq          = mthca_destroy_srq;
 
 		if (mthca_is_memfree(dev))
@@ -1152,8 +1306,10 @@
 
 	dev->ib_dev.create_qp            = mthca_create_qp;
 	dev->ib_dev.modify_qp            = mthca_modify_qp;
+	dev->ib_dev.query_qp             = mthca_query_qp;
 	dev->ib_dev.destroy_qp           = mthca_destroy_qp;
 	dev->ib_dev.create_cq            = mthca_create_cq;
+	dev->ib_dev.resize_cq            = mthca_resize_cq;
 	dev->ib_dev.destroy_cq           = mthca_destroy_cq;
 	dev->ib_dev.poll_cq              = mthca_poll_cq;
 	dev->ib_dev.get_dma_mr           = mthca_get_dma_mr;
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.h b/drivers/infiniband/hw/mthca/mthca_provider.h
index 1e73947..2e7f521 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.h
+++ b/drivers/infiniband/hw/mthca/mthca_provider.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  *
  * This software is available to you under a choice of one of two
@@ -164,9 +164,11 @@
  * - wait_event until ref count is zero
  *
  * It is the consumer's responsibilty to make sure that no QP
- * operations (WQE posting or state modification) are pending when the
+ * operations (WQE posting or state modification) are pending when a
  * QP is destroyed.  Also, the consumer must make sure that calls to
- * qp_modify are serialized.
+ * qp_modify are serialized.  Similarly, the consumer is responsible
+ * for ensuring that no CQ resize operations are pending when a CQ
+ * is destroyed.
  *
  * Possible optimizations (wait for profile data to see if/where we
  * have locks bouncing between CPUs):
@@ -176,25 +178,40 @@
  *   send queue and one for the receive queue)
  */
 
+struct mthca_cq_buf {
+	union mthca_buf		queue;
+	struct mthca_mr		mr;
+	int			is_direct;
+};
+
+struct mthca_cq_resize {
+	struct mthca_cq_buf	buf;
+	int			cqe;
+	enum {
+		CQ_RESIZE_ALLOC,
+		CQ_RESIZE_READY,
+		CQ_RESIZE_SWAPPED
+	}			state;
+};
+
 struct mthca_cq {
-	struct ib_cq           ibcq;
-	spinlock_t             lock;
-	atomic_t               refcount;
-	int                    cqn;
-	u32                    cons_index;
-	int                    is_direct;
-	int                    is_kernel;
+	struct ib_cq		ibcq;
+	spinlock_t		lock;
+	atomic_t		refcount;
+	int			cqn;
+	u32			cons_index;
+	struct mthca_cq_buf	buf;
+	struct mthca_cq_resize *resize_buf;
+	int			is_kernel;
 
 	/* Next fields are Arbel only */
-	int                    set_ci_db_index;
-	__be32                *set_ci_db;
-	int                    arm_db_index;
-	__be32                *arm_db;
-	int                    arm_sn;
+	int			set_ci_db_index;
+	__be32		       *set_ci_db;
+	int			arm_db_index;
+	__be32		       *arm_db;
+	int			arm_sn;
 
-	union mthca_buf        queue;
-	struct mthca_mr        mr;
-	wait_queue_head_t      wait;
+	wait_queue_head_t	wait;
 };
 
 struct mthca_srq {
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c
index fba608e..f673c46 100644
--- a/drivers/infiniband/hw/mthca/mthca_qp.c
+++ b/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -2,7 +2,7 @@
  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Cisco Systems. All rights reserved.
  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
- * Copyright (c) 2004 Voltaire, Inc. All rights reserved. 
+ * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -286,207 +286,6 @@
 	}
 }
 
-static const struct {
-	int trans;
-	u32 req_param[NUM_TRANS];
-	u32 opt_param[NUM_TRANS];
-} state_table[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = {
-	[IB_QPS_RESET] = {
-		[IB_QPS_RESET] = { .trans = MTHCA_TRANS_ANY2RST },
-		[IB_QPS_ERR] = { .trans = MTHCA_TRANS_ANY2ERR },
-		[IB_QPS_INIT]  = {
-			.trans = MTHCA_TRANS_RST2INIT,
-			.req_param = {
-				[UD]  = (IB_QP_PKEY_INDEX |
-					 IB_QP_PORT       |
-					 IB_QP_QKEY),
-				[UC]  = (IB_QP_PKEY_INDEX |
-					 IB_QP_PORT       |
-					 IB_QP_ACCESS_FLAGS),
-				[RC]  = (IB_QP_PKEY_INDEX |
-					 IB_QP_PORT       |
-					 IB_QP_ACCESS_FLAGS),
-				[MLX] = (IB_QP_PKEY_INDEX |
-					 IB_QP_QKEY),
-			},
-			/* bug-for-bug compatibility with VAPI: */
-			.opt_param = {
-				[MLX] = IB_QP_PORT
-			}
-		},
-	},
-	[IB_QPS_INIT]  = {
-		[IB_QPS_RESET] = { .trans = MTHCA_TRANS_ANY2RST },
-		[IB_QPS_ERR] = { .trans = MTHCA_TRANS_ANY2ERR },
-		[IB_QPS_INIT]  = {
-			.trans = MTHCA_TRANS_INIT2INIT,
-			.opt_param = {
-				[UD]  = (IB_QP_PKEY_INDEX |
-					 IB_QP_PORT       |
-					 IB_QP_QKEY),
-				[UC]  = (IB_QP_PKEY_INDEX |
-					 IB_QP_PORT       |
-					 IB_QP_ACCESS_FLAGS),
-				[RC]  = (IB_QP_PKEY_INDEX |
-					 IB_QP_PORT       |
-					 IB_QP_ACCESS_FLAGS),
-				[MLX] = (IB_QP_PKEY_INDEX |
-					 IB_QP_QKEY),
-			}
-		},
-		[IB_QPS_RTR]   = {
-			.trans = MTHCA_TRANS_INIT2RTR,
-			.req_param = {
-				[UC]  = (IB_QP_AV                  |
-					 IB_QP_PATH_MTU            |
-					 IB_QP_DEST_QPN            |
-					 IB_QP_RQ_PSN),
-				[RC]  = (IB_QP_AV                  |
-					 IB_QP_PATH_MTU            |
-					 IB_QP_DEST_QPN            |
-					 IB_QP_RQ_PSN              |
-					 IB_QP_MAX_DEST_RD_ATOMIC  |
-					 IB_QP_MIN_RNR_TIMER),
-			},
-			.opt_param = {
-				[UD]  = (IB_QP_PKEY_INDEX |
-					 IB_QP_QKEY),
-				[UC]  = (IB_QP_ALT_PATH     |
-					 IB_QP_ACCESS_FLAGS |
-					 IB_QP_PKEY_INDEX),
-				[RC]  = (IB_QP_ALT_PATH     |
-					 IB_QP_ACCESS_FLAGS |
-					 IB_QP_PKEY_INDEX),
-				[MLX] = (IB_QP_PKEY_INDEX |
-					 IB_QP_QKEY),
-			}
-		}
-	},
-	[IB_QPS_RTR]   = {
-		[IB_QPS_RESET] = { .trans = MTHCA_TRANS_ANY2RST },
-		[IB_QPS_ERR] = { .trans = MTHCA_TRANS_ANY2ERR },
-		[IB_QPS_RTS]   = {
-			.trans = MTHCA_TRANS_RTR2RTS,
-			.req_param = {
-				[UD]  = IB_QP_SQ_PSN,
-				[UC]  = IB_QP_SQ_PSN,
-				[RC]  = (IB_QP_TIMEOUT           |
-					 IB_QP_RETRY_CNT         |
-					 IB_QP_RNR_RETRY         |
-					 IB_QP_SQ_PSN            |
-					 IB_QP_MAX_QP_RD_ATOMIC),
-				[MLX] = IB_QP_SQ_PSN,
-			},
-			.opt_param = {
-				[UD]  = (IB_QP_CUR_STATE             |
-					 IB_QP_QKEY),
-				[UC]  = (IB_QP_CUR_STATE             |
-					 IB_QP_ALT_PATH              |
-					 IB_QP_ACCESS_FLAGS          |
-					 IB_QP_PATH_MIG_STATE),
-				[RC]  = (IB_QP_CUR_STATE             |
-					 IB_QP_ALT_PATH              |
-					 IB_QP_ACCESS_FLAGS          |
-					 IB_QP_MIN_RNR_TIMER         |
-					 IB_QP_PATH_MIG_STATE),
-				[MLX] = (IB_QP_CUR_STATE             |
-					 IB_QP_QKEY),
-			}
-		}
-	},
-	[IB_QPS_RTS]   = {
-		[IB_QPS_RESET] = { .trans = MTHCA_TRANS_ANY2RST },
-		[IB_QPS_ERR] = { .trans = MTHCA_TRANS_ANY2ERR },
-		[IB_QPS_RTS]   = {
-			.trans = MTHCA_TRANS_RTS2RTS,
-			.opt_param = {
-				[UD]  = (IB_QP_CUR_STATE             |
-					 IB_QP_QKEY),
-				[UC]  = (IB_QP_ACCESS_FLAGS          |
-					 IB_QP_ALT_PATH              |
-					 IB_QP_PATH_MIG_STATE),
-				[RC]  = (IB_QP_ACCESS_FLAGS          |
-					 IB_QP_ALT_PATH              |
-					 IB_QP_PATH_MIG_STATE        |
-					 IB_QP_MIN_RNR_TIMER),
-				[MLX] = (IB_QP_CUR_STATE             |
-					 IB_QP_QKEY),
-			}
-		},
-		[IB_QPS_SQD]   = {
-			.trans = MTHCA_TRANS_RTS2SQD,
-		},
-	},
-	[IB_QPS_SQD]   = {
-		[IB_QPS_RESET] = { .trans = MTHCA_TRANS_ANY2RST },
-		[IB_QPS_ERR] = { .trans = MTHCA_TRANS_ANY2ERR },
-		[IB_QPS_RTS]   = {
-			.trans = MTHCA_TRANS_SQD2RTS,
-			.opt_param = {
-				[UD]  = (IB_QP_CUR_STATE             |
-					 IB_QP_QKEY),
-				[UC]  = (IB_QP_CUR_STATE             |
-					 IB_QP_ALT_PATH              |
-					 IB_QP_ACCESS_FLAGS          |
-					 IB_QP_PATH_MIG_STATE),
-				[RC]  = (IB_QP_CUR_STATE             |
-					 IB_QP_ALT_PATH              |
-					 IB_QP_ACCESS_FLAGS          |
-					 IB_QP_MIN_RNR_TIMER         |
-					 IB_QP_PATH_MIG_STATE),
-				[MLX] = (IB_QP_CUR_STATE             |
-					 IB_QP_QKEY),
-			}
-		},
-		[IB_QPS_SQD]   = {
-			.trans = MTHCA_TRANS_SQD2SQD,
-			.opt_param = {
-				[UD]  = (IB_QP_PKEY_INDEX            |
-					 IB_QP_QKEY),
-				[UC]  = (IB_QP_AV                    |
-					 IB_QP_CUR_STATE             |
-					 IB_QP_ALT_PATH              |
-					 IB_QP_ACCESS_FLAGS          |
-					 IB_QP_PKEY_INDEX            |
-					 IB_QP_PATH_MIG_STATE),
-				[RC]  = (IB_QP_AV                    |
-					 IB_QP_TIMEOUT               |
-					 IB_QP_RETRY_CNT             |
-					 IB_QP_RNR_RETRY             |
-					 IB_QP_MAX_QP_RD_ATOMIC      |
-					 IB_QP_MAX_DEST_RD_ATOMIC    |
-					 IB_QP_CUR_STATE             |
-					 IB_QP_ALT_PATH              |
-					 IB_QP_ACCESS_FLAGS          |
-					 IB_QP_PKEY_INDEX            |
-					 IB_QP_MIN_RNR_TIMER         |
-					 IB_QP_PATH_MIG_STATE),
-				[MLX] = (IB_QP_PKEY_INDEX            |
-					 IB_QP_QKEY),
-			}
-		}
-	},
-	[IB_QPS_SQE]   = {
-		[IB_QPS_RESET] = { .trans = MTHCA_TRANS_ANY2RST },
-		[IB_QPS_ERR] = { .trans = MTHCA_TRANS_ANY2ERR },
-		[IB_QPS_RTS]   = {
-			.trans = MTHCA_TRANS_SQERR2RTS,
-			.opt_param = {
-				[UD]  = (IB_QP_CUR_STATE             |
-					 IB_QP_QKEY),
-				[UC]  = (IB_QP_CUR_STATE             |
-					 IB_QP_ACCESS_FLAGS),
-				[MLX] = (IB_QP_CUR_STATE             |
-					 IB_QP_QKEY),
-			}
-		}
-	},
-	[IB_QPS_ERR] = {
-		[IB_QPS_RESET] = { .trans = MTHCA_TRANS_ANY2RST },
-		[IB_QPS_ERR] = { .trans = MTHCA_TRANS_ANY2ERR }
-	}
-};
-
 static void store_attrs(struct mthca_sqp *sqp, struct ib_qp_attr *attr,
 			int attr_mask)
 {
@@ -549,6 +348,141 @@
 	return cpu_to_be32(hw_access_flags);
 }
 
+static inline enum ib_qp_state to_ib_qp_state(int mthca_state)
+{
+	switch (mthca_state) {
+	case MTHCA_QP_STATE_RST:      return IB_QPS_RESET;
+	case MTHCA_QP_STATE_INIT:     return IB_QPS_INIT;
+	case MTHCA_QP_STATE_RTR:      return IB_QPS_RTR;
+	case MTHCA_QP_STATE_RTS:      return IB_QPS_RTS;
+	case MTHCA_QP_STATE_DRAINING:
+	case MTHCA_QP_STATE_SQD:      return IB_QPS_SQD;
+	case MTHCA_QP_STATE_SQE:      return IB_QPS_SQE;
+	case MTHCA_QP_STATE_ERR:      return IB_QPS_ERR;
+	default:                      return -1;
+	}
+}
+
+static inline enum ib_mig_state to_ib_mig_state(int mthca_mig_state)
+{
+	switch (mthca_mig_state) {
+	case 0:  return IB_MIG_ARMED;
+	case 1:  return IB_MIG_REARM;
+	case 3:  return IB_MIG_MIGRATED;
+	default: return -1;
+	}
+}
+
+static int to_ib_qp_access_flags(int mthca_flags)
+{
+	int ib_flags = 0;
+
+	if (mthca_flags & MTHCA_QP_BIT_RRE)
+		ib_flags |= IB_ACCESS_REMOTE_READ;
+	if (mthca_flags & MTHCA_QP_BIT_RWE)
+		ib_flags |= IB_ACCESS_REMOTE_WRITE;
+	if (mthca_flags & MTHCA_QP_BIT_RAE)
+		ib_flags |= IB_ACCESS_REMOTE_ATOMIC;
+
+	return ib_flags;
+}
+
+static void to_ib_ah_attr(struct mthca_dev *dev, struct ib_ah_attr *ib_ah_attr,
+				struct mthca_qp_path *path)
+{
+	memset(ib_ah_attr, 0, sizeof *path);
+	ib_ah_attr->port_num 	  = (be32_to_cpu(path->port_pkey) >> 24) & 0x3;
+	ib_ah_attr->dlid     	  = be16_to_cpu(path->rlid);
+	ib_ah_attr->sl       	  = be32_to_cpu(path->sl_tclass_flowlabel) >> 28;
+	ib_ah_attr->src_path_bits = path->g_mylmc & 0x7f;
+	ib_ah_attr->static_rate   = path->static_rate & 0x7;
+	ib_ah_attr->ah_flags      = (path->g_mylmc & (1 << 7)) ? IB_AH_GRH : 0;
+	if (ib_ah_attr->ah_flags) {
+		ib_ah_attr->grh.sgid_index = path->mgid_index & (dev->limits.gid_table_len - 1);
+		ib_ah_attr->grh.hop_limit  = path->hop_limit;
+		ib_ah_attr->grh.traffic_class =
+			(be32_to_cpu(path->sl_tclass_flowlabel) >> 20) & 0xff;
+		ib_ah_attr->grh.flow_label =
+			be32_to_cpu(path->sl_tclass_flowlabel) & 0xfffff;
+		memcpy(ib_ah_attr->grh.dgid.raw,
+			path->rgid, sizeof ib_ah_attr->grh.dgid.raw);
+	}
+}
+
+int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask,
+		   struct ib_qp_init_attr *qp_init_attr)
+{
+	struct mthca_dev *dev = to_mdev(ibqp->device);
+	struct mthca_qp *qp = to_mqp(ibqp);
+	int err;
+	struct mthca_mailbox *mailbox;
+	struct mthca_qp_param *qp_param;
+	struct mthca_qp_context *context;
+	int mthca_state;
+	u8 status;
+
+	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+	if (IS_ERR(mailbox))
+		return PTR_ERR(mailbox);
+
+	err = mthca_QUERY_QP(dev, qp->qpn, 0, mailbox, &status);
+	if (err)
+		goto out;
+	if (status) {
+		mthca_warn(dev, "QUERY_QP returned status %02x\n", status);
+		err = -EINVAL;
+		goto out;
+	}
+
+	qp_param    = mailbox->buf;
+	context     = &qp_param->context;
+	mthca_state = be32_to_cpu(context->flags) >> 28;
+
+	qp_attr->qp_state 	     = to_ib_qp_state(mthca_state);
+	qp_attr->cur_qp_state 	     = qp_attr->qp_state;
+	qp_attr->path_mtu 	     = context->mtu_msgmax >> 5;
+	qp_attr->path_mig_state      =
+		to_ib_mig_state((be32_to_cpu(context->flags) >> 11) & 0x3);
+	qp_attr->qkey 		     = be32_to_cpu(context->qkey);
+	qp_attr->rq_psn 	     = be32_to_cpu(context->rnr_nextrecvpsn) & 0xffffff;
+	qp_attr->sq_psn 	     = be32_to_cpu(context->next_send_psn) & 0xffffff;
+	qp_attr->dest_qp_num 	     = be32_to_cpu(context->remote_qpn) & 0xffffff;
+	qp_attr->qp_access_flags     =
+		to_ib_qp_access_flags(be32_to_cpu(context->params2));
+	qp_attr->cap.max_send_wr     = qp->sq.max;
+	qp_attr->cap.max_recv_wr     = qp->rq.max;
+	qp_attr->cap.max_send_sge    = qp->sq.max_gs;
+	qp_attr->cap.max_recv_sge    = qp->rq.max_gs;
+	qp_attr->cap.max_inline_data = qp->max_inline_data;
+
+	to_ib_ah_attr(dev, &qp_attr->ah_attr, &context->pri_path);
+	to_ib_ah_attr(dev, &qp_attr->alt_ah_attr, &context->alt_path);
+
+	qp_attr->pkey_index     = be32_to_cpu(context->pri_path.port_pkey) & 0x7f;
+	qp_attr->alt_pkey_index = be32_to_cpu(context->alt_path.port_pkey) & 0x7f;
+
+	/* qp_attr->en_sqd_async_notify is only applicable in modify qp */
+	qp_attr->sq_draining = mthca_state == MTHCA_QP_STATE_DRAINING;
+
+	qp_attr->max_rd_atomic = 1 << ((be32_to_cpu(context->params1) >> 21) & 0x7);
+
+	qp_attr->max_dest_rd_atomic =
+		1 << ((be32_to_cpu(context->params2) >> 21) & 0x7);
+	qp_attr->min_rnr_timer 	    =
+		(be32_to_cpu(context->rnr_nextrecvpsn) >> 24) & 0x1f;
+	qp_attr->port_num 	    = qp_attr->ah_attr.port_num;
+	qp_attr->timeout 	    = context->pri_path.ackto >> 3;
+	qp_attr->retry_cnt 	    = (be32_to_cpu(context->params1) >> 16) & 0x7;
+	qp_attr->rnr_retry 	    = context->pri_path.rnr_retry >> 5;
+	qp_attr->alt_port_num 	    = qp_attr->alt_ah_attr.port_num;
+	qp_attr->alt_timeout 	    = context->alt_path.ackto >> 3;
+	qp_init_attr->cap 	    = qp_attr->cap;
+
+out:
+	mthca_free_mailbox(dev, mailbox);
+	return err;
+}
+
 static void mthca_path_set(struct ib_ah_attr *ah, struct mthca_qp_path *path)
 {
 	path->g_mylmc     = ah->src_path_bits & 0x7f;
@@ -559,9 +493,9 @@
 		path->g_mylmc   |= 1 << 7;
 		path->mgid_index = ah->grh.sgid_index;
 		path->hop_limit  = ah->grh.hop_limit;
-		path->sl_tclass_flowlabel = 
+		path->sl_tclass_flowlabel =
 			cpu_to_be32((ah->sl << 28)                |
-				    (ah->grh.traffic_class << 20) | 
+				    (ah->grh.traffic_class << 20) |
 				    (ah->grh.flow_label));
 		memcpy(path->rgid, ah->grh.dgid.raw, 16);
 	} else
@@ -576,18 +510,12 @@
 	struct mthca_mailbox *mailbox;
 	struct mthca_qp_param *qp_param;
 	struct mthca_qp_context *qp_context;
-	u32 req_param, opt_param;
+	u32 sqd_event = 0;
 	u8 status;
 	int err;
 
 	if (attr_mask & IB_QP_CUR_STATE) {
-		if (attr->cur_qp_state != IB_QPS_RTR &&
-		    attr->cur_qp_state != IB_QPS_RTS &&
-		    attr->cur_qp_state != IB_QPS_SQD &&
-		    attr->cur_qp_state != IB_QPS_SQE)
-			return -EINVAL;
-		else
-			cur_state = attr->cur_qp_state;
+		cur_state = attr->cur_qp_state;
 	} else {
 		spin_lock_irq(&qp->sq.lock);
 		spin_lock(&qp->rq.lock);
@@ -596,44 +524,20 @@
 		spin_unlock_irq(&qp->sq.lock);
 	}
 
-	if (attr_mask & IB_QP_STATE) {
-               if (attr->qp_state < 0 || attr->qp_state > IB_QPS_ERR)
-			return -EINVAL;
-		new_state = attr->qp_state;
-	} else
-		new_state = cur_state;
+	new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state;
 
-	if (state_table[cur_state][new_state].trans == MTHCA_TRANS_INVALID) {
-		mthca_dbg(dev, "Illegal QP transition "
-			  "%d->%d\n", cur_state, new_state);
+	if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type, attr_mask)) {
+		mthca_dbg(dev, "Bad QP transition (transport %d) "
+			  "%d->%d with attr 0x%08x\n",
+			  qp->transport, cur_state, new_state,
+			  attr_mask);
 		return -EINVAL;
 	}
 
-	req_param = state_table[cur_state][new_state].req_param[qp->transport];
-	opt_param = state_table[cur_state][new_state].opt_param[qp->transport];
-
-	if ((req_param & attr_mask) != req_param) {
-		mthca_dbg(dev, "QP transition "
-			  "%d->%d missing req attr 0x%08x\n",
-			  cur_state, new_state,
-			  req_param & ~attr_mask);
-		return -EINVAL;
-	}
-
-	if (attr_mask & ~(req_param | opt_param | IB_QP_STATE)) {
-		mthca_dbg(dev, "QP transition (transport %d) "
-			  "%d->%d has extra attr 0x%08x\n",
-			  qp->transport,
-			  cur_state, new_state,
-			  attr_mask & ~(req_param | opt_param |
-						 IB_QP_STATE));
-		return -EINVAL;
-	}
-
-	if ((attr_mask & IB_QP_PKEY_INDEX) && 
+	if ((attr_mask & IB_QP_PKEY_INDEX) &&
 	     attr->pkey_index >= dev->limits.pkey_table_len) {
-		mthca_dbg(dev, "PKey index (%u) too large. max is %d\n",
-			  attr->pkey_index,dev->limits.pkey_table_len-1); 
+		mthca_dbg(dev, "P_Key index (%u) too large. max is %d\n",
+			  attr->pkey_index, dev->limits.pkey_table_len-1);
 		return -EINVAL;
 	}
 
@@ -733,7 +637,7 @@
 	if (attr_mask & IB_QP_RNR_RETRY) {
 		qp_context->alt_path.rnr_retry = qp_context->pri_path.rnr_retry =
 			attr->rnr_retry << 5;
-		qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RNR_RETRY | 
+		qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RNR_RETRY |
 							MTHCA_QP_OPTPAR_ALT_RNR_RETRY);
 	}
 
@@ -748,14 +652,20 @@
 	}
 
 	if (attr_mask & IB_QP_ALT_PATH) {
+		if (attr->alt_pkey_index >= dev->limits.pkey_table_len) {
+			mthca_dbg(dev, "Alternate P_Key index (%u) too large. max is %d\n",
+				  attr->alt_pkey_index, dev->limits.pkey_table_len-1);
+			return -EINVAL;
+		}
+
 		if (attr->alt_port_num == 0 || attr->alt_port_num > dev->limits.num_ports) {
-			mthca_dbg(dev, "Alternate port number (%u) is invalid\n", 
+			mthca_dbg(dev, "Alternate port number (%u) is invalid\n",
 				attr->alt_port_num);
 			return -EINVAL;
 		}
 
 		mthca_path_set(&attr->alt_ah_attr, &qp_context->alt_path);
-		qp_context->alt_path.port_pkey |= cpu_to_be32(attr->alt_pkey_index | 
+		qp_context->alt_path.port_pkey |= cpu_to_be32(attr->alt_pkey_index |
 							      attr->alt_port_num << 24);
 		qp_context->alt_path.ackto = attr->alt_timeout << 3;
 		qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_ALT_ADDR_PATH);
@@ -841,11 +751,16 @@
 		qp_context->srqn = cpu_to_be32(1 << 24 |
 					       to_msrq(ibqp->srq)->srqn);
 
-	err = mthca_MODIFY_QP(dev, state_table[cur_state][new_state].trans,
-			      qp->qpn, 0, mailbox, 0, &status);
+	if (cur_state == IB_QPS_RTS && new_state == IB_QPS_SQD	&&
+	    attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY		&&
+	    attr->en_sqd_async_notify)
+		sqd_event = 1 << 31;
+
+	err = mthca_MODIFY_QP(dev, cur_state, new_state, qp->qpn, 0,
+			      mailbox, sqd_event, &status);
 	if (status) {
-		mthca_warn(dev, "modify QP %d returned status %02x.\n",
-			   state_table[cur_state][new_state].trans, status);
+		mthca_warn(dev, "modify QP %d->%d returned status %02x.\n",
+			   cur_state, new_state, status);
 		err = -EINVAL;
 	}
 
@@ -1078,10 +993,10 @@
 		if (ret)
 			goto err_qpc;
 
- 		ret = mthca_table_get(dev, dev->qp_table.rdb_table,
- 				      qp->qpn << dev->qp_table.rdb_shift);
- 		if (ret)
- 			goto err_eqpc;
+		ret = mthca_table_get(dev, dev->qp_table.rdb_table,
+				      qp->qpn << dev->qp_table.rdb_shift);
+		if (ret)
+			goto err_eqpc;
 
 	}
 
@@ -1393,7 +1308,8 @@
 	wait_event(qp->wait, !atomic_read(&qp->refcount));
 
 	if (qp->state != IB_QPS_RESET)
-		mthca_MODIFY_QP(dev, MTHCA_TRANS_ANY2RST, qp->qpn, 0, NULL, 0, &status);
+		mthca_MODIFY_QP(dev, qp->state, IB_QPS_RESET, qp->qpn, 0,
+				NULL, 0, &status);
 
 	/*
 	 * If this is a userspace QP, the buffers, MR, CQs and so on
@@ -1699,7 +1615,9 @@
 				    mthca_opcode[wr->opcode]);
 		wmb();
 		((struct mthca_next_seg *) prev_wqe)->ee_nds =
-			cpu_to_be32((size0 ? 0 : MTHCA_NEXT_DBD) | size);
+			cpu_to_be32((size0 ? 0 : MTHCA_NEXT_DBD) | size |
+				    ((wr->send_flags & IB_SEND_FENCE) ?
+				    MTHCA_NEXT_FENCE : 0));
 
 		if (!size0) {
 			size0 = size;
@@ -2061,7 +1979,9 @@
 				    mthca_opcode[wr->opcode]);
 		wmb();
 		((struct mthca_next_seg *) prev_wqe)->ee_nds =
-			cpu_to_be32(MTHCA_NEXT_DBD | size);
+			cpu_to_be32(MTHCA_NEXT_DBD | size |
+                                    ((wr->send_flags & IB_SEND_FENCE) ?
+                                    MTHCA_NEXT_FENCE : 0));
 
 		if (!size0) {
 			size0 = size;
@@ -2115,7 +2035,7 @@
 	int i;
 	void *wqe;
 
- 	spin_lock_irqsave(&qp->rq.lock, flags);
+	spin_lock_irqsave(&qp->rq.lock, flags);
 
 	/* XXX check that state is OK to post receive */
 
@@ -2182,8 +2102,8 @@
 	return err;
 }
 
-int mthca_free_err_wqe(struct mthca_dev *dev, struct mthca_qp *qp, int is_send,
-		       int index, int *dbd, __be32 *new_wqe)
+void mthca_free_err_wqe(struct mthca_dev *dev, struct mthca_qp *qp, int is_send,
+			int index, int *dbd, __be32 *new_wqe)
 {
 	struct mthca_next_seg *next;
 
@@ -2193,7 +2113,7 @@
 	 */
 	if (qp->ibqp.srq) {
 		*new_wqe = 0;
-		return 0;
+		return;
 	}
 
 	if (is_send)
@@ -2207,8 +2127,6 @@
 			(next->ee_nds & cpu_to_be32(0x3f));
 	else
 		*new_wqe = 0;
-
-	return 0;
 }
 
 int __devinit mthca_init_qp_table(struct mthca_dev *dev)
diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c
index e7e153d..47a6a75 100644
--- a/drivers/infiniband/hw/mthca/mthca_srq.c
+++ b/drivers/infiniband/hw/mthca/mthca_srq.c
@@ -49,7 +49,8 @@
 	__be32 state_pd;
 	__be32 lkey;
 	__be32 uar;
-	__be32 wqe_cnt;
+	__be16 limit_watermark;
+	__be16 wqe_cnt;
 	u32    reserved[2];
 };
 
@@ -271,6 +272,9 @@
 	srq->first_free = 0;
 	srq->last_free  = srq->max - 1;
 
+	attr->max_wr    = (mthca_is_memfree(dev)) ? srq->max - 1 : srq->max;
+	attr->max_sge   = srq->max_gs;
+
 	return 0;
 
 err_out_free_srq:
@@ -339,7 +343,7 @@
 
 int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
 		     enum ib_srq_attr_mask attr_mask)
-{	
+{
 	struct mthca_dev *dev = to_mdev(ibsrq->device);
 	struct mthca_srq *srq = to_msrq(ibsrq);
 	int ret;
@@ -360,6 +364,41 @@
 	return 0;
 }
 
+int mthca_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr)
+{
+	struct mthca_dev *dev = to_mdev(ibsrq->device);
+	struct mthca_srq *srq = to_msrq(ibsrq);
+	struct mthca_mailbox *mailbox;
+	struct mthca_arbel_srq_context *arbel_ctx;
+	struct mthca_tavor_srq_context *tavor_ctx;
+	u8 status;
+	int err;
+
+	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+	if (IS_ERR(mailbox))
+		return PTR_ERR(mailbox);
+
+	err = mthca_QUERY_SRQ(dev, srq->srqn, mailbox, &status);
+	if (err)
+		goto out;
+
+	if (mthca_is_memfree(dev)) {
+		arbel_ctx = mailbox->buf;
+		srq_attr->srq_limit = be16_to_cpu(arbel_ctx->limit_watermark);
+	} else {
+		tavor_ctx = mailbox->buf;
+		srq_attr->srq_limit = be16_to_cpu(tavor_ctx->limit_watermark);
+	}
+
+	srq_attr->max_wr  = (mthca_is_memfree(dev)) ? srq->max - 1 : srq->max;
+	srq_attr->max_sge = srq->max_gs;
+
+out:
+	mthca_free_mailbox(dev, mailbox);
+
+	return err;
+}
+
 void mthca_srq_event(struct mthca_dev *dev, u32 srqn,
 		     enum ib_event_type event_type)
 {
diff --git a/drivers/infiniband/hw/mthca/mthca_user.h b/drivers/infiniband/hw/mthca/mthca_user.h
index bb015c6..02cc0a7 100644
--- a/drivers/infiniband/hw/mthca/mthca_user.h
+++ b/drivers/infiniband/hw/mthca/mthca_user.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -75,6 +75,11 @@
 	__u32 reserved;
 };
 
+struct mthca_resize_cq {
+	__u32 lkey;
+	__u32 reserved;
+};
+
 struct mthca_create_srq {
 	__u32 lkey;
 	__u32 db_index;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index 2f85a9a..1251f86 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -217,10 +217,16 @@
 	struct list_head    list;
 };
 
+/*
+ * We stash a pointer to our private neighbour information after our
+ * hardware address in neigh->ha.  The ALIGN() expression here makes
+ * sure that this pointer is stored aligned so that an unaligned
+ * load is not needed to dereference it.
+ */
 static inline struct ipoib_neigh **to_ipoib_neigh(struct neighbour *neigh)
 {
-	return (struct ipoib_neigh **) (neigh->ha + 24 -
-					(offsetof(struct neighbour, ha) & 4));
+	return (void*) neigh + ALIGN(offsetof(struct neighbour, ha) +
+				     INFINIBAND_ALEN, sizeof(void *));
 }
 
 extern struct workqueue_struct *ipoib_workqueue;
@@ -253,7 +259,7 @@
 
 int ipoib_ib_dev_open(struct net_device *dev);
 int ipoib_ib_dev_up(struct net_device *dev);
-int ipoib_ib_dev_down(struct net_device *dev);
+int ipoib_ib_dev_down(struct net_device *dev, int flush);
 int ipoib_ib_dev_stop(struct net_device *dev);
 
 int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index 86bcdd7..a1f5a05 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -416,6 +416,7 @@
 	ret = ipoib_ib_post_receives(dev);
 	if (ret) {
 		ipoib_warn(priv, "ipoib_ib_post_receives returned %d\n", ret);
+		ipoib_ib_dev_stop(dev);
 		return -1;
 	}
 
@@ -434,7 +435,7 @@
 	return ipoib_mcast_start_thread(dev);
 }
 
-int ipoib_ib_dev_down(struct net_device *dev)
+int ipoib_ib_dev_down(struct net_device *dev, int flush)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 
@@ -449,10 +450,11 @@
 		set_bit(IPOIB_PKEY_STOP, &priv->flags);
 		cancel_delayed_work(&priv->pkey_task);
 		mutex_unlock(&pkey_mutex);
-		flush_workqueue(ipoib_workqueue);
+		if (flush)
+			flush_workqueue(ipoib_workqueue);
 	}
 
-	ipoib_mcast_stop_thread(dev, 1);
+	ipoib_mcast_stop_thread(dev, flush);
 	ipoib_mcast_dev_flush(dev);
 
 	ipoib_flush_paths(dev);
@@ -590,7 +592,7 @@
 
 	ipoib_dbg(priv, "flushing\n");
 
-	ipoib_ib_dev_down(dev);
+	ipoib_ib_dev_down(dev, 0);
 
 	/*
 	 * The device could have been brought down between the start and when
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 9d9cecd..37da8d3 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -133,7 +133,13 @@
 
 	netif_stop_queue(dev);
 
-	ipoib_ib_dev_down(dev);
+	/*
+	 * Now flush workqueue to make sure a scheduled task doesn't
+	 * bring our internal state back up.
+	 */
+	flush_workqueue(ipoib_workqueue);
+
+	ipoib_ib_dev_down(dev, 1);
 	ipoib_ib_dev_stop(dev);
 
 	if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) {
@@ -512,12 +518,7 @@
 			   be32_to_cpup((__be32 *) skb->dst->neighbour->ha));
 	} else {
 		neigh->ah  = NULL;
-		if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
-			__skb_queue_tail(&neigh->queue, skb);
-		} else {
-			++priv->stats.tx_dropped;
-			dev_kfree_skb_any(skb);
-		}
+		__skb_queue_tail(&neigh->queue, skb);
 
 		if (!path->query && path_rec_start(dev, path))
 			goto err;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index 19fd173..93c462e 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -212,6 +212,7 @@
 {
 	struct net_device *dev = mcast->dev;
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
+	struct ipoib_ah *ah;
 	int ret;
 
 	mcast->mcmember = *mcmember;
@@ -268,8 +269,8 @@
 				av.static_rate, priv->local_rate,
 				ib_sa_rate_enum_to_int(mcast->mcmember.rate));
 
-		mcast->ah = ipoib_create_ah(dev, priv->pd, &av);
-		if (!mcast->ah) {
+		ah = ipoib_create_ah(dev, priv->pd, &av);
+		if (!ah) {
 			ipoib_warn(priv, "ib_address_create failed\n");
 		} else {
 			ipoib_dbg_mcast(priv, "MGID " IPOIB_GID_FMT
@@ -279,6 +280,10 @@
 					be16_to_cpu(mcast->mcmember.mlid),
 					mcast->mcmember.sl);
 		}
+
+		spin_lock_irq(&priv->lock);
+		mcast->ah = ah;
+		spin_unlock_irq(&priv->lock);
 	}
 
 	/* actually send any queued packets */
@@ -431,9 +436,11 @@
 	if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS)
 		mcast->backoff = IPOIB_MAX_BACKOFF_SECONDS;
 
+	mutex_lock(&mcast_mutex);
+
+	spin_lock_irq(&priv->lock);
 	mcast->query = NULL;
 
-	mutex_lock(&mcast_mutex);
 	if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) {
 		if (status == -ETIMEDOUT)
 			queue_work(ipoib_workqueue, &priv->mcast_task);
@@ -442,6 +449,7 @@
 					   mcast->backoff * HZ);
 	} else
 		complete(&mcast->done);
+	spin_unlock_irq(&priv->lock);
 	mutex_unlock(&mcast_mutex);
 
 	return;
@@ -629,21 +637,27 @@
 	if (flush)
 		flush_workqueue(ipoib_workqueue);
 
+	spin_lock_irq(&priv->lock);
 	if (priv->broadcast && priv->broadcast->query) {
 		ib_sa_cancel_query(priv->broadcast->query_id, priv->broadcast->query);
 		priv->broadcast->query = NULL;
+		spin_unlock_irq(&priv->lock);
 		ipoib_dbg_mcast(priv, "waiting for bcast\n");
 		wait_for_completion(&priv->broadcast->done);
-	}
+	} else
+		spin_unlock_irq(&priv->lock);
 
 	list_for_each_entry(mcast, &priv->multicast_list, list) {
+		spin_lock_irq(&priv->lock);
 		if (mcast->query) {
 			ib_sa_cancel_query(mcast->query_id, mcast->query);
 			mcast->query = NULL;
+			spin_unlock_irq(&priv->lock);
 			ipoib_dbg_mcast(priv, "waiting for MGID " IPOIB_GID_FMT "\n",
 					IPOIB_GID_ARG(mcast->mcmember.mgid));
 			wait_for_completion(&mcast->done);
-		}
+		} else
+			spin_unlock_irq(&priv->lock);
 	}
 
 	return 0;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
index faaf10e..18d2f53 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
@@ -255,6 +255,6 @@
 	    record->event == IB_EVENT_LID_CHANGE  ||
 	    record->event == IB_EVENT_SM_CHANGE) {
 		ipoib_dbg(priv, "Port active event\n");
-		schedule_work(&priv->flush_task);
+		queue_work(ipoib_workqueue, &priv->flush_task);
 	}
 }
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 960dae5..a13dcdf 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -1237,6 +1237,87 @@
 	return ret;
 }
 
+static ssize_t show_id_ext(struct class_device *cdev, char *buf)
+{
+	struct srp_target_port *target = host_to_target(class_to_shost(cdev));
+
+	if (target->state == SRP_TARGET_DEAD ||
+	    target->state == SRP_TARGET_REMOVED)
+		return -ENODEV;
+
+	return sprintf(buf, "0x%016llx\n",
+		       (unsigned long long) be64_to_cpu(target->id_ext));
+}
+
+static ssize_t show_ioc_guid(struct class_device *cdev, char *buf)
+{
+	struct srp_target_port *target = host_to_target(class_to_shost(cdev));
+
+	if (target->state == SRP_TARGET_DEAD ||
+	    target->state == SRP_TARGET_REMOVED)
+		return -ENODEV;
+
+	return sprintf(buf, "0x%016llx\n",
+		       (unsigned long long) be64_to_cpu(target->ioc_guid));
+}
+
+static ssize_t show_service_id(struct class_device *cdev, char *buf)
+{
+	struct srp_target_port *target = host_to_target(class_to_shost(cdev));
+
+	if (target->state == SRP_TARGET_DEAD ||
+	    target->state == SRP_TARGET_REMOVED)
+		return -ENODEV;
+
+	return sprintf(buf, "0x%016llx\n",
+		       (unsigned long long) be64_to_cpu(target->service_id));
+}
+
+static ssize_t show_pkey(struct class_device *cdev, char *buf)
+{
+	struct srp_target_port *target = host_to_target(class_to_shost(cdev));
+
+	if (target->state == SRP_TARGET_DEAD ||
+	    target->state == SRP_TARGET_REMOVED)
+		return -ENODEV;
+
+	return sprintf(buf, "0x%04x\n", be16_to_cpu(target->path.pkey));
+}
+
+static ssize_t show_dgid(struct class_device *cdev, char *buf)
+{
+	struct srp_target_port *target = host_to_target(class_to_shost(cdev));
+
+	if (target->state == SRP_TARGET_DEAD ||
+	    target->state == SRP_TARGET_REMOVED)
+		return -ENODEV;
+
+	return sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+		       be16_to_cpu(((__be16 *) target->path.dgid.raw)[0]),
+		       be16_to_cpu(((__be16 *) target->path.dgid.raw)[1]),
+		       be16_to_cpu(((__be16 *) target->path.dgid.raw)[2]),
+		       be16_to_cpu(((__be16 *) target->path.dgid.raw)[3]),
+		       be16_to_cpu(((__be16 *) target->path.dgid.raw)[4]),
+		       be16_to_cpu(((__be16 *) target->path.dgid.raw)[5]),
+		       be16_to_cpu(((__be16 *) target->path.dgid.raw)[6]),
+		       be16_to_cpu(((__be16 *) target->path.dgid.raw)[7]));
+}
+
+static CLASS_DEVICE_ATTR(id_ext,	S_IRUGO, show_id_ext,		NULL);
+static CLASS_DEVICE_ATTR(ioc_guid,	S_IRUGO, show_ioc_guid,		NULL);
+static CLASS_DEVICE_ATTR(service_id,	S_IRUGO, show_service_id,	NULL);
+static CLASS_DEVICE_ATTR(pkey,		S_IRUGO, show_pkey,		NULL);
+static CLASS_DEVICE_ATTR(dgid,		S_IRUGO, show_dgid,		NULL);
+
+static struct class_device_attribute *srp_host_attrs[] = {
+	&class_device_attr_id_ext,
+	&class_device_attr_ioc_guid,
+	&class_device_attr_service_id,
+	&class_device_attr_pkey,
+	&class_device_attr_dgid,
+	NULL
+};
+
 static struct scsi_host_template srp_template = {
 	.module				= THIS_MODULE,
 	.name				= DRV_NAME,
@@ -1249,7 +1330,8 @@
 	.this_id			= -1,
 	.sg_tablesize			= SRP_MAX_INDIRECT,
 	.cmd_per_lun			= SRP_SQ_SIZE,
-	.use_clustering			= ENABLE_CLUSTERING
+	.use_clustering			= ENABLE_CLUSTERING,
+	.shost_attrs			= srp_host_attrs
 };
 
 static int srp_add_target(struct srp_host *host, struct srp_target_port *target)
@@ -1366,6 +1448,7 @@
 				strlcpy(dgid, p + i * 2, 3);
 				target->path.dgid.raw[i] = simple_strtoul(dgid, NULL, 16);
 			}
+			kfree(p);
 			break;
 
 		case SRP_OPT_PKEY:
diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile
index bd458cb..61b8961 100644
--- a/drivers/media/common/Makefile
+++ b/drivers/media/common/Makefile
@@ -1,5 +1,6 @@
 saa7146-objs    := saa7146_i2c.o saa7146_core.o
 saa7146_vv-objs := saa7146_vv_ksyms.o saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o
+ir-common-objs  := ir-functions.o ir-keymaps.o
 
 obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o
 obj-$(CONFIG_VIDEO_SAA7146_VV) += saa7146_vv.o
diff --git a/drivers/media/common/ir-common.c b/drivers/media/common/ir-common.c
deleted file mode 100644
index 97fa3fc..0000000
--- a/drivers/media/common/ir-common.c
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
- *
- * some common structs and functions to handle infrared remotes via
- * input layer ...
- *
- * (c) 2003 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/string.h>
-#include <media/ir-common.h>
-
-/* -------------------------------------------------------------------------- */
-
-MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
-MODULE_LICENSE("GPL");
-
-static int repeat = 1;
-module_param(repeat, int, 0444);
-MODULE_PARM_DESC(repeat,"auto-repeat for IR keys (default: on)");
-
-static int debug = 0;    /* debug level (0,1,2) */
-module_param(debug, int, 0644);
-
-#define dprintk(level, fmt, arg...)	if (debug >= level) \
-	printk(KERN_DEBUG fmt , ## arg)
-
-/* -------------------------------------------------------------------------- */
-
-/* generic RC5 keytable                                          */
-/* see http://users.pandora.be/nenya/electronics/rc5/codes00.htm */
-/* used by old (black) Hauppauge remotes                         */
-IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE] = {
-	/* Keys 0 to 9 */
-	[ 0x00 ] = KEY_KP0,
-	[ 0x01 ] = KEY_KP1,
-	[ 0x02 ] = KEY_KP2,
-	[ 0x03 ] = KEY_KP3,
-	[ 0x04 ] = KEY_KP4,
-	[ 0x05 ] = KEY_KP5,
-	[ 0x06 ] = KEY_KP6,
-	[ 0x07 ] = KEY_KP7,
-	[ 0x08 ] = KEY_KP8,
-	[ 0x09 ] = KEY_KP9,
-
-	[ 0x0b ] = KEY_CHANNEL,		/* channel / program (japan: 11) */
-	[ 0x0c ] = KEY_POWER,		/* standby */
-	[ 0x0d ] = KEY_MUTE,		/* mute / demute */
-	[ 0x0f ] = KEY_TV,		/* display */
-	[ 0x10 ] = KEY_VOLUMEUP,
-	[ 0x11 ] = KEY_VOLUMEDOWN,
-	[ 0x12 ] = KEY_BRIGHTNESSUP,
-	[ 0x13 ] = KEY_BRIGHTNESSDOWN,
-	[ 0x1e ] = KEY_SEARCH,		/* search + */
-	[ 0x20 ] = KEY_CHANNELUP,	/* channel / program + */
-	[ 0x21 ] = KEY_CHANNELDOWN,	/* channel / program - */
-	[ 0x22 ] = KEY_CHANNEL,		/* alt / channel */
-	[ 0x23 ] = KEY_LANGUAGE,	/* 1st / 2nd language */
-	[ 0x26 ] = KEY_SLEEP,		/* sleeptimer */
-	[ 0x2e ] = KEY_MENU,		/* 2nd controls (USA: menu) */
-	[ 0x30 ] = KEY_PAUSE,
-	[ 0x32 ] = KEY_REWIND,
-	[ 0x33 ] = KEY_GOTO,
-	[ 0x35 ] = KEY_PLAY,
-	[ 0x36 ] = KEY_STOP,
-	[ 0x37 ] = KEY_RECORD,		/* recording */
-	[ 0x3c ] = KEY_TEXT,    	/* teletext submode (Japan: 12) */
-	[ 0x3d ] = KEY_SUSPEND,		/* system standby */
-
-};
-EXPORT_SYMBOL_GPL(ir_codes_rc5_tv);
-
-/* Table for Leadtek Winfast Remote Controls - used by both bttv and cx88 */
-IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = {
-	/* Keys 0 to 9 */
-	[ 18 ] = KEY_KP0,
-	[  5 ] = KEY_KP1,
-	[  6 ] = KEY_KP2,
-	[  7 ] = KEY_KP3,
-	[  9 ] = KEY_KP4,
-	[ 10 ] = KEY_KP5,
-	[ 11 ] = KEY_KP6,
-	[ 13 ] = KEY_KP7,
-	[ 14 ] = KEY_KP8,
-	[ 15 ] = KEY_KP9,
-
-	[  0 ] = KEY_POWER,
-	[  2 ] = KEY_TUNER,		/* TV/FM */
-	[ 30 ] = KEY_VIDEO,
-	[  4 ] = KEY_VOLUMEUP,
-	[  8 ] = KEY_VOLUMEDOWN,
-	[ 12 ] = KEY_CHANNELUP,
-	[ 16 ] = KEY_CHANNELDOWN,
-	[  3 ] = KEY_ZOOM,		/* fullscreen */
-	[ 31 ] = KEY_SUBTITLE,		/* closed caption/teletext */
-	[ 32 ] = KEY_SLEEP,
-	[ 20 ] = KEY_MUTE,
-	[ 43 ] = KEY_RED,
-	[ 44 ] = KEY_GREEN,
-	[ 45 ] = KEY_YELLOW,
-	[ 46 ] = KEY_BLUE,
-	[ 24 ] = KEY_KPPLUS,		/* fine tune + */
-	[ 25 ] = KEY_KPMINUS,		/* fine tune - */
-	[ 33 ] = KEY_KPDOT,
-	[ 19 ] = KEY_KPENTER,
-	[ 34 ] = KEY_BACK,
-	[ 35 ] = KEY_PLAYPAUSE,
-	[ 36 ] = KEY_NEXT,
-	[ 38 ] = KEY_STOP,
-	[ 39 ] = KEY_RECORD
-};
-EXPORT_SYMBOL_GPL(ir_codes_winfast);
-
-IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE] = {
-	[ 0x59 ] = KEY_MUTE,
-	[ 0x4a ] = KEY_POWER,
-
-	[ 0x18 ] = KEY_TEXT,
-	[ 0x26 ] = KEY_TV,
-	[ 0x3d ] = KEY_PRINT,
-
-	[ 0x48 ] = KEY_RED,
-	[ 0x04 ] = KEY_GREEN,
-	[ 0x11 ] = KEY_YELLOW,
-	[ 0x00 ] = KEY_BLUE,
-
-	[ 0x2d ] = KEY_VOLUMEUP,
-	[ 0x1e ] = KEY_VOLUMEDOWN,
-
-	[ 0x49 ] = KEY_MENU,
-
-	[ 0x16 ] = KEY_CHANNELUP,
-	[ 0x17 ] = KEY_CHANNELDOWN,
-
-	[ 0x20 ] = KEY_UP,
-	[ 0x21 ] = KEY_DOWN,
-	[ 0x22 ] = KEY_LEFT,
-	[ 0x23 ] = KEY_RIGHT,
-	[ 0x0d ] = KEY_SELECT,
-
-
-
-	[ 0x08 ] = KEY_BACK,
-	[ 0x07 ] = KEY_REFRESH,
-
-	[ 0x2f ] = KEY_ZOOM,
-	[ 0x29 ] = KEY_RECORD,
-
-	[ 0x4b ] = KEY_PAUSE,
-	[ 0x4d ] = KEY_REWIND,
-	[ 0x2e ] = KEY_PLAY,
-	[ 0x4e ] = KEY_FORWARD,
-	[ 0x53 ] = KEY_PREVIOUS,
-	[ 0x4c ] = KEY_STOP,
-	[ 0x54 ] = KEY_NEXT,
-
-	[ 0x69 ] = KEY_KP0,
-	[ 0x6a ] = KEY_KP1,
-	[ 0x6b ] = KEY_KP2,
-	[ 0x6c ] = KEY_KP3,
-	[ 0x6d ] = KEY_KP4,
-	[ 0x6e ] = KEY_KP5,
-	[ 0x6f ] = KEY_KP6,
-	[ 0x70 ] = KEY_KP7,
-	[ 0x71 ] = KEY_KP8,
-	[ 0x72 ] = KEY_KP9,
-
-	[ 0x74 ] = KEY_CHANNEL,
-	[ 0x0a ] = KEY_BACKSPACE,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_pinnacle);
-
-/* empty keytable, can be used as placeholder for not-yet created keytables */
-IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE] = {
-	[ 42 ] = KEY_COFFEE,
-};
-EXPORT_SYMBOL_GPL(ir_codes_empty);
-
-/* Hauppauge: the newer, gray remotes (seems there are multiple
- * slightly different versions), shipped with cx88+ivtv cards.
- * almost rc5 coding, but some non-standard keys */
-IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE] = {
-	/* Keys 0 to 9 */
-	[ 0x00 ] = KEY_KP0,
-	[ 0x01 ] = KEY_KP1,
-	[ 0x02 ] = KEY_KP2,
-	[ 0x03 ] = KEY_KP3,
-	[ 0x04 ] = KEY_KP4,
-	[ 0x05 ] = KEY_KP5,
-	[ 0x06 ] = KEY_KP6,
-	[ 0x07 ] = KEY_KP7,
-	[ 0x08 ] = KEY_KP8,
-	[ 0x09 ] = KEY_KP9,
-
-	[ 0x0a ] = KEY_TEXT,      	/* keypad asterisk as well */
-	[ 0x0b ] = KEY_RED,		/* red button */
-	[ 0x0c ] = KEY_RADIO,
-	[ 0x0d ] = KEY_MENU,
-	[ 0x0e ] = KEY_SUBTITLE,	/* also the # key */
-	[ 0x0f ] = KEY_MUTE,
-	[ 0x10 ] = KEY_VOLUMEUP,
-	[ 0x11 ] = KEY_VOLUMEDOWN,
-	[ 0x12 ] = KEY_PREVIOUS,	/* previous channel */
-	[ 0x14 ] = KEY_UP,
-	[ 0x15 ] = KEY_DOWN,
-	[ 0x16 ] = KEY_LEFT,
-	[ 0x17 ] = KEY_RIGHT,
-	[ 0x18 ] = KEY_VIDEO,		/* Videos */
-	[ 0x19 ] = KEY_AUDIO,		/* Music */
-	/* 0x1a: Pictures - presume this means
-	   "Multimedia Home Platform" -
-	   no "PICTURES" key in input.h
-	 */
-	[ 0x1a ] = KEY_MHP,
-
-	[ 0x1b ] = KEY_EPG,		/* Guide */
-	[ 0x1c ] = KEY_TV,
-	[ 0x1e ] = KEY_NEXTSONG,	/* skip >| */
-	[ 0x1f ] = KEY_EXIT,		/* back/exit */
-	[ 0x20 ] = KEY_CHANNELUP,	/* channel / program + */
-	[ 0x21 ] = KEY_CHANNELDOWN,	/* channel / program - */
-	[ 0x22 ] = KEY_CHANNEL,		/* source (old black remote) */
-	[ 0x24 ] = KEY_PREVIOUSSONG,	/* replay |< */
-	[ 0x25 ] = KEY_ENTER,		/* OK */
-	[ 0x26 ] = KEY_SLEEP,		/* minimize (old black remote) */
-	[ 0x29 ] = KEY_BLUE,		/* blue key */
-	[ 0x2e ] = KEY_GREEN,		/* green button */
-	[ 0x30 ] = KEY_PAUSE,		/* pause */
-	[ 0x32 ] = KEY_REWIND,		/* backward << */
-	[ 0x34 ] = KEY_FASTFORWARD,	/* forward >> */
-	[ 0x35 ] = KEY_PLAY,
-	[ 0x36 ] = KEY_STOP,
-	[ 0x37 ] = KEY_RECORD,		/* recording */
-	[ 0x38 ] = KEY_YELLOW,		/* yellow key */
-	[ 0x3b ] = KEY_SELECT,		/* top right button */
-	[ 0x3c ] = KEY_ZOOM,		/* full */
-	[ 0x3d ] = KEY_POWER,		/* system power (green button) */
-};
-EXPORT_SYMBOL(ir_codes_hauppauge_new);
-
-IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE] = {
-	[  2 ] = KEY_KP0,
-	[  1 ] = KEY_KP1,
-	[ 11 ] = KEY_KP2,
-	[ 27 ] = KEY_KP3,
-	[  5 ] = KEY_KP4,
-	[  9 ] = KEY_KP5,
-	[ 21 ] = KEY_KP6,
-	[  6 ] = KEY_KP7,
-	[ 10 ] = KEY_KP8,
-	[ 18 ] = KEY_KP9,
-
-	[  3 ] = KEY_TUNER,		/* TV/FM */
-	[  7 ] = KEY_SEARCH,		/* scan */
-	[ 28 ] = KEY_ZOOM,		/* full screen */
-	[ 30 ] = KEY_POWER,
-	[ 23 ] = KEY_VOLUMEDOWN,
-	[ 31 ] = KEY_VOLUMEUP,
-	[ 20 ] = KEY_CHANNELDOWN,
-	[ 22 ] = KEY_CHANNELUP,
-	[ 24 ] = KEY_MUTE,
-
-	[  0 ] = KEY_LIST,		/* source */
-	[ 19 ] = KEY_INFO,		/* loop */
-	[ 16 ] = KEY_LAST,		/* +100 */
-	[ 13 ] = KEY_CLEAR,		/* reset */
-	[ 12 ] = BTN_RIGHT,		/* fun++ */
-	[  4 ] = BTN_LEFT,		/* fun-- */
-	[ 14 ] = KEY_GOTO,		/* function */
-	[ 15 ] = KEY_STOP,		/* freeze */
-};
-EXPORT_SYMBOL(ir_codes_pixelview);
-
-/* -------------------------------------------------------------------------- */
-
-static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir)
-{
-	if (KEY_RESERVED == ir->keycode) {
-		printk(KERN_INFO "%s: unknown key: key=0x%02x raw=0x%02x down=%d\n",
-		       dev->name,ir->ir_key,ir->ir_raw,ir->keypressed);
-		return;
-	}
-	dprintk(1,"%s: key event code=%d down=%d\n",
-		dev->name,ir->keycode,ir->keypressed);
-	input_report_key(dev,ir->keycode,ir->keypressed);
-	input_sync(dev);
-}
-
-/* -------------------------------------------------------------------------- */
-
-void ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
-		   int ir_type, IR_KEYTAB_TYPE *ir_codes)
-{
-	int i;
-
-	ir->ir_type = ir_type;
-	if (ir_codes)
-		memcpy(ir->ir_codes, ir_codes, sizeof(ir->ir_codes));
-
-
-	dev->keycode     = ir->ir_codes;
-	dev->keycodesize = sizeof(IR_KEYTAB_TYPE);
-	dev->keycodemax  = IR_KEYTAB_SIZE;
-	for (i = 0; i < IR_KEYTAB_SIZE; i++)
-		set_bit(ir->ir_codes[i], dev->keybit);
-	clear_bit(0, dev->keybit);
-
-	set_bit(EV_KEY, dev->evbit);
-	if (repeat)
-		set_bit(EV_REP, dev->evbit);
-}
-
-void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir)
-{
-	if (ir->keypressed) {
-		ir->keypressed = 0;
-		ir_input_key_event(dev,ir);
-	}
-}
-
-void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir,
-		      u32 ir_key, u32 ir_raw)
-{
-	u32 keycode = IR_KEYCODE(ir->ir_codes, ir_key);
-
-	if (ir->keypressed && ir->keycode != keycode) {
-		ir->keypressed = 0;
-		ir_input_key_event(dev,ir);
-	}
-	if (!ir->keypressed) {
-		ir->ir_key  = ir_key;
-		ir->ir_raw  = ir_raw;
-		ir->keycode = keycode;
-		ir->keypressed = 1;
-		ir_input_key_event(dev,ir);
-	}
-}
-
-/* -------------------------------------------------------------------------- */
-
-u32 ir_extract_bits(u32 data, u32 mask)
-{
-	int mbit, vbit;
-	u32 value;
-
-	value = 0;
-	vbit  = 0;
-	for (mbit = 0; mbit < 32; mbit++) {
-		if (!(mask & ((u32)1 << mbit)))
-			continue;
-		if (data & ((u32)1 << mbit))
-			value |= (1 << vbit);
-		vbit++;
-	}
-	return value;
-}
-
-static int inline getbit(u32 *samples, int bit)
-{
-	return (samples[bit/32] & (1 << (31-(bit%32)))) ? 1 : 0;
-}
-
-/* sump raw samples for visual debugging ;) */
-int ir_dump_samples(u32 *samples, int count)
-{
-	int i, bit, start;
-
-	printk(KERN_DEBUG "ir samples: ");
-	start = 0;
-	for (i = 0; i < count * 32; i++) {
-		bit = getbit(samples,i);
-		if (bit)
-			start = 1;
-		if (0 == start)
-			continue;
-		printk("%s", bit ? "#" : "_");
-	}
-	printk("\n");
-	return 0;
-}
-
-/* decode raw samples, pulse distance coding used by NEC remotes */
-int ir_decode_pulsedistance(u32 *samples, int count, int low, int high)
-{
-	int i,last,bit,len;
-	u32 curBit;
-	u32 value;
-
-	/* find start burst */
-	for (i = len = 0; i < count * 32; i++) {
-		bit = getbit(samples,i);
-		if (bit) {
-			len++;
-		} else {
-			if (len >= 29)
-				break;
-			len = 0;
-		}
-	}
-
-	/* start burst to short */
-	if (len < 29)
-		return 0xffffffff;
-
-	/* find start silence */
-	for (len = 0; i < count * 32; i++) {
-		bit = getbit(samples,i);
-		if (bit) {
-			break;
-		} else {
-			len++;
-		}
-	}
-
-	/* silence to short */
-	if (len < 7)
-		return 0xffffffff;
-
-	/* go decoding */
-	len   = 0;
-	last = 1;
-	value = 0; curBit = 1;
-	for (; i < count * 32; i++) {
-		bit  = getbit(samples,i);
-		if (last) {
-			if(bit) {
-				continue;
-			} else {
-				len = 1;
-			}
-		} else {
-			if (bit) {
-				if (len > (low + high) /2)
-					value |= curBit;
-				curBit <<= 1;
-				if (curBit == 1)
-					break;
-			} else {
-				len++;
-			}
-		}
-		last = bit;
-	}
-
-	return value;
-}
-
-/* decode raw samples, biphase coding, used by rc5 for example */
-int ir_decode_biphase(u32 *samples, int count, int low, int high)
-{
-	int i,last,bit,len,flips;
-	u32 value;
-
-	/* find start bit (1) */
-	for (i = 0; i < 32; i++) {
-		bit = getbit(samples,i);
-		if (bit)
-			break;
-	}
-
-	/* go decoding */
-	len   = 0;
-	flips = 0;
-	value = 1;
-	for (; i < count * 32; i++) {
-		if (len > high)
-			break;
-		if (flips > 1)
-			break;
-		last = bit;
-		bit  = getbit(samples,i);
-		if (last == bit) {
-			len++;
-			continue;
-		}
-		if (len < low) {
-			len++;
-			flips++;
-			continue;
-		}
-		value <<= 1;
-		value |= bit;
-		flips = 0;
-		len   = 1;
-	}
-	return value;
-}
-
-EXPORT_SYMBOL_GPL(ir_input_init);
-EXPORT_SYMBOL_GPL(ir_input_nokey);
-EXPORT_SYMBOL_GPL(ir_input_keydown);
-
-EXPORT_SYMBOL_GPL(ir_extract_bits);
-EXPORT_SYMBOL_GPL(ir_dump_samples);
-EXPORT_SYMBOL_GPL(ir_decode_biphase);
-EXPORT_SYMBOL_GPL(ir_decode_pulsedistance);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
-
diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c
new file mode 100644
index 0000000..397cff8
--- /dev/null
+++ b/drivers/media/common/ir-functions.c
@@ -0,0 +1,272 @@
+/*
+ *
+ * some common structs and functions to handle infrared remotes via
+ * input layer ...
+ *
+ * (c) 2003 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <media/ir-common.h>
+
+/* -------------------------------------------------------------------------- */
+
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_LICENSE("GPL");
+
+static int repeat = 1;
+module_param(repeat, int, 0444);
+MODULE_PARM_DESC(repeat,"auto-repeat for IR keys (default: on)");
+
+static int debug = 0;    /* debug level (0,1,2) */
+module_param(debug, int, 0644);
+
+#define dprintk(level, fmt, arg...)	if (debug >= level) \
+	printk(KERN_DEBUG fmt , ## arg)
+
+/* -------------------------------------------------------------------------- */
+
+static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir)
+{
+	if (KEY_RESERVED == ir->keycode) {
+		printk(KERN_INFO "%s: unknown key: key=0x%02x raw=0x%02x down=%d\n",
+		       dev->name,ir->ir_key,ir->ir_raw,ir->keypressed);
+		return;
+	}
+	dprintk(1,"%s: key event code=%d down=%d\n",
+		dev->name,ir->keycode,ir->keypressed);
+	input_report_key(dev,ir->keycode,ir->keypressed);
+	input_sync(dev);
+}
+
+/* -------------------------------------------------------------------------- */
+
+void ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
+		   int ir_type, IR_KEYTAB_TYPE *ir_codes)
+{
+	int i;
+
+	ir->ir_type = ir_type;
+	if (ir_codes)
+		memcpy(ir->ir_codes, ir_codes, sizeof(ir->ir_codes));
+
+
+	dev->keycode     = ir->ir_codes;
+	dev->keycodesize = sizeof(IR_KEYTAB_TYPE);
+	dev->keycodemax  = IR_KEYTAB_SIZE;
+	for (i = 0; i < IR_KEYTAB_SIZE; i++)
+		set_bit(ir->ir_codes[i], dev->keybit);
+	clear_bit(0, dev->keybit);
+
+	set_bit(EV_KEY, dev->evbit);
+	if (repeat)
+		set_bit(EV_REP, dev->evbit);
+}
+
+void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir)
+{
+	if (ir->keypressed) {
+		ir->keypressed = 0;
+		ir_input_key_event(dev,ir);
+	}
+}
+
+void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir,
+		      u32 ir_key, u32 ir_raw)
+{
+	u32 keycode = IR_KEYCODE(ir->ir_codes, ir_key);
+
+	if (ir->keypressed && ir->keycode != keycode) {
+		ir->keypressed = 0;
+		ir_input_key_event(dev,ir);
+	}
+	if (!ir->keypressed) {
+		ir->ir_key  = ir_key;
+		ir->ir_raw  = ir_raw;
+		ir->keycode = keycode;
+		ir->keypressed = 1;
+		ir_input_key_event(dev,ir);
+	}
+}
+
+/* -------------------------------------------------------------------------- */
+
+u32 ir_extract_bits(u32 data, u32 mask)
+{
+	int mbit, vbit;
+	u32 value;
+
+	value = 0;
+	vbit  = 0;
+	for (mbit = 0; mbit < 32; mbit++) {
+		if (!(mask & ((u32)1 << mbit)))
+			continue;
+		if (data & ((u32)1 << mbit))
+			value |= (1 << vbit);
+		vbit++;
+	}
+	return value;
+}
+
+static int inline getbit(u32 *samples, int bit)
+{
+	return (samples[bit/32] & (1 << (31-(bit%32)))) ? 1 : 0;
+}
+
+/* sump raw samples for visual debugging ;) */
+int ir_dump_samples(u32 *samples, int count)
+{
+	int i, bit, start;
+
+	printk(KERN_DEBUG "ir samples: ");
+	start = 0;
+	for (i = 0; i < count * 32; i++) {
+		bit = getbit(samples,i);
+		if (bit)
+			start = 1;
+		if (0 == start)
+			continue;
+		printk("%s", bit ? "#" : "_");
+	}
+	printk("\n");
+	return 0;
+}
+
+/* decode raw samples, pulse distance coding used by NEC remotes */
+int ir_decode_pulsedistance(u32 *samples, int count, int low, int high)
+{
+	int i,last,bit,len;
+	u32 curBit;
+	u32 value;
+
+	/* find start burst */
+	for (i = len = 0; i < count * 32; i++) {
+		bit = getbit(samples,i);
+		if (bit) {
+			len++;
+		} else {
+			if (len >= 29)
+				break;
+			len = 0;
+		}
+	}
+
+	/* start burst to short */
+	if (len < 29)
+		return 0xffffffff;
+
+	/* find start silence */
+	for (len = 0; i < count * 32; i++) {
+		bit = getbit(samples,i);
+		if (bit) {
+			break;
+		} else {
+			len++;
+		}
+	}
+
+	/* silence to short */
+	if (len < 7)
+		return 0xffffffff;
+
+	/* go decoding */
+	len   = 0;
+	last = 1;
+	value = 0; curBit = 1;
+	for (; i < count * 32; i++) {
+		bit  = getbit(samples,i);
+		if (last) {
+			if(bit) {
+				continue;
+			} else {
+				len = 1;
+			}
+		} else {
+			if (bit) {
+				if (len > (low + high) /2)
+					value |= curBit;
+				curBit <<= 1;
+				if (curBit == 1)
+					break;
+			} else {
+				len++;
+			}
+		}
+		last = bit;
+	}
+
+	return value;
+}
+
+/* decode raw samples, biphase coding, used by rc5 for example */
+int ir_decode_biphase(u32 *samples, int count, int low, int high)
+{
+	int i,last,bit,len,flips;
+	u32 value;
+
+	/* find start bit (1) */
+	for (i = 0; i < 32; i++) {
+		bit = getbit(samples,i);
+		if (bit)
+			break;
+	}
+
+	/* go decoding */
+	len   = 0;
+	flips = 0;
+	value = 1;
+	for (; i < count * 32; i++) {
+		if (len > high)
+			break;
+		if (flips > 1)
+			break;
+		last = bit;
+		bit  = getbit(samples,i);
+		if (last == bit) {
+			len++;
+			continue;
+		}
+		if (len < low) {
+			len++;
+			flips++;
+			continue;
+		}
+		value <<= 1;
+		value |= bit;
+		flips = 0;
+		len   = 1;
+	}
+	return value;
+}
+
+EXPORT_SYMBOL_GPL(ir_input_init);
+EXPORT_SYMBOL_GPL(ir_input_nokey);
+EXPORT_SYMBOL_GPL(ir_input_keydown);
+
+EXPORT_SYMBOL_GPL(ir_extract_bits);
+EXPORT_SYMBOL_GPL(ir_dump_samples);
+EXPORT_SYMBOL_GPL(ir_decode_biphase);
+EXPORT_SYMBOL_GPL(ir_decode_pulsedistance);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
+
diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
new file mode 100644
index 0000000..a294d5c
--- /dev/null
+++ b/drivers/media/common/ir-keymaps.c
@@ -0,0 +1,1415 @@
+/*
+
+
+    Keytables for supported remote controls. This file is part of
+    video4linux.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include <linux/input.h>
+#include <media/ir-common.h>
+
+/* empty keytable, can be used as placeholder for not-yet created keytables */
+IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE] = {
+	[ 0x2a ] = KEY_COFFEE,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_empty);
+
+/* Matt Jesson <dvb@jesson.eclipse.co.uk */
+IR_KEYTAB_TYPE ir_codes_avermedia_dvbt[IR_KEYTAB_SIZE] = {
+	[ 0x28 ] = KEY_0,         //'0' / 'enter'
+	[ 0x22 ] = KEY_1,         //'1'
+	[ 0x12 ] = KEY_2,         //'2' / 'up arrow'
+	[ 0x32 ] = KEY_3,         //'3'
+	[ 0x24 ] = KEY_4,         //'4' / 'left arrow'
+	[ 0x14 ] = KEY_5,         //'5'
+	[ 0x34 ] = KEY_6,         //'6' / 'right arrow'
+	[ 0x26 ] = KEY_7,         //'7'
+	[ 0x16 ] = KEY_8,         //'8' / 'down arrow'
+	[ 0x36 ] = KEY_9,         //'9'
+
+	[ 0x20 ] = KEY_LIST,        // 'source'
+	[ 0x10 ] = KEY_TEXT,        // 'teletext'
+	[ 0x00 ] = KEY_POWER,       // 'power'
+	[ 0x04 ] = KEY_AUDIO,       // 'audio'
+	[ 0x06 ] = KEY_ZOOM,        // 'full screen'
+	[ 0x18 ] = KEY_VIDEO,       // 'display'
+	[ 0x38 ] = KEY_SEARCH,      // 'loop'
+	[ 0x08 ] = KEY_INFO,        // 'preview'
+	[ 0x2a ] = KEY_REWIND,      // 'backward <<'
+	[ 0x1a ] = KEY_FASTFORWARD, // 'forward >>'
+	[ 0x3a ] = KEY_RECORD,      // 'capture'
+	[ 0x0a ] = KEY_MUTE,        // 'mute'
+	[ 0x2c ] = KEY_RECORD,      // 'record'
+	[ 0x1c ] = KEY_PAUSE,       // 'pause'
+	[ 0x3c ] = KEY_STOP,        // 'stop'
+	[ 0x0c ] = KEY_PLAY,        // 'play'
+	[ 0x2e ] = KEY_RED,         // 'red'
+	[ 0x01 ] = KEY_BLUE,        // 'blue' / 'cancel'
+	[ 0x0e ] = KEY_YELLOW,      // 'yellow' / 'ok'
+	[ 0x21 ] = KEY_GREEN,       // 'green'
+	[ 0x11 ] = KEY_CHANNELDOWN, // 'channel -'
+	[ 0x31 ] = KEY_CHANNELUP,   // 'channel +'
+	[ 0x1e ] = KEY_VOLUMEDOWN,  // 'volume -'
+	[ 0x3e ] = KEY_VOLUMEUP,    // 'volume +'
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_avermedia_dvbt);
+
+/* Attila Kondoros <attila.kondoros@chello.hu> */
+IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE] = {
+
+	[ 0x01 ] = KEY_1,
+	[ 0x02 ] = KEY_2,
+	[ 0x03 ] = KEY_3,
+	[ 0x04 ] = KEY_4,
+	[ 0x05 ] = KEY_5,
+	[ 0x06 ] = KEY_6,
+	[ 0x07 ] = KEY_7,
+	[ 0x08 ] = KEY_8,
+	[ 0x09 ] = KEY_9,
+	[ 0x00 ] = KEY_0,
+	[ 0x17 ] = KEY_LAST,        // +100
+	[ 0x0a ] = KEY_LIST,        // recall
+
+
+	[ 0x1c ] = KEY_TUNER,       // TV/FM
+	[ 0x15 ] = KEY_SEARCH,      // scan
+	[ 0x12 ] = KEY_POWER,       // power
+	[ 0x1f ] = KEY_VOLUMEDOWN,  // vol up
+	[ 0x1b ] = KEY_VOLUMEUP,    // vol down
+	[ 0x1e ] = KEY_CHANNELDOWN, // chn up
+	[ 0x1a ] = KEY_CHANNELUP,   // chn down
+
+	[ 0x11 ] = KEY_VIDEO,       // video
+	[ 0x0f ] = KEY_ZOOM,        // full screen
+	[ 0x13 ] = KEY_MUTE,        // mute/unmute
+	[ 0x10 ] = KEY_TEXT,        // min
+
+	[ 0x0d ] = KEY_STOP,        // freeze
+	[ 0x0e ] = KEY_RECORD,      // record
+	[ 0x1d ] = KEY_PLAYPAUSE,   // stop
+	[ 0x19 ] = KEY_PLAY,        // play
+
+	[ 0x16 ] = KEY_GOTO,        // osd
+	[ 0x14 ] = KEY_REFRESH,     // default
+	[ 0x0c ] = KEY_KPPLUS,      // fine tune >>>>
+	[ 0x18 ] = KEY_KPMINUS      // fine tune <<<<
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_apac_viewcomp);
+
+/* ---------------------------------------------------------------------- */
+
+IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE] = {
+
+	[ 0x1e ] = KEY_POWER,       // power
+	[ 0x07 ] = KEY_MEDIA,       // source
+	[ 0x1c ] = KEY_SEARCH,      // scan
+
+/* FIXME: duplicate keycodes?
+ *
+ * These four keys seem to share the same GPIO as CH+, CH-, <<< and >>>
+ * The GPIO values are
+ * 6397fb for both "Scan <" and "CH -",
+ * 639ffb for "Scan >" and "CH+",
+ * 6384fb for "Tune <" and "<<<",
+ * 638cfb for "Tune >" and ">>>", regardless of the mask.
+ *
+ *	[ 0x17 ] = KEY_BACK,        // fm scan <<
+ *	[ 0x1f ] = KEY_FORWARD,     // fm scan >>
+ *
+ *	[ 0x04 ] = KEY_LEFT,        // fm tuning <
+ *	[ 0x0c ] = KEY_RIGHT,       // fm tuning >
+ *
+ * For now, these four keys are disabled. Pressing them will generate
+ * the CH+/CH-/<<</>>> events
+ */
+
+	[ 0x03 ] = KEY_TUNER,       // TV/FM
+
+	[ 0x00 ] = KEY_RECORD,
+	[ 0x08 ] = KEY_STOP,
+	[ 0x11 ] = KEY_PLAY,
+
+	[ 0x1a ] = KEY_PLAYPAUSE,   // freeze
+	[ 0x19 ] = KEY_ZOOM,        // zoom
+	[ 0x0f ] = KEY_TEXT,        // min
+
+	[ 0x01 ] = KEY_1,
+	[ 0x0b ] = KEY_2,
+	[ 0x1b ] = KEY_3,
+	[ 0x05 ] = KEY_4,
+	[ 0x09 ] = KEY_5,
+	[ 0x15 ] = KEY_6,
+	[ 0x06 ] = KEY_7,
+	[ 0x0a ] = KEY_8,
+	[ 0x12 ] = KEY_9,
+	[ 0x02 ] = KEY_0,
+	[ 0x10 ] = KEY_LAST,        // +100
+	[ 0x13 ] = KEY_LIST,        // recall
+
+	[ 0x1f ] = KEY_CHANNELUP,   // chn down
+	[ 0x17 ] = KEY_CHANNELDOWN, // chn up
+	[ 0x16 ] = KEY_VOLUMEUP,    // vol down
+	[ 0x14 ] = KEY_VOLUMEDOWN,  // vol up
+
+	[ 0x04 ] = KEY_KPMINUS,     // <<<
+	[ 0x0e ] = KEY_SETUP,       // function
+	[ 0x0c ] = KEY_KPPLUS,      // >>>
+
+	[ 0x0d ] = KEY_GOTO,        // mts
+	[ 0x1d ] = KEY_REFRESH,     // reset
+	[ 0x18 ] = KEY_MUTE         // mute/unmute
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_pixelview);
+
+IR_KEYTAB_TYPE ir_codes_nebula[IR_KEYTAB_SIZE] = {
+	[ 0x00 ] = KEY_0,
+	[ 0x01 ] = KEY_1,
+	[ 0x02 ] = KEY_2,
+	[ 0x03 ] = KEY_3,
+	[ 0x04 ] = KEY_4,
+	[ 0x05 ] = KEY_5,
+	[ 0x06 ] = KEY_6,
+	[ 0x07 ] = KEY_7,
+	[ 0x08 ] = KEY_8,
+	[ 0x09 ] = KEY_9,
+	[ 0x0a ] = KEY_TV,
+	[ 0x0b ] = KEY_AUX,
+	[ 0x0c ] = KEY_DVD,
+	[ 0x0d ] = KEY_POWER,
+	[ 0x0e ] = KEY_MHP,	/* labelled 'Picture' */
+	[ 0x0f ] = KEY_AUDIO,
+	[ 0x10 ] = KEY_INFO,
+	[ 0x11 ] = KEY_F13,	/* 16:9 */
+	[ 0x12 ] = KEY_F14,	/* 14:9 */
+	[ 0x13 ] = KEY_EPG,
+	[ 0x14 ] = KEY_EXIT,
+	[ 0x15 ] = KEY_MENU,
+	[ 0x16 ] = KEY_UP,
+	[ 0x17 ] = KEY_DOWN,
+	[ 0x18 ] = KEY_LEFT,
+	[ 0x19 ] = KEY_RIGHT,
+	[ 0x1a ] = KEY_ENTER,
+	[ 0x1b ] = KEY_CHANNELUP,
+	[ 0x1c ] = KEY_CHANNELDOWN,
+	[ 0x1d ] = KEY_VOLUMEUP,
+	[ 0x1e ] = KEY_VOLUMEDOWN,
+	[ 0x1f ] = KEY_RED,
+	[ 0x20 ] = KEY_GREEN,
+	[ 0x21 ] = KEY_YELLOW,
+	[ 0x22 ] = KEY_BLUE,
+	[ 0x23 ] = KEY_SUBTITLE,
+	[ 0x24 ] = KEY_F15,	/* AD */
+	[ 0x25 ] = KEY_TEXT,
+	[ 0x26 ] = KEY_MUTE,
+	[ 0x27 ] = KEY_REWIND,
+	[ 0x28 ] = KEY_STOP,
+	[ 0x29 ] = KEY_PLAY,
+	[ 0x2a ] = KEY_FASTFORWARD,
+	[ 0x2b ] = KEY_F16,	/* chapter */
+	[ 0x2c ] = KEY_PAUSE,
+	[ 0x2d ] = KEY_PLAY,
+	[ 0x2e ] = KEY_RECORD,
+	[ 0x2f ] = KEY_F17,	/* picture in picture */
+	[ 0x30 ] = KEY_KPPLUS,	/* zoom in */
+	[ 0x31 ] = KEY_KPMINUS,	/* zoom out */
+	[ 0x32 ] = KEY_F18,	/* capture */
+	[ 0x33 ] = KEY_F19,	/* web */
+	[ 0x34 ] = KEY_EMAIL,
+	[ 0x35 ] = KEY_PHONE,
+	[ 0x36 ] = KEY_PC
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_nebula);
+
+/* DigitalNow DNTV Live DVB-T Remote */
+IR_KEYTAB_TYPE ir_codes_dntv_live_dvb_t[IR_KEYTAB_SIZE] = {
+	[ 0x00 ] = KEY_ESC,		/* 'go up a level?' */
+	/* Keys 0 to 9 */
+	[ 0x0a ] = KEY_0,
+	[ 0x01 ] = KEY_1,
+	[ 0x02 ] = KEY_2,
+	[ 0x03 ] = KEY_3,
+	[ 0x04 ] = KEY_4,
+	[ 0x05 ] = KEY_5,
+	[ 0x06 ] = KEY_6,
+	[ 0x07 ] = KEY_7,
+	[ 0x08 ] = KEY_8,
+	[ 0x09 ] = KEY_9,
+
+	[ 0x0b ] = KEY_TUNER,		/* tv/fm */
+	[ 0x0c ] = KEY_SEARCH,		/* scan */
+	[ 0x0d ] = KEY_STOP,
+	[ 0x0e ] = KEY_PAUSE,
+	[ 0x0f ] = KEY_LIST,		/* source */
+
+	[ 0x10 ] = KEY_MUTE,
+	[ 0x11 ] = KEY_REWIND,		/* backward << */
+	[ 0x12 ] = KEY_POWER,
+	[ 0x13 ] = KEY_S,			/* snap */
+	[ 0x14 ] = KEY_AUDIO,		/* stereo */
+	[ 0x15 ] = KEY_CLEAR,		/* reset */
+	[ 0x16 ] = KEY_PLAY,
+	[ 0x17 ] = KEY_ENTER,
+	[ 0x18 ] = KEY_ZOOM,		/* full screen */
+	[ 0x19 ] = KEY_FASTFORWARD,	/* forward >> */
+	[ 0x1a ] = KEY_CHANNELUP,
+	[ 0x1b ] = KEY_VOLUMEUP,
+	[ 0x1c ] = KEY_INFO,		/* preview */
+	[ 0x1d ] = KEY_RECORD,		/* record */
+	[ 0x1e ] = KEY_CHANNELDOWN,
+	[ 0x1f ] = KEY_VOLUMEDOWN,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_dntv_live_dvb_t);
+
+/* ---------------------------------------------------------------------- */
+
+/* IO-DATA BCTV7E Remote */
+IR_KEYTAB_TYPE ir_codes_iodata_bctv7e[IR_KEYTAB_SIZE] = {
+	[ 0x40 ] = KEY_TV,
+	[ 0x20 ] = KEY_RADIO,		/* FM */
+	[ 0x60 ] = KEY_EPG,
+	[ 0x00 ] = KEY_POWER,
+
+	/* Keys 0 to 9 */
+	[ 0x44 ] = KEY_0,		/* 10 */
+	[ 0x50 ] = KEY_1,
+	[ 0x30 ] = KEY_2,
+	[ 0x70 ] = KEY_3,
+	[ 0x48 ] = KEY_4,
+	[ 0x28 ] = KEY_5,
+	[ 0x68 ] = KEY_6,
+	[ 0x58 ] = KEY_7,
+	[ 0x38 ] = KEY_8,
+	[ 0x78 ] = KEY_9,
+
+	[ 0x10 ] = KEY_L,			/* Live */
+	[ 0x08 ] = KEY_T,			/* Time Shift */
+
+	[ 0x18 ] = KEY_PLAYPAUSE,		/* Play */
+
+	[ 0x24 ] = KEY_ENTER,		/* 11 */
+	[ 0x64 ] = KEY_ESC,		/* 12 */
+	[ 0x04 ] = KEY_M,			/* Multi */
+
+	[ 0x54 ] = KEY_VIDEO,
+	[ 0x34 ] = KEY_CHANNELUP,
+	[ 0x74 ] = KEY_VOLUMEUP,
+	[ 0x14 ] = KEY_MUTE,
+
+	[ 0x4c ] = KEY_S,			/* SVIDEO */
+	[ 0x2c ] = KEY_CHANNELDOWN,
+	[ 0x6c ] = KEY_VOLUMEDOWN,
+	[ 0x0c ] = KEY_ZOOM,
+
+	[ 0x5c ] = KEY_PAUSE,
+	[ 0x3c ] = KEY_C,			/* || (red) */
+	[ 0x7c ] = KEY_RECORD,		/* recording */
+	[ 0x1c ] = KEY_STOP,
+
+	[ 0x41 ] = KEY_REWIND,		/* backward << */
+	[ 0x21 ] = KEY_PLAY,
+	[ 0x61 ] = KEY_FASTFORWARD,	/* forward >> */
+	[ 0x01 ] = KEY_NEXT,		/* skip >| */
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_iodata_bctv7e);
+
+/* ---------------------------------------------------------------------- */
+
+/* ADS Tech Instant TV DVB-T PCI Remote */
+IR_KEYTAB_TYPE ir_codes_adstech_dvb_t_pci[IR_KEYTAB_SIZE] = {
+	/* Keys 0 to 9 */
+	[ 0x4d ] = KEY_0,
+	[ 0x57 ] = KEY_1,
+	[ 0x4f ] = KEY_2,
+	[ 0x53 ] = KEY_3,
+	[ 0x56 ] = KEY_4,
+	[ 0x4e ] = KEY_5,
+	[ 0x5e ] = KEY_6,
+	[ 0x54 ] = KEY_7,
+	[ 0x4c ] = KEY_8,
+	[ 0x5c ] = KEY_9,
+
+	[ 0x5b ] = KEY_POWER,
+	[ 0x5f ] = KEY_MUTE,
+	[ 0x55 ] = KEY_GOTO,
+	[ 0x5d ] = KEY_SEARCH,
+	[ 0x17 ] = KEY_EPG,		/* Guide */
+	[ 0x1f ] = KEY_MENU,
+	[ 0x0f ] = KEY_UP,
+	[ 0x46 ] = KEY_DOWN,
+	[ 0x16 ] = KEY_LEFT,
+	[ 0x1e ] = KEY_RIGHT,
+	[ 0x0e ] = KEY_SELECT,		/* Enter */
+	[ 0x5a ] = KEY_INFO,
+	[ 0x52 ] = KEY_EXIT,
+	[ 0x59 ] = KEY_PREVIOUS,
+	[ 0x51 ] = KEY_NEXT,
+	[ 0x58 ] = KEY_REWIND,
+	[ 0x50 ] = KEY_FORWARD,
+	[ 0x44 ] = KEY_PLAYPAUSE,
+	[ 0x07 ] = KEY_STOP,
+	[ 0x1b ] = KEY_RECORD,
+	[ 0x13 ] = KEY_TUNER,		/* Live */
+	[ 0x0a ] = KEY_A,
+	[ 0x12 ] = KEY_B,
+	[ 0x03 ] = KEY_PROG1,		/* 1 */
+	[ 0x01 ] = KEY_PROG2,		/* 2 */
+	[ 0x00 ] = KEY_PROG3,		/* 3 */
+	[ 0x06 ] = KEY_DVD,
+	[ 0x48 ] = KEY_AUX,		/* Photo */
+	[ 0x40 ] = KEY_VIDEO,
+	[ 0x19 ] = KEY_AUDIO,		/* Music */
+	[ 0x0b ] = KEY_CHANNELUP,
+	[ 0x08 ] = KEY_CHANNELDOWN,
+	[ 0x15 ] = KEY_VOLUMEUP,
+	[ 0x1c ] = KEY_VOLUMEDOWN,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_adstech_dvb_t_pci);
+
+/* ---------------------------------------------------------------------- */
+
+/* MSI TV@nywhere remote */
+IR_KEYTAB_TYPE ir_codes_msi_tvanywhere[IR_KEYTAB_SIZE] = {
+	/* Keys 0 to 9 */
+	[ 0x00 ] = KEY_0,
+	[ 0x01 ] = KEY_1,
+	[ 0x02 ] = KEY_2,
+	[ 0x03 ] = KEY_3,
+	[ 0x04 ] = KEY_4,
+	[ 0x05 ] = KEY_5,
+	[ 0x06 ] = KEY_6,
+	[ 0x07 ] = KEY_7,
+	[ 0x08 ] = KEY_8,
+	[ 0x09 ] = KEY_9,
+
+	[ 0x0c ] = KEY_MUTE,
+	[ 0x0f ] = KEY_SCREEN,		/* Full Screen */
+	[ 0x10 ] = KEY_F,			/* Funtion */
+	[ 0x11 ] = KEY_T,			/* Time shift */
+	[ 0x12 ] = KEY_POWER,
+	[ 0x13 ] = KEY_MEDIA,		/* MTS */
+	[ 0x14 ] = KEY_SLOW,
+	[ 0x16 ] = KEY_REWIND,		/* backward << */
+	[ 0x17 ] = KEY_ENTER,		/* Return */
+	[ 0x18 ] = KEY_FASTFORWARD,	/* forward >> */
+	[ 0x1a ] = KEY_CHANNELUP,
+	[ 0x1b ] = KEY_VOLUMEUP,
+	[ 0x1e ] = KEY_CHANNELDOWN,
+	[ 0x1f ] = KEY_VOLUMEDOWN,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_msi_tvanywhere);
+
+/* ---------------------------------------------------------------------- */
+
+/* Cinergy 1400 DVB-T */
+IR_KEYTAB_TYPE ir_codes_cinergy_1400[IR_KEYTAB_SIZE] = {
+	[ 0x01 ] = KEY_POWER,
+	[ 0x02 ] = KEY_1,
+	[ 0x03 ] = KEY_2,
+	[ 0x04 ] = KEY_3,
+	[ 0x05 ] = KEY_4,
+	[ 0x06 ] = KEY_5,
+	[ 0x07 ] = KEY_6,
+	[ 0x08 ] = KEY_7,
+	[ 0x09 ] = KEY_8,
+	[ 0x0a ] = KEY_9,
+	[ 0x0c ] = KEY_0,
+
+	[ 0x0b ] = KEY_VIDEO,
+	[ 0x0d ] = KEY_REFRESH,
+	[ 0x0e ] = KEY_SELECT,
+	[ 0x0f ] = KEY_EPG,
+	[ 0x10 ] = KEY_UP,
+	[ 0x11 ] = KEY_LEFT,
+	[ 0x12 ] = KEY_OK,
+	[ 0x13 ] = KEY_RIGHT,
+	[ 0x14 ] = KEY_DOWN,
+	[ 0x15 ] = KEY_TEXT,
+	[ 0x16 ] = KEY_INFO,
+
+	[ 0x17 ] = KEY_RED,
+	[ 0x18 ] = KEY_GREEN,
+	[ 0x19 ] = KEY_YELLOW,
+	[ 0x1a ] = KEY_BLUE,
+
+	[ 0x1b ] = KEY_CHANNELUP,
+	[ 0x1c ] = KEY_VOLUMEUP,
+	[ 0x1d ] = KEY_MUTE,
+	[ 0x1e ] = KEY_VOLUMEDOWN,
+	[ 0x1f ] = KEY_CHANNELDOWN,
+
+	[ 0x40 ] = KEY_PAUSE,
+	[ 0x4c ] = KEY_PLAY,
+	[ 0x58 ] = KEY_RECORD,
+	[ 0x54 ] = KEY_PREVIOUS,
+	[ 0x48 ] = KEY_STOP,
+	[ 0x5c ] = KEY_NEXT,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_cinergy_1400);
+
+/* ---------------------------------------------------------------------- */
+
+/* AVERTV STUDIO 303 Remote */
+IR_KEYTAB_TYPE ir_codes_avertv_303[IR_KEYTAB_SIZE] = {
+	[ 0x2a ] = KEY_1,
+	[ 0x32 ] = KEY_2,
+	[ 0x3a ] = KEY_3,
+	[ 0x4a ] = KEY_4,
+	[ 0x52 ] = KEY_5,
+	[ 0x5a ] = KEY_6,
+	[ 0x6a ] = KEY_7,
+	[ 0x72 ] = KEY_8,
+	[ 0x7a ] = KEY_9,
+	[ 0x0e ] = KEY_0,
+
+	[ 0x02 ] = KEY_POWER,
+	[ 0x22 ] = KEY_VIDEO,
+	[ 0x42 ] = KEY_AUDIO,
+	[ 0x62 ] = KEY_ZOOM,
+	[ 0x0a ] = KEY_TV,
+	[ 0x12 ] = KEY_CD,
+	[ 0x1a ] = KEY_TEXT,
+
+	[ 0x16 ] = KEY_SUBTITLE,
+	[ 0x1e ] = KEY_REWIND,
+	[ 0x06 ] = KEY_PRINT,
+
+	[ 0x2e ] = KEY_SEARCH,
+	[ 0x36 ] = KEY_SLEEP,
+	[ 0x3e ] = KEY_SHUFFLE,
+	[ 0x26 ] = KEY_MUTE,
+
+	[ 0x4e ] = KEY_RECORD,
+	[ 0x56 ] = KEY_PAUSE,
+	[ 0x5e ] = KEY_STOP,
+	[ 0x46 ] = KEY_PLAY,
+
+	[ 0x6e ] = KEY_RED,
+	[ 0x0b ] = KEY_GREEN,
+	[ 0x66 ] = KEY_YELLOW,
+	[ 0x03 ] = KEY_BLUE,
+
+	[ 0x76 ] = KEY_LEFT,
+	[ 0x7e ] = KEY_RIGHT,
+	[ 0x13 ] = KEY_DOWN,
+	[ 0x1b ] = KEY_UP,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_avertv_303);
+
+/* ---------------------------------------------------------------------- */
+
+/* DigitalNow DNTV Live! DVB-T Pro Remote */
+IR_KEYTAB_TYPE ir_codes_dntv_live_dvbt_pro[IR_KEYTAB_SIZE] = {
+	[ 0x16 ] = KEY_POWER,
+	[ 0x5b ] = KEY_HOME,
+
+	[ 0x55 ] = KEY_TV,		/* live tv */
+	[ 0x58 ] = KEY_TUNER,		/* digital Radio */
+	[ 0x5a ] = KEY_RADIO,		/* FM radio */
+	[ 0x59 ] = KEY_DVD,		/* dvd menu */
+	[ 0x03 ] = KEY_1,
+	[ 0x01 ] = KEY_2,
+	[ 0x06 ] = KEY_3,
+	[ 0x09 ] = KEY_4,
+	[ 0x1d ] = KEY_5,
+	[ 0x1f ] = KEY_6,
+	[ 0x0d ] = KEY_7,
+	[ 0x19 ] = KEY_8,
+	[ 0x1b ] = KEY_9,
+	[ 0x0c ] = KEY_CANCEL,
+	[ 0x15 ] = KEY_0,
+	[ 0x4a ] = KEY_CLEAR,
+	[ 0x13 ] = KEY_BACK,
+	[ 0x00 ] = KEY_TAB,
+	[ 0x4b ] = KEY_UP,
+	[ 0x4e ] = KEY_LEFT,
+	[ 0x4f ] = KEY_OK,
+	[ 0x52 ] = KEY_RIGHT,
+	[ 0x51 ] = KEY_DOWN,
+	[ 0x1e ] = KEY_VOLUMEUP,
+	[ 0x0a ] = KEY_VOLUMEDOWN,
+	[ 0x02 ] = KEY_CHANNELDOWN,
+	[ 0x05 ] = KEY_CHANNELUP,
+	[ 0x11 ] = KEY_RECORD,
+	[ 0x14 ] = KEY_PLAY,
+	[ 0x4c ] = KEY_PAUSE,
+	[ 0x1a ] = KEY_STOP,
+	[ 0x40 ] = KEY_REWIND,
+	[ 0x12 ] = KEY_FASTFORWARD,
+	[ 0x41 ] = KEY_PREVIOUSSONG,	/* replay |< */
+	[ 0x42 ] = KEY_NEXTSONG,	/* skip >| */
+	[ 0x54 ] = KEY_CAMERA,		/* capture */
+	[ 0x50 ] = KEY_LANGUAGE,	/* sap */
+	[ 0x47 ] = KEY_TV2,		/* pip */
+	[ 0x4d ] = KEY_SCREEN,
+	[ 0x43 ] = KEY_SUBTITLE,
+	[ 0x10 ] = KEY_MUTE,
+	[ 0x49 ] = KEY_AUDIO,		/* l/r */
+	[ 0x07 ] = KEY_SLEEP,
+	[ 0x08 ] = KEY_VIDEO,		/* a/v */
+	[ 0x0e ] = KEY_PREVIOUS,	/* recall */
+	[ 0x45 ] = KEY_ZOOM,		/* zoom + */
+	[ 0x46 ] = KEY_ANGLE,		/* zoom - */
+	[ 0x56 ] = KEY_RED,
+	[ 0x57 ] = KEY_GREEN,
+	[ 0x5c ] = KEY_YELLOW,
+	[ 0x5d ] = KEY_BLUE,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_dntv_live_dvbt_pro);
+
+IR_KEYTAB_TYPE ir_codes_em_terratec[IR_KEYTAB_SIZE] = {
+	[ 0x01 ] = KEY_CHANNEL,
+	[ 0x02 ] = KEY_SELECT,
+	[ 0x03 ] = KEY_MUTE,
+	[ 0x04 ] = KEY_POWER,
+	[ 0x05 ] = KEY_1,
+	[ 0x06 ] = KEY_2,
+	[ 0x07 ] = KEY_3,
+	[ 0x08 ] = KEY_CHANNELUP,
+	[ 0x09 ] = KEY_4,
+	[ 0x0a ] = KEY_5,
+	[ 0x0b ] = KEY_6,
+	[ 0x0c ] = KEY_CHANNELDOWN,
+	[ 0x0d ] = KEY_7,
+	[ 0x0e ] = KEY_8,
+	[ 0x0f ] = KEY_9,
+	[ 0x10 ] = KEY_VOLUMEUP,
+	[ 0x11 ] = KEY_0,
+	[ 0x12 ] = KEY_MENU,
+	[ 0x13 ] = KEY_PRINT,
+	[ 0x14 ] = KEY_VOLUMEDOWN,
+	[ 0x16 ] = KEY_PAUSE,
+	[ 0x18 ] = KEY_RECORD,
+	[ 0x19 ] = KEY_REWIND,
+	[ 0x1a ] = KEY_PLAY,
+	[ 0x1b ] = KEY_FORWARD,
+	[ 0x1c ] = KEY_BACKSPACE,
+	[ 0x1e ] = KEY_STOP,
+	[ 0x40 ] = KEY_ZOOM,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_em_terratec);
+
+IR_KEYTAB_TYPE ir_codes_em_pinnacle_usb[IR_KEYTAB_SIZE] = {
+	[ 0x3a ] = KEY_0,
+	[ 0x31 ] = KEY_1,
+	[ 0x32 ] = KEY_2,
+	[ 0x33 ] = KEY_3,
+	[ 0x34 ] = KEY_4,
+	[ 0x35 ] = KEY_5,
+	[ 0x36 ] = KEY_6,
+	[ 0x37 ] = KEY_7,
+	[ 0x38 ] = KEY_8,
+	[ 0x39 ] = KEY_9,
+
+	[ 0x2f ] = KEY_POWER,
+
+	[ 0x2e ] = KEY_P,
+	[ 0x1f ] = KEY_L,
+	[ 0x2b ] = KEY_I,
+
+	[ 0x2d ] = KEY_ZOOM,
+	[ 0x1e ] = KEY_ZOOM,
+	[ 0x1b ] = KEY_VOLUMEUP,
+	[ 0x0f ] = KEY_VOLUMEDOWN,
+	[ 0x17 ] = KEY_CHANNELUP,
+	[ 0x1c ] = KEY_CHANNELDOWN,
+	[ 0x25 ] = KEY_INFO,
+
+	[ 0x3c ] = KEY_MUTE,
+
+	[ 0x3d ] = KEY_LEFT,
+	[ 0x3b ] = KEY_RIGHT,
+
+	[ 0x3f ] = KEY_UP,
+	[ 0x3e ] = KEY_DOWN,
+	[ 0x1a ] = KEY_PAUSE,
+
+	[ 0x1d ] = KEY_MENU,
+	[ 0x19 ] = KEY_PLAY,
+	[ 0x16 ] = KEY_REWIND,
+	[ 0x13 ] = KEY_FORWARD,
+	[ 0x15 ] = KEY_PAUSE,
+	[ 0x0e ] = KEY_REWIND,
+	[ 0x0d ] = KEY_PLAY,
+	[ 0x0b ] = KEY_STOP,
+	[ 0x07 ] = KEY_FORWARD,
+	[ 0x27 ] = KEY_RECORD,
+	[ 0x26 ] = KEY_TUNER,
+	[ 0x29 ] = KEY_TEXT,
+	[ 0x2a ] = KEY_MEDIA,
+	[ 0x18 ] = KEY_EPG,
+	[ 0x27 ] = KEY_RECORD,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_em_pinnacle_usb);
+
+IR_KEYTAB_TYPE ir_codes_flyvideo[IR_KEYTAB_SIZE] = {
+	[ 0x0f ] = KEY_0,
+	[ 0x03 ] = KEY_1,
+	[ 0x04 ] = KEY_2,
+	[ 0x05 ] = KEY_3,
+	[ 0x07 ] = KEY_4,
+	[ 0x08 ] = KEY_5,
+	[ 0x09 ] = KEY_6,
+	[ 0x0b ] = KEY_7,
+	[ 0x0c ] = KEY_8,
+	[ 0x0d ] = KEY_9,
+
+	[ 0x0e ] = KEY_MODE,         // Air/Cable
+	[ 0x11 ] = KEY_VIDEO,        // Video
+	[ 0x15 ] = KEY_AUDIO,        // Audio
+	[ 0x00 ] = KEY_POWER,        // Power
+	[ 0x18 ] = KEY_TUNER,        // AV Source
+	[ 0x02 ] = KEY_ZOOM,         // Fullscreen
+	[ 0x1a ] = KEY_LANGUAGE,     // Stereo
+	[ 0x1b ] = KEY_MUTE,         // Mute
+	[ 0x14 ] = KEY_VOLUMEUP,     // Volume +
+	[ 0x17 ] = KEY_VOLUMEDOWN,   // Volume -
+	[ 0x12 ] = KEY_CHANNELUP,    // Channel +
+	[ 0x13 ] = KEY_CHANNELDOWN,  // Channel -
+	[ 0x06 ] = KEY_AGAIN,        // Recall
+	[ 0x10 ] = KEY_ENTER,      // Enter
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_flyvideo);
+
+IR_KEYTAB_TYPE ir_codes_flydvb[IR_KEYTAB_SIZE] = {
+	[ 0x01 ] = KEY_ZOOM,		// Full Screen
+	[ 0x00 ] = KEY_POWER,		// Power
+
+	[ 0x03 ] = KEY_1,
+	[ 0x04 ] = KEY_2,
+	[ 0x05 ] = KEY_3,
+	[ 0x07 ] = KEY_4,
+	[ 0x08 ] = KEY_5,
+	[ 0x09 ] = KEY_6,
+	[ 0x0b ] = KEY_7,
+	[ 0x0c ] = KEY_8,
+	[ 0x0d ] = KEY_9,
+	[ 0x06 ] = KEY_AGAIN,		// Recall
+	[ 0x0f ] = KEY_0,
+	[ 0x10 ] = KEY_MUTE,		// Mute
+	[ 0x02 ] = KEY_RADIO,		// TV/Radio
+	[ 0x1b ] = KEY_LANGUAGE,		// SAP (Second Audio Program)
+
+	[ 0x14 ] = KEY_VOLUMEUP,		// VOL+
+	[ 0x17 ] = KEY_VOLUMEDOWN,	// VOL-
+	[ 0x12 ] = KEY_CHANNELUP,		// CH+
+	[ 0x13 ] = KEY_CHANNELDOWN,	// CH-
+	[ 0x1d ] = KEY_ENTER,		// Enter
+
+	[ 0x1a ] = KEY_MODE,		// PIP
+	[ 0x18 ] = KEY_TUNER,		// Source
+
+	[ 0x1e ] = KEY_RECORD,		// Record/Pause
+	[ 0x15 ] = KEY_ANGLE,		// Swap (no label on key)
+	[ 0x1c ] = KEY_PAUSE,		// Timeshift/Pause
+	[ 0x19 ] = KEY_BACK,		// Rewind <<
+	[ 0x0a ] = KEY_PLAYPAUSE,		// Play/Pause
+	[ 0x1f ] = KEY_FORWARD,		// Forward >>
+	[ 0x16 ] = KEY_PREVIOUS,		// Back |<<
+	[ 0x11 ] = KEY_STOP,		// Stop
+	[ 0x0e ] = KEY_NEXT,		// End >>|
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_flydvb);
+
+IR_KEYTAB_TYPE ir_codes_cinergy[IR_KEYTAB_SIZE] = {
+	[ 0x00 ] = KEY_0,
+	[ 0x01 ] = KEY_1,
+	[ 0x02 ] = KEY_2,
+	[ 0x03 ] = KEY_3,
+	[ 0x04 ] = KEY_4,
+	[ 0x05 ] = KEY_5,
+	[ 0x06 ] = KEY_6,
+	[ 0x07 ] = KEY_7,
+	[ 0x08 ] = KEY_8,
+	[ 0x09 ] = KEY_9,
+
+	[ 0x0a ] = KEY_POWER,
+	[ 0x0b ] = KEY_PROG1,           // app
+	[ 0x0c ] = KEY_ZOOM,            // zoom/fullscreen
+	[ 0x0d ] = KEY_CHANNELUP,       // channel
+	[ 0x0e ] = KEY_CHANNELDOWN,     // channel-
+	[ 0x0f ] = KEY_VOLUMEUP,
+	[ 0x10 ] = KEY_VOLUMEDOWN,
+	[ 0x11 ] = KEY_TUNER,           // AV
+	[ 0x12 ] = KEY_NUMLOCK,         // -/--
+	[ 0x13 ] = KEY_AUDIO,           // audio
+	[ 0x14 ] = KEY_MUTE,
+	[ 0x15 ] = KEY_UP,
+	[ 0x16 ] = KEY_DOWN,
+	[ 0x17 ] = KEY_LEFT,
+	[ 0x18 ] = KEY_RIGHT,
+	[ 0x19 ] = BTN_LEFT,
+	[ 0x1a ] = BTN_RIGHT,
+	[ 0x1b ] = KEY_WWW,             // text
+	[ 0x1c ] = KEY_REWIND,
+	[ 0x1d ] = KEY_FORWARD,
+	[ 0x1e ] = KEY_RECORD,
+	[ 0x1f ] = KEY_PLAY,
+	[ 0x20 ] = KEY_PREVIOUSSONG,
+	[ 0x21 ] = KEY_NEXTSONG,
+	[ 0x22 ] = KEY_PAUSE,
+	[ 0x23 ] = KEY_STOP,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_cinergy);
+
+/* Alfons Geser <a.geser@cox.net>
+ * updates from Job D. R. Borges <jobdrb@ig.com.br> */
+IR_KEYTAB_TYPE ir_codes_eztv[IR_KEYTAB_SIZE] = {
+	[ 0x12 ] = KEY_POWER,
+	[ 0x01 ] = KEY_TV,             // DVR
+	[ 0x15 ] = KEY_DVD,            // DVD
+	[ 0x17 ] = KEY_AUDIO,          // music
+				     // DVR mode / DVD mode / music mode
+
+	[ 0x1b ] = KEY_MUTE,           // mute
+	[ 0x02 ] = KEY_LANGUAGE,       // MTS/SAP / audio / autoseek
+	[ 0x1e ] = KEY_SUBTITLE,       // closed captioning / subtitle / seek
+	[ 0x16 ] = KEY_ZOOM,           // full screen
+	[ 0x1c ] = KEY_VIDEO,          // video source / eject / delall
+	[ 0x1d ] = KEY_RESTART,        // playback / angle / del
+	[ 0x2f ] = KEY_SEARCH,         // scan / menu / playlist
+	[ 0x30 ] = KEY_CHANNEL,        // CH surfing / bookmark / memo
+
+	[ 0x31 ] = KEY_HELP,           // help
+	[ 0x32 ] = KEY_MODE,           // num/memo
+	[ 0x33 ] = KEY_ESC,            // cancel
+
+	[ 0x0c ] = KEY_UP,             // up
+	[ 0x10 ] = KEY_DOWN,           // down
+	[ 0x08 ] = KEY_LEFT,           // left
+	[ 0x04 ] = KEY_RIGHT,          // right
+	[ 0x03 ] = KEY_SELECT,         // select
+
+	[ 0x1f ] = KEY_REWIND,         // rewind
+	[ 0x20 ] = KEY_PLAYPAUSE,      // play/pause
+	[ 0x29 ] = KEY_FORWARD,        // forward
+	[ 0x14 ] = KEY_AGAIN,          // repeat
+	[ 0x2b ] = KEY_RECORD,         // recording
+	[ 0x2c ] = KEY_STOP,           // stop
+	[ 0x2d ] = KEY_PLAY,           // play
+	[ 0x2e ] = KEY_SHUFFLE,        // snapshot / shuffle
+
+	[ 0x00 ] = KEY_0,
+	[ 0x05 ] = KEY_1,
+	[ 0x06 ] = KEY_2,
+	[ 0x07 ] = KEY_3,
+	[ 0x09 ] = KEY_4,
+	[ 0x0a ] = KEY_5,
+	[ 0x0b ] = KEY_6,
+	[ 0x0d ] = KEY_7,
+	[ 0x0e ] = KEY_8,
+	[ 0x0f ] = KEY_9,
+
+	[ 0x2a ] = KEY_VOLUMEUP,
+	[ 0x11 ] = KEY_VOLUMEDOWN,
+	[ 0x18 ] = KEY_CHANNELUP,      // CH.tracking up
+	[ 0x19 ] = KEY_CHANNELDOWN,    // CH.tracking down
+
+	[ 0x13 ] = KEY_ENTER,        // enter
+	[ 0x21 ] = KEY_DOT,          // . (decimal dot)
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_eztv);
+
+/* Alex Hermann <gaaf@gmx.net> */
+IR_KEYTAB_TYPE ir_codes_avermedia[IR_KEYTAB_SIZE] = {
+	[ 0x28 ] = KEY_1,
+	[ 0x18 ] = KEY_2,
+	[ 0x38 ] = KEY_3,
+	[ 0x24 ] = KEY_4,
+	[ 0x14 ] = KEY_5,
+	[ 0x34 ] = KEY_6,
+	[ 0x2c ] = KEY_7,
+	[ 0x1c ] = KEY_8,
+	[ 0x3c ] = KEY_9,
+	[ 0x22 ] = KEY_0,
+
+	[ 0x20 ] = KEY_TV,		/* TV/FM */
+	[ 0x10 ] = KEY_CD,		/* CD */
+	[ 0x30 ] = KEY_TEXT,		/* TELETEXT */
+	[ 0x00 ] = KEY_POWER,		/* POWER */
+
+	[ 0x08 ] = KEY_VIDEO,		/* VIDEO */
+	[ 0x04 ] = KEY_AUDIO,		/* AUDIO */
+	[ 0x0c ] = KEY_ZOOM,		/* FULL SCREEN */
+
+	[ 0x12 ] = KEY_SUBTITLE,	/* DISPLAY */
+	[ 0x32 ] = KEY_REWIND,		/* LOOP	*/
+	[ 0x02 ] = KEY_PRINT,		/* PREVIEW */
+
+	[ 0x2a ] = KEY_SEARCH,		/* AUTOSCAN */
+	[ 0x1a ] = KEY_SLEEP,		/* FREEZE */
+	[ 0x3a ] = KEY_SHUFFLE,		/* SNAPSHOT */
+	[ 0x0a ] = KEY_MUTE,		/* MUTE */
+
+	[ 0x26 ] = KEY_RECORD,		/* RECORD */
+	[ 0x16 ] = KEY_PAUSE,		/* PAUSE */
+	[ 0x36 ] = KEY_STOP,		/* STOP */
+	[ 0x06 ] = KEY_PLAY,		/* PLAY */
+
+	[ 0x2e ] = KEY_RED,		/* RED */
+	[ 0x21 ] = KEY_GREEN,		/* GREEN */
+	[ 0x0e ] = KEY_YELLOW,		/* YELLOW */
+	[ 0x01 ] = KEY_BLUE,		/* BLUE */
+
+	[ 0x1e ] = KEY_VOLUMEDOWN,	/* VOLUME- */
+	[ 0x3e ] = KEY_VOLUMEUP,	/* VOLUME+ */
+	[ 0x11 ] = KEY_CHANNELDOWN,	/* CHANNEL/PAGE- */
+	[ 0x31 ] = KEY_CHANNELUP	/* CHANNEL/PAGE+ */
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_avermedia);
+
+IR_KEYTAB_TYPE ir_codes_videomate_tv_pvr[IR_KEYTAB_SIZE] = {
+	[ 0x14 ] = KEY_MUTE,
+	[ 0x24 ] = KEY_ZOOM,
+
+	[ 0x01 ] = KEY_DVD,
+	[ 0x23 ] = KEY_RADIO,
+	[ 0x00 ] = KEY_TV,
+
+	[ 0x0a ] = KEY_REWIND,
+	[ 0x08 ] = KEY_PLAYPAUSE,
+	[ 0x0f ] = KEY_FORWARD,
+
+	[ 0x02 ] = KEY_PREVIOUS,
+	[ 0x07 ] = KEY_STOP,
+	[ 0x06 ] = KEY_NEXT,
+
+	[ 0x0c ] = KEY_UP,
+	[ 0x0e ] = KEY_DOWN,
+	[ 0x0b ] = KEY_LEFT,
+	[ 0x0d ] = KEY_RIGHT,
+	[ 0x11 ] = KEY_OK,
+
+	[ 0x03 ] = KEY_MENU,
+	[ 0x09 ] = KEY_SETUP,
+	[ 0x05 ] = KEY_VIDEO,
+	[ 0x22 ] = KEY_CHANNEL,
+
+	[ 0x12 ] = KEY_VOLUMEUP,
+	[ 0x15 ] = KEY_VOLUMEDOWN,
+	[ 0x10 ] = KEY_CHANNELUP,
+	[ 0x13 ] = KEY_CHANNELDOWN,
+
+	[ 0x04 ] = KEY_RECORD,
+
+	[ 0x16 ] = KEY_1,
+	[ 0x17 ] = KEY_2,
+	[ 0x18 ] = KEY_3,
+	[ 0x19 ] = KEY_4,
+	[ 0x1a ] = KEY_5,
+	[ 0x1b ] = KEY_6,
+	[ 0x1c ] = KEY_7,
+	[ 0x1d ] = KEY_8,
+	[ 0x1e ] = KEY_9,
+	[ 0x1f ] = KEY_0,
+
+	[ 0x20 ] = KEY_LANGUAGE,
+	[ 0x21 ] = KEY_SLEEP,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_videomate_tv_pvr);
+
+/* Michael Tokarev <mjt@tls.msk.ru>
+   http://www.corpit.ru/mjt/beholdTV/remote_control.jpg
+   keytable is used by MANLI MTV00[ 0x0c ] and BeholdTV 40[13] at
+   least, and probably other cards too.
+   The "ascii-art picture" below (in comments, first row
+   is the keycode in hex, and subsequent row(s) shows
+   the button labels (several variants when appropriate)
+   helps to descide which keycodes to assign to the buttons.
+ */
+IR_KEYTAB_TYPE ir_codes_manli[IR_KEYTAB_SIZE] = {
+
+	/*  0x1c            0x12  *
+	 * FUNCTION         POWER *
+	 *   FM              (|)  *
+	 *                        */
+	[ 0x1c ] = KEY_RADIO,	/*XXX*/
+	[ 0x12 ] = KEY_POWER,
+
+	/*  0x01    0x02    0x03  *
+	 *   1       2       3    *
+	 *                        *
+	 *  0x04    0x05    0x06  *
+	 *   4       5       6    *
+	 *                        *
+	 *  0x07    0x08    0x09  *
+	 *   7       8       9    *
+	 *                        */
+	[ 0x01 ] = KEY_1,
+	[ 0x02 ] = KEY_2,
+	[ 0x03 ] = KEY_3,
+	[ 0x04 ] = KEY_4,
+	[ 0x05 ] = KEY_5,
+	[ 0x06 ] = KEY_6,
+	[ 0x07 ] = KEY_7,
+	[ 0x08 ] = KEY_8,
+	[ 0x09 ] = KEY_9,
+
+	/*  0x0a    0x00    0x17  *
+	 * RECALL    0      +100  *
+	 *                  PLUS  *
+	 *                        */
+	[ 0x0a ] = KEY_AGAIN,	/*XXX KEY_REWIND? */
+	[ 0x00 ] = KEY_0,
+	[ 0x17 ] = KEY_DIGITS,	/*XXX*/
+
+	/*  0x14            0x10  *
+	 *  MENU            INFO  *
+	 *  OSD                   */
+	[ 0x14 ] = KEY_MENU,
+	[ 0x10 ] = KEY_INFO,
+
+	/*          0x0b          *
+	 *           Up           *
+	 *                        *
+	 *  0x18    0x16    0x0c  *
+	 *  Left     Ok     Right *
+	 *                        *
+	 *         0x015          *
+	 *         Down           *
+	 *                        */
+	[ 0x0b ] = KEY_UP,	/*XXX KEY_SCROLLUP? */
+	[ 0x18 ] = KEY_LEFT,	/*XXX KEY_BACK? */
+	[ 0x16 ] = KEY_OK,	/*XXX KEY_SELECT? KEY_ENTER? */
+	[ 0x0c ] = KEY_RIGHT,	/*XXX KEY_FORWARD? */
+	[ 0x15 ] = KEY_DOWN,	/*XXX KEY_SCROLLDOWN? */
+
+	/*  0x11            0x0d  *
+	 *  TV/AV           MODE  *
+	 *  SOURCE         STEREO *
+	 *                        */
+	[ 0x11 ] = KEY_TV,	/*XXX*/
+	[ 0x0d ] = KEY_MODE,	/*XXX there's no KEY_STEREO */
+
+	/*  0x0f    0x1b    0x1a  *
+	 *  AUDIO   Vol+    Chan+ *
+	 *        TIMESHIFT???    *
+	 *                        *
+	 *  0x0e    0x1f    0x1e  *
+	 *  SLEEP   Vol-    Chan- *
+	 *                        */
+	[ 0x0f ] = KEY_AUDIO,
+	[ 0x1b ] = KEY_VOLUMEUP,
+	[ 0x1a ] = KEY_CHANNELUP,
+	[ 0x0e ] = KEY_SLEEP,	/*XXX maybe KEY_PAUSE */
+	[ 0x1f ] = KEY_VOLUMEDOWN,
+	[ 0x1e ] = KEY_CHANNELDOWN,
+
+	/*         0x13     0x19  *
+	 *         MUTE   SNAPSHOT*
+	 *                        */
+	[ 0x13 ] = KEY_MUTE,
+	[ 0x19 ] = KEY_RECORD,	/*XXX*/
+
+	// 0x1d unused ?
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_manli);
+
+/* Mike Baikov <mike@baikov.com> */
+IR_KEYTAB_TYPE ir_codes_gotview7135[IR_KEYTAB_SIZE] = {
+
+	[ 0x21 ] = KEY_POWER,
+	[ 0x69 ] = KEY_TV,
+	[ 0x33 ] = KEY_0,
+	[ 0x51 ] = KEY_1,
+	[ 0x31 ] = KEY_2,
+	[ 0x71 ] = KEY_3,
+	[ 0x3b ] = KEY_4,
+	[ 0x58 ] = KEY_5,
+	[ 0x41 ] = KEY_6,
+	[ 0x48 ] = KEY_7,
+	[ 0x30 ] = KEY_8,
+	[ 0x53 ] = KEY_9,
+	[ 0x73 ] = KEY_AGAIN, /* LOOP */
+	[ 0x0a ] = KEY_AUDIO,
+	[ 0x61 ] = KEY_PRINT, /* PREVIEW */
+	[ 0x7a ] = KEY_VIDEO,
+	[ 0x20 ] = KEY_CHANNELUP,
+	[ 0x40 ] = KEY_CHANNELDOWN,
+	[ 0x18 ] = KEY_VOLUMEDOWN,
+	[ 0x50 ] = KEY_VOLUMEUP,
+	[ 0x10 ] = KEY_MUTE,
+	[ 0x4a ] = KEY_SEARCH,
+	[ 0x7b ] = KEY_SHUFFLE, /* SNAPSHOT */
+	[ 0x22 ] = KEY_RECORD,
+	[ 0x62 ] = KEY_STOP,
+	[ 0x78 ] = KEY_PLAY,
+	[ 0x39 ] = KEY_REWIND,
+	[ 0x59 ] = KEY_PAUSE,
+	[ 0x19 ] = KEY_FORWARD,
+	[ 0x09 ] = KEY_ZOOM,
+
+	[ 0x52 ] = KEY_F21, /* LIVE TIMESHIFT */
+	[ 0x1a ] = KEY_F22, /* MIN TIMESHIFT */
+	[ 0x3a ] = KEY_F23, /* TIMESHIFT */
+	[ 0x70 ] = KEY_F24, /* NORMAL TIMESHIFT */
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_gotview7135);
+
+IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = {
+	[ 0x03 ] = KEY_POWER,
+	[ 0x6f ] = KEY_MUTE,
+	[ 0x10 ] = KEY_BACKSPACE,       /* Recall */
+
+	[ 0x11 ] = KEY_0,
+	[ 0x04 ] = KEY_1,
+	[ 0x05 ] = KEY_2,
+	[ 0x06 ] = KEY_3,
+	[ 0x08 ] = KEY_4,
+	[ 0x09 ] = KEY_5,
+	[ 0x0a ] = KEY_6,
+	[ 0x0c ] = KEY_7,
+	[ 0x0d ] = KEY_8,
+	[ 0x0e ] = KEY_9,
+	[ 0x12 ] = KEY_DOT,           /* 100+ */
+
+	[ 0x07 ] = KEY_VOLUMEUP,
+	[ 0x0b ] = KEY_VOLUMEDOWN,
+	[ 0x1a ] = KEY_KPPLUS,
+	[ 0x18 ] = KEY_KPMINUS,
+	[ 0x15 ] = KEY_UP,
+	[ 0x1d ] = KEY_DOWN,
+	[ 0x0f ] = KEY_CHANNELUP,
+	[ 0x13 ] = KEY_CHANNELDOWN,
+	[ 0x48 ] = KEY_ZOOM,
+
+	[ 0x1b ] = KEY_VIDEO,           /* Video source */
+	[ 0x49 ] = KEY_LANGUAGE,        /* MTS Select */
+	[ 0x19 ] = KEY_SEARCH,          /* Auto Scan */
+
+	[ 0x4b ] = KEY_RECORD,
+	[ 0x46 ] = KEY_PLAY,
+	[ 0x45 ] = KEY_PAUSE,           /* Pause */
+	[ 0x44 ] = KEY_STOP,
+	[ 0x40 ] = KEY_FORWARD,         /* Forward ? */
+	[ 0x42 ] = KEY_REWIND,          /* Backward ? */
+
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_purpletv);
+
+/* Mapping for the 28 key remote control as seen at
+   http://www.sednacomputer.com/photo/cardbus-tv.jpg
+   Pavel Mihaylov <bin@bash.info> */
+IR_KEYTAB_TYPE ir_codes_pctv_sedna[IR_KEYTAB_SIZE] = {
+	[ 0x00 ] = KEY_0,
+	[ 0x01 ] = KEY_1,
+	[ 0x02 ] = KEY_2,
+	[ 0x03 ] = KEY_3,
+	[ 0x04 ] = KEY_4,
+	[ 0x05 ] = KEY_5,
+	[ 0x06 ] = KEY_6,
+	[ 0x07 ] = KEY_7,
+	[ 0x08 ] = KEY_8,
+	[ 0x09 ] = KEY_9,
+
+	[ 0x0a ] = KEY_AGAIN,          /* Recall */
+	[ 0x0b ] = KEY_CHANNELUP,
+	[ 0x0c ] = KEY_VOLUMEUP,
+	[ 0x0d ] = KEY_MODE,           /* Stereo */
+	[ 0x0e ] = KEY_STOP,
+	[ 0x0f ] = KEY_PREVIOUSSONG,
+	[ 0x10 ] = KEY_ZOOM,
+	[ 0x11 ] = KEY_TUNER,          /* Source */
+	[ 0x12 ] = KEY_POWER,
+	[ 0x13 ] = KEY_MUTE,
+	[ 0x15 ] = KEY_CHANNELDOWN,
+	[ 0x18 ] = KEY_VOLUMEDOWN,
+	[ 0x19 ] = KEY_SHUFFLE,        /* Snapshot */
+	[ 0x1a ] = KEY_NEXTSONG,
+	[ 0x1b ] = KEY_TEXT,           /* Time Shift */
+	[ 0x1c ] = KEY_RADIO,          /* FM Radio */
+	[ 0x1d ] = KEY_RECORD,
+	[ 0x1e ] = KEY_PAUSE,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_pctv_sedna);
+
+/* Mark Phalan <phalanm@o2.ie> */
+IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE] = {
+	[ 0x00 ] = KEY_0,
+	[ 0x01 ] = KEY_1,
+	[ 0x02 ] = KEY_2,
+	[ 0x03 ] = KEY_3,
+	[ 0x04 ] = KEY_4,
+	[ 0x05 ] = KEY_5,
+	[ 0x06 ] = KEY_6,
+	[ 0x07 ] = KEY_7,
+	[ 0x08 ] = KEY_8,
+	[ 0x09 ] = KEY_9,
+
+	[ 0x12 ] = KEY_POWER,
+	[ 0x10 ] = KEY_MUTE,
+	[ 0x1f ] = KEY_VOLUMEDOWN,
+	[ 0x1b ] = KEY_VOLUMEUP,
+	[ 0x1a ] = KEY_CHANNELUP,
+	[ 0x1e ] = KEY_CHANNELDOWN,
+	[ 0x0e ] = KEY_PAGEUP,
+	[ 0x1d ] = KEY_PAGEDOWN,
+	[ 0x13 ] = KEY_SOUND,
+
+	[ 0x18 ] = KEY_KPPLUSMINUS,	/* CH +/- */
+	[ 0x16 ] = KEY_SUBTITLE,		/* CC */
+	[ 0x0d ] = KEY_TEXT,		/* TTX */
+	[ 0x0b ] = KEY_TV,		/* AIR/CBL */
+	[ 0x11 ] = KEY_PC,		/* PC/TV */
+	[ 0x17 ] = KEY_OK,		/* CH RTN */
+	[ 0x19 ] = KEY_MODE, 		/* FUNC */
+	[ 0x0c ] = KEY_SEARCH, 		/* AUTOSCAN */
+
+	/* Not sure what to do with these ones! */
+	[ 0x0f ] = KEY_SELECT, 		/* SOURCE */
+	[ 0x0a ] = KEY_KPPLUS,		/* +100 */
+	[ 0x14 ] = KEY_EQUAL,		/* SYNC */
+	[ 0x1c ] = KEY_MEDIA,             /* PC/TV */
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_pv951);
+
+/* generic RC5 keytable                                          */
+/* see http://users.pandora.be/nenya/electronics/rc5/codes00.htm */
+/* used by old (black) Hauppauge remotes                         */
+IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE] = {
+	/* Keys 0 to 9 */
+	[ 0x00 ] = KEY_0,
+	[ 0x01 ] = KEY_1,
+	[ 0x02 ] = KEY_2,
+	[ 0x03 ] = KEY_3,
+	[ 0x04 ] = KEY_4,
+	[ 0x05 ] = KEY_5,
+	[ 0x06 ] = KEY_6,
+	[ 0x07 ] = KEY_7,
+	[ 0x08 ] = KEY_8,
+	[ 0x09 ] = KEY_9,
+
+	[ 0x0b ] = KEY_CHANNEL,		/* channel / program (japan: 11) */
+	[ 0x0c ] = KEY_POWER,		/* standby */
+	[ 0x0d ] = KEY_MUTE,		/* mute / demute */
+	[ 0x0f ] = KEY_TV,		/* display */
+	[ 0x10 ] = KEY_VOLUMEUP,
+	[ 0x11 ] = KEY_VOLUMEDOWN,
+	[ 0x12 ] = KEY_BRIGHTNESSUP,
+	[ 0x13 ] = KEY_BRIGHTNESSDOWN,
+	[ 0x1e ] = KEY_SEARCH,		/* search + */
+	[ 0x20 ] = KEY_CHANNELUP,	/* channel / program + */
+	[ 0x21 ] = KEY_CHANNELDOWN,	/* channel / program - */
+	[ 0x22 ] = KEY_CHANNEL,		/* alt / channel */
+	[ 0x23 ] = KEY_LANGUAGE,	/* 1st / 2nd language */
+	[ 0x26 ] = KEY_SLEEP,		/* sleeptimer */
+	[ 0x2e ] = KEY_MENU,		/* 2nd controls (USA: menu) */
+	[ 0x30 ] = KEY_PAUSE,
+	[ 0x32 ] = KEY_REWIND,
+	[ 0x33 ] = KEY_GOTO,
+	[ 0x35 ] = KEY_PLAY,
+	[ 0x36 ] = KEY_STOP,
+	[ 0x37 ] = KEY_RECORD,		/* recording */
+	[ 0x3c ] = KEY_TEXT,    	/* teletext submode (Japan: 12) */
+	[ 0x3d ] = KEY_SUSPEND,		/* system standby */
+
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_rc5_tv);
+
+/* Table for Leadtek Winfast Remote Controls - used by both bttv and cx88 */
+IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = {
+	/* Keys 0 to 9 */
+	[ 0x12 ] = KEY_0,
+	[ 0x05 ] = KEY_1,
+	[ 0x06 ] = KEY_2,
+	[ 0x07 ] = KEY_3,
+	[ 0x09 ] = KEY_4,
+	[ 0x0a ] = KEY_5,
+	[ 0x0b ] = KEY_6,
+	[ 0x0d ] = KEY_7,
+	[ 0x0e ] = KEY_8,
+	[ 0x0f ] = KEY_9,
+
+	[ 0x00 ] = KEY_POWER,
+	[ 0x02 ] = KEY_TUNER,		/* TV/FM */
+	[ 0x1e ] = KEY_VIDEO,
+	[ 0x04 ] = KEY_VOLUMEUP,
+	[ 0x08 ] = KEY_VOLUMEDOWN,
+	[ 0x0c ] = KEY_CHANNELUP,
+	[ 0x10 ] = KEY_CHANNELDOWN,
+	[ 0x03 ] = KEY_ZOOM,		/* fullscreen */
+	[ 0x1f ] = KEY_SUBTITLE,		/* closed caption/teletext */
+	[ 0x20 ] = KEY_SLEEP,
+	[ 0x14 ] = KEY_MUTE,
+	[ 0x2b ] = KEY_RED,
+	[ 0x2c ] = KEY_GREEN,
+	[ 0x2d ] = KEY_YELLOW,
+	[ 0x2e ] = KEY_BLUE,
+	[ 0x18 ] = KEY_KPPLUS,		/* fine tune + */
+	[ 0x19 ] = KEY_KPMINUS,		/* fine tune - */
+	[ 0x21 ] = KEY_DOT,
+	[ 0x13 ] = KEY_ENTER,
+	[ 0x22 ] = KEY_BACK,
+	[ 0x23 ] = KEY_PLAYPAUSE,
+	[ 0x24 ] = KEY_NEXT,
+	[ 0x26 ] = KEY_STOP,
+	[ 0x27 ] = KEY_RECORD
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_winfast);
+
+IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE] = {
+	[ 0x59 ] = KEY_MUTE,
+	[ 0x4a ] = KEY_POWER,
+
+	[ 0x18 ] = KEY_TEXT,
+	[ 0x26 ] = KEY_TV,
+	[ 0x3d ] = KEY_PRINT,
+
+	[ 0x48 ] = KEY_RED,
+	[ 0x04 ] = KEY_GREEN,
+	[ 0x11 ] = KEY_YELLOW,
+	[ 0x00 ] = KEY_BLUE,
+
+	[ 0x2d ] = KEY_VOLUMEUP,
+	[ 0x1e ] = KEY_VOLUMEDOWN,
+
+	[ 0x49 ] = KEY_MENU,
+
+	[ 0x16 ] = KEY_CHANNELUP,
+	[ 0x17 ] = KEY_CHANNELDOWN,
+
+	[ 0x20 ] = KEY_UP,
+	[ 0x21 ] = KEY_DOWN,
+	[ 0x22 ] = KEY_LEFT,
+	[ 0x23 ] = KEY_RIGHT,
+	[ 0x0d ] = KEY_SELECT,
+
+
+
+	[ 0x08 ] = KEY_BACK,
+	[ 0x07 ] = KEY_REFRESH,
+
+	[ 0x2f ] = KEY_ZOOM,
+	[ 0x29 ] = KEY_RECORD,
+
+	[ 0x4b ] = KEY_PAUSE,
+	[ 0x4d ] = KEY_REWIND,
+	[ 0x2e ] = KEY_PLAY,
+	[ 0x4e ] = KEY_FORWARD,
+	[ 0x53 ] = KEY_PREVIOUS,
+	[ 0x4c ] = KEY_STOP,
+	[ 0x54 ] = KEY_NEXT,
+
+	[ 0x69 ] = KEY_0,
+	[ 0x6a ] = KEY_1,
+	[ 0x6b ] = KEY_2,
+	[ 0x6c ] = KEY_3,
+	[ 0x6d ] = KEY_4,
+	[ 0x6e ] = KEY_5,
+	[ 0x6f ] = KEY_6,
+	[ 0x70 ] = KEY_7,
+	[ 0x71 ] = KEY_8,
+	[ 0x72 ] = KEY_9,
+
+	[ 0x74 ] = KEY_CHANNEL,
+	[ 0x0a ] = KEY_BACKSPACE,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_pinnacle);
+
+/* Hauppauge: the newer, gray remotes (seems there are multiple
+ * slightly different versions), shipped with cx88+ivtv cards.
+ * almost rc5 coding, but some non-standard keys */
+IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE] = {
+	/* Keys 0 to 9 */
+	[ 0x00 ] = KEY_0,
+	[ 0x01 ] = KEY_1,
+	[ 0x02 ] = KEY_2,
+	[ 0x03 ] = KEY_3,
+	[ 0x04 ] = KEY_4,
+	[ 0x05 ] = KEY_5,
+	[ 0x06 ] = KEY_6,
+	[ 0x07 ] = KEY_7,
+	[ 0x08 ] = KEY_8,
+	[ 0x09 ] = KEY_9,
+
+	[ 0x0a ] = KEY_TEXT,      	/* keypad asterisk as well */
+	[ 0x0b ] = KEY_RED,		/* red button */
+	[ 0x0c ] = KEY_RADIO,
+	[ 0x0d ] = KEY_MENU,
+	[ 0x0e ] = KEY_SUBTITLE,	/* also the # key */
+	[ 0x0f ] = KEY_MUTE,
+	[ 0x10 ] = KEY_VOLUMEUP,
+	[ 0x11 ] = KEY_VOLUMEDOWN,
+	[ 0x12 ] = KEY_PREVIOUS,	/* previous channel */
+	[ 0x14 ] = KEY_UP,
+	[ 0x15 ] = KEY_DOWN,
+	[ 0x16 ] = KEY_LEFT,
+	[ 0x17 ] = KEY_RIGHT,
+	[ 0x18 ] = KEY_VIDEO,		/* Videos */
+	[ 0x19 ] = KEY_AUDIO,		/* Music */
+	/* 0x1a: Pictures - presume this means
+	   "Multimedia Home Platform" -
+	   no "PICTURES" key in input.h
+	 */
+	[ 0x1a ] = KEY_MHP,
+
+	[ 0x1b ] = KEY_EPG,		/* Guide */
+	[ 0x1c ] = KEY_TV,
+	[ 0x1e ] = KEY_NEXTSONG,	/* skip >| */
+	[ 0x1f ] = KEY_EXIT,		/* back/exit */
+	[ 0x20 ] = KEY_CHANNELUP,	/* channel / program + */
+	[ 0x21 ] = KEY_CHANNELDOWN,	/* channel / program - */
+	[ 0x22 ] = KEY_CHANNEL,		/* source (old black remote) */
+	[ 0x24 ] = KEY_PREVIOUSSONG,	/* replay |< */
+	[ 0x25 ] = KEY_ENTER,		/* OK */
+	[ 0x26 ] = KEY_SLEEP,		/* minimize (old black remote) */
+	[ 0x29 ] = KEY_BLUE,		/* blue key */
+	[ 0x2e ] = KEY_GREEN,		/* green button */
+	[ 0x30 ] = KEY_PAUSE,		/* pause */
+	[ 0x32 ] = KEY_REWIND,		/* backward << */
+	[ 0x34 ] = KEY_FASTFORWARD,	/* forward >> */
+	[ 0x35 ] = KEY_PLAY,
+	[ 0x36 ] = KEY_STOP,
+	[ 0x37 ] = KEY_RECORD,		/* recording */
+	[ 0x38 ] = KEY_YELLOW,		/* yellow key */
+	[ 0x3b ] = KEY_SELECT,		/* top right button */
+	[ 0x3c ] = KEY_ZOOM,		/* full */
+	[ 0x3d ] = KEY_POWER,		/* system power (green button) */
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_hauppauge_new);
+
diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c
index 04c1938..8cdd4d2 100644
--- a/drivers/media/common/saa7146_core.c
+++ b/drivers/media/common/saa7146_core.c
@@ -21,7 +21,7 @@
 #include <media/saa7146.h>
 
 LIST_HEAD(saa7146_devices);
-DECLARE_MUTEX(saa7146_devices_lock);
+DEFINE_MUTEX(saa7146_devices_lock);
 
 static int saa7146_num;
 
@@ -116,8 +116,7 @@
 		pg = vmalloc_to_page(virt);
 		if (NULL == pg)
 			goto err;
-		if (PageHighMem(pg))
-			BUG();
+		BUG_ON(PageHighMem(pg));
 		sglist[i].page   = pg;
 		sglist[i].length = PAGE_SIZE;
 	}
@@ -402,11 +401,11 @@
 
 	pci_set_drvdata(pci, dev);
 
-	init_MUTEX(&dev->lock);
+	mutex_init(&dev->lock);
 	spin_lock_init(&dev->int_slock);
 	spin_lock_init(&dev->slock);
 
-	init_MUTEX(&dev->i2c_lock);
+	mutex_init(&dev->i2c_lock);
 
 	dev->module = THIS_MODULE;
 	init_waitqueue_head(&dev->i2c_wq);
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
index f8cf73e..3870fa9 100644
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146_fops.c
@@ -17,18 +17,18 @@
 	}
 
 	/* is it free? */
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 	if (vv->resources & bit) {
 		DEB_D(("locked! vv->resources:0x%02x, we want:0x%02x\n",vv->resources,bit));
 		/* no, someone else uses it */
-		up(&dev->lock);
+		mutex_unlock(&dev->lock);
 		return 0;
 	}
 	/* it's free, grab it */
 	fh->resources  |= bit;
 	vv->resources |= bit;
 	DEB_D(("res: get 0x%02x, cur:0x%02x\n",bit,vv->resources));
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 	return 1;
 }
 
@@ -37,14 +37,13 @@
 	struct saa7146_dev *dev = fh->dev;
 	struct saa7146_vv *vv = dev->vv_data;
 
-	if ((fh->resources & bits) != bits)
-		BUG();
+	BUG_ON((fh->resources & bits) != bits);
 
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 	fh->resources  &= ~bits;
 	vv->resources &= ~bits;
 	DEB_D(("res: put 0x%02x, cur:0x%02x\n",bits,vv->resources));
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 }
 
 
@@ -55,8 +54,7 @@
 {
 	DEB_EE(("dev:%p, buf:%p\n",dev,buf));
 
-	if (in_interrupt())
-		BUG();
+	BUG_ON(in_interrupt());
 
 	videobuf_waiton(&buf->vb,0,0);
 	videobuf_dma_pci_unmap(dev->pci, &buf->vb.dma);
@@ -204,7 +202,7 @@
 
 	DEB_EE(("inode:%p, file:%p, minor:%d\n",inode,file,minor));
 
-	if (down_interruptible(&saa7146_devices_lock))
+	if (mutex_lock_interruptible(&saa7146_devices_lock))
 		return -ERESTARTSYS;
 
 	list_for_each(list,&saa7146_devices) {
@@ -276,7 +274,7 @@
 		kfree(fh);
 		file->private_data = NULL;
 	}
-	up(&saa7146_devices_lock);
+	mutex_unlock(&saa7146_devices_lock);
 	return result;
 }
 
@@ -287,7 +285,7 @@
 
 	DEB_EE(("inode:%p, file:%p\n",inode,file));
 
-	if (down_interruptible(&saa7146_devices_lock))
+	if (mutex_lock_interruptible(&saa7146_devices_lock))
 		return -ERESTARTSYS;
 
 	if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
@@ -303,7 +301,7 @@
 	file->private_data = NULL;
 	kfree(fh);
 
-	up(&saa7146_devices_lock);
+	mutex_unlock(&saa7146_devices_lock);
 
 	return 0;
 }
diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c
index 8aabdd8fb..d9953f7 100644
--- a/drivers/media/common/saa7146_i2c.c
+++ b/drivers/media/common/saa7146_i2c.c
@@ -279,7 +279,7 @@
 	int address_err = 0;
 	int short_delay = 0;
 
-	if (down_interruptible (&dev->i2c_lock))
+	if (mutex_lock_interruptible(&dev->i2c_lock))
 		return -ERESTARTSYS;
 
 	for(i=0;i<num;i++) {
@@ -366,7 +366,7 @@
 		}
 	}
 
-	up(&dev->i2c_lock);
+	mutex_unlock(&dev->i2c_lock);
 	return err;
 }
 
diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c
index 468d3c9..500bd3f 100644
--- a/drivers/media/common/saa7146_vbi.c
+++ b/drivers/media/common/saa7146_vbi.c
@@ -410,7 +410,7 @@
 			    V4L2_FIELD_SEQ_TB, // FIXME: does this really work?
 			    sizeof(struct saa7146_buf),
 			    file);
-	init_MUTEX(&fh->vbi_q.lock);
+	mutex_init(&fh->vbi_q.lock);
 
 	init_timer(&fh->vbi_read_timeout);
 	fh->vbi_read_timeout.function = vbi_read_timeout;
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index 7ebac79..6b42713 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -378,20 +378,20 @@
 		err = try_win(dev,&f->fmt.win);
 		if (0 != err)
 			return err;
-		down(&dev->lock);
+		mutex_lock(&dev->lock);
 		fh->ov.win    = f->fmt.win;
 		fh->ov.nclips = f->fmt.win.clipcount;
 		if (fh->ov.nclips > 16)
 			fh->ov.nclips = 16;
 		if (copy_from_user(fh->ov.clips,f->fmt.win.clips,sizeof(struct v4l2_clip)*fh->ov.nclips)) {
-			up(&dev->lock);
+			mutex_unlock(&dev->lock);
 			return -EFAULT;
 		}
 
 		/* fh->ov.fh is used to indicate that we have valid overlay informations, too */
 		fh->ov.fh = fh;
 
-		up(&dev->lock);
+		mutex_unlock(&dev->lock);
 
 		/* check if our current overlay is active */
 		if (IS_OVERLAY_ACTIVE(fh) != 0) {
@@ -516,7 +516,7 @@
 		return -EINVAL;
 	}
 
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 
 	switch (ctrl->type) {
 	case V4L2_CTRL_TYPE_BOOLEAN:
@@ -560,7 +560,7 @@
 		/* fixme: we can support changing VFLIP and HFLIP here... */
 		if (IS_CAPTURE_ACTIVE(fh) != 0) {
 			DEB_D(("V4L2_CID_HFLIP while active capture.\n"));
-			up(&dev->lock);
+			mutex_unlock(&dev->lock);
 			return -EINVAL;
 		}
 		vv->hflip = c->value;
@@ -568,7 +568,7 @@
 	case V4L2_CID_VFLIP:
 		if (IS_CAPTURE_ACTIVE(fh) != 0) {
 			DEB_D(("V4L2_CID_VFLIP while active capture.\n"));
-			up(&dev->lock);
+			mutex_unlock(&dev->lock);
 			return -EINVAL;
 		}
 		vv->vflip = c->value;
@@ -577,7 +577,7 @@
 		return -EINVAL;
 	}
 	}
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 
 	if (IS_OVERLAY_ACTIVE(fh) != 0) {
 		saa7146_stop_preview(fh);
@@ -939,7 +939,7 @@
 			}
 		}
 
-		down(&dev->lock);
+		mutex_lock(&dev->lock);
 
 		/* ok, accept it */
 		vv->ov_fb = *fb;
@@ -948,7 +948,7 @@
 			vv->ov_fb.fmt.bytesperline =
 				vv->ov_fb.fmt.width*fmt->depth/8;
 
-		up(&dev->lock);
+		mutex_unlock(&dev->lock);
 
 		return 0;
 	}
@@ -1086,7 +1086,7 @@
 			}
 		}
 
-		down(&dev->lock);
+		mutex_lock(&dev->lock);
 
 		for(i = 0; i < dev->ext_vv_data->num_stds; i++)
 			if (*id & dev->ext_vv_data->stds[i].id)
@@ -1098,7 +1098,7 @@
 			found = 1;
 		}
 
-		up(&dev->lock);
+		mutex_unlock(&dev->lock);
 
 		if (vv->ov_suspend != NULL) {
 			saa7146_start_preview(vv->ov_suspend);
@@ -1201,11 +1201,11 @@
 		DEB_D(("VIDIOCGMBUF \n"));
 
 		q = &fh->video_q;
-		down(&q->lock);
+		mutex_lock(&q->lock);
 		err = videobuf_mmap_setup(q,gbuffers,gbufsize,
 					  V4L2_MEMORY_MMAP);
 		if (err < 0) {
-			up(&q->lock);
+			mutex_unlock(&q->lock);
 			return err;
 		}
 		memset(mbuf,0,sizeof(*mbuf));
@@ -1213,7 +1213,7 @@
 		mbuf->size   = gbuffers * gbufsize;
 		for (i = 0; i < gbuffers; i++)
 			mbuf->offsets[i] = i * gbufsize;
-		up(&q->lock);
+		mutex_unlock(&q->lock);
 		return 0;
 	}
 	default:
@@ -1414,7 +1414,7 @@
 			    sizeof(struct saa7146_buf),
 			    file);
 
-	init_MUTEX(&fh->video_q.lock);
+	mutex_init(&fh->video_q.lock);
 
 	return 0;
 }
diff --git a/drivers/media/dvb/b2c2/flexcop-common.h b/drivers/media/dvb/b2c2/flexcop-common.h
index 7d7e161..b3dd060 100644
--- a/drivers/media/dvb/b2c2/flexcop-common.h
+++ b/drivers/media/dvb/b2c2/flexcop-common.h
@@ -10,6 +10,7 @@
 
 #include <linux/config.h>
 #include <linux/pci.h>
+#include <linux/mutex.h>
 
 #include "flexcop-reg.h"
 
@@ -73,8 +74,7 @@
 	int (*fe_sleep) (struct dvb_frontend *);
 
 	struct i2c_adapter i2c_adap;
-	struct semaphore i2c_sem;
-
+	struct mutex i2c_mutex;
 	struct module *owner;
 
 	/* options and status */
diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c
index 56495cb..e0bd2d8 100644
--- a/drivers/media/dvb/b2c2/flexcop-i2c.c
+++ b/drivers/media/dvb/b2c2/flexcop-i2c.c
@@ -135,7 +135,7 @@
 	struct flexcop_device *fc = i2c_get_adapdata(i2c_adap);
 	int i, ret = 0;
 
-	if (down_interruptible(&fc->i2c_sem))
+	if (mutex_lock_interruptible(&fc->i2c_mutex))
 		return -ERESTARTSYS;
 
 	/* reading */
@@ -161,7 +161,7 @@
 	else
 		ret = num;
 
-	up(&fc->i2c_sem);
+	mutex_unlock(&fc->i2c_mutex);
 
 	return ret;
 }
@@ -180,7 +180,7 @@
 {
 	int ret;
 
-	sema_init(&fc->i2c_sem,1);
+	mutex_init(&fc->i2c_mutex);
 
 	memset(&fc->i2c_adap, 0, sizeof(struct i2c_adapter));
 	strncpy(fc->i2c_adap.name, "B2C2 FlexCop device",I2C_NAME_SIZE);
diff --git a/drivers/media/dvb/bt8xx/Makefile b/drivers/media/dvb/bt8xx/Makefile
index d188e4c..9d197ef 100644
--- a/drivers/media/dvb/bt8xx/Makefile
+++ b/drivers/media/dvb/bt8xx/Makefile
@@ -1,3 +1,3 @@
 obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/video -Idrivers/media/dvb/frontends
+EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/video/bt8xx -Idrivers/media/dvb/frontends
diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c
index 356f447..5500f8a 100644
--- a/drivers/media/dvb/bt8xx/bt878.c
+++ b/drivers/media/dvb/bt8xx/bt878.c
@@ -344,7 +344,7 @@
 	int retval;
 
 	retval = 0;
-	if (down_interruptible (&bt->gpio_lock))
+	if (mutex_lock_interruptible(&bt->gpio_lock))
 		return -ERESTARTSYS;
 	/* special gpio signal */
 	switch (cmd) {
@@ -375,7 +375,7 @@
 		retval = -EINVAL;
 		break;
 	}
-	up(&bt->gpio_lock);
+	mutex_unlock(&bt->gpio_lock);
 	return retval;
 }
 
diff --git a/drivers/media/dvb/bt8xx/bt878.h b/drivers/media/dvb/bt8xx/bt878.h
index 9faf937..f685bc1 100644
--- a/drivers/media/dvb/bt8xx/bt878.h
+++ b/drivers/media/dvb/bt8xx/bt878.h
@@ -25,6 +25,8 @@
 #include <linux/pci.h>
 #include <linux/sched.h>
 #include <linux/spinlock.h>
+#include <linux/mutex.h>
+
 #include "bt848.h"
 #include "bttv.h"
 
@@ -108,7 +110,7 @@
 extern int bt878_num;
 
 struct bt878 {
-	struct semaphore  gpio_lock;
+	struct mutex gpio_lock;
 	unsigned int nr;
 	unsigned int bttv_nr;
 	struct i2c_adapter *adapter;
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index 0310e3d..1cfa5e5 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -910,7 +910,7 @@
 
 static int dst_probe(struct dst_state *state)
 {
-	sema_init(&state->dst_mutex, 1);
+	mutex_init(&state->dst_mutex);
 	if ((rdc_8820_reset(state)) < 0) {
 		dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed.");
 		return -1;
@@ -962,7 +962,7 @@
 {
 	u8 reply;
 
-	down(&state->dst_mutex);
+	mutex_lock(&state->dst_mutex);
 	if ((dst_comm_init(state)) < 0) {
 		dprintk(verbose, DST_NOTICE, 1, "DST Communication Initialization Failed.");
 		goto error;
@@ -1013,11 +1013,11 @@
 		dprintk(verbose, DST_INFO, 1, "checksum failure");
 		goto error;
 	}
-	up(&state->dst_mutex);
+	mutex_unlock(&state->dst_mutex);
 	return 0;
 
 error:
-	up(&state->dst_mutex);
+	mutex_unlock(&state->dst_mutex);
 	return -EIO;
 
 }
@@ -1128,7 +1128,7 @@
 			dst_set_voltage(fe, SEC_VOLTAGE_13);
 	}
 	state->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE);
-	down(&state->dst_mutex);
+	mutex_lock(&state->dst_mutex);
 	if ((dst_comm_init(state)) < 0) {
 		dprintk(verbose, DST_DEBUG, 1, "DST Communication initialization failed.");
 		goto error;
@@ -1160,11 +1160,11 @@
 	state->diseq_flags |= ATTEMPT_TUNE;
 	retval = dst_get_tuna(state);
 werr:
-	up(&state->dst_mutex);
+	mutex_unlock(&state->dst_mutex);
 	return retval;
 
 error:
-	up(&state->dst_mutex);
+	mutex_unlock(&state->dst_mutex);
 	return -EIO;
 }
 
diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c
index c650b4b..f6b49a8 100644
--- a/drivers/media/dvb/bt8xx/dst_ca.c
+++ b/drivers/media/dvb/bt8xx/dst_ca.c
@@ -81,7 +81,7 @@
 {
 	u8 reply;
 
-	down(&state->dst_mutex);
+	mutex_lock(&state->dst_mutex);
 	dst_comm_init(state);
 	msleep(65);
 
@@ -110,11 +110,11 @@
 			goto error;
 		}
 	}
-	up(&state->dst_mutex);
+	mutex_unlock(&state->dst_mutex);
 	return 0;
 
 error:
-	up(&state->dst_mutex);
+	mutex_unlock(&state->dst_mutex);
 	return -EIO;
 }
 
diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h
index 81557f3..51d4e04 100644
--- a/drivers/media/dvb/bt8xx/dst_common.h
+++ b/drivers/media/dvb/bt8xx/dst_common.h
@@ -25,6 +25,7 @@
 #include <linux/smp_lock.h>
 #include <linux/dvb/frontend.h>
 #include <linux/device.h>
+#include <linux/mutex.h>
 #include "bt878.h"
 
 #include "dst_ca.h"
@@ -121,7 +122,7 @@
 	u8 vendor[8];
 	u8 board_info[8];
 
-	struct semaphore dst_mutex;
+	struct mutex dst_mutex;
 };
 
 struct dst_types {
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
index ea27b15..baa8227 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -76,13 +76,13 @@
 	if (!dvbdmx->dmx.frontend)
 		return -EINVAL;
 
-	down(&card->lock);
+	mutex_lock(&card->lock);
 	card->nfeeds++;
 	rc = card->nfeeds;
 	if (card->nfeeds == 1)
 		bt878_start(card->bt, card->gpio_mode,
 			    card->op_sync_orin, card->irq_err_ignore);
-	up(&card->lock);
+	mutex_unlock(&card->lock);
 	return rc;
 }
 
@@ -96,11 +96,11 @@
 	if (!dvbdmx->dmx.frontend)
 		return -EINVAL;
 
-	down(&card->lock);
+	mutex_lock(&card->lock);
 	card->nfeeds--;
 	if (card->nfeeds == 0)
 		bt878_stop(card->bt);
-	up(&card->lock);
+	mutex_unlock(&card->lock);
 
 	return 0;
 }
@@ -239,6 +239,20 @@
 
 static int pinnsat_pll_init(struct dvb_frontend* fe)
 {
+	struct dvb_bt8xx_card *card = fe->dvb->priv;
+
+	bttv_gpio_enable(card->bttv_nr, 1, 1);  /* output */
+	bttv_write_gpio(card->bttv_nr, 1, 1);   /* relay on */
+
+	return 0;
+}
+
+static int pinnsat_pll_sleep(struct dvb_frontend* fe)
+{
+	struct dvb_bt8xx_card *card = fe->dvb->priv;
+
+	bttv_write_gpio(card->bttv_nr, 1, 0);   /* relay off */
+
 	return 0;
 }
 
@@ -246,6 +260,7 @@
 	.demod_address = 0x55,
 	.pll_init = pinnsat_pll_init,
 	.pll_set = cx24108_pll_set,
+	.pll_sleep = pinnsat_pll_sleep,
 };
 
 static int microtune_mt7202dtf_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
@@ -788,7 +803,7 @@
 	if (!(card = kzalloc(sizeof(struct dvb_bt8xx_card), GFP_KERNEL)))
 		return -ENOMEM;
 
-	init_MUTEX(&card->lock);
+	mutex_init(&card->lock);
 	card->bttv_nr = sub->core->nr;
 	strncpy(card->card_name, sub->core->name, sizeof(sub->core->name));
 	card->i2c_adapter = &sub->core->i2c_adap;
@@ -798,14 +813,14 @@
 		card->gpio_mode = 0x0400c060;
 		/* should be: BT878_A_GAIN=0,BT878_A_PWRDN,BT878_DA_DPM,BT878_DA_SBR,
 			      BT878_DA_IOM=1,BT878_DA_APP to enable serial highspeed mode. */
-		card->op_sync_orin = 0;
-		card->irq_err_ignore = 0;
+		card->op_sync_orin = BT878_RISC_SYNC_MASK;
+		card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
 		break;
 
 	case BTTV_BOARD_DVICO_DVBT_LITE:
 		card->gpio_mode = 0x0400C060;
-		card->op_sync_orin = 0;
-		card->irq_err_ignore = 0;
+		card->op_sync_orin = BT878_RISC_SYNC_MASK;
+		card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
 		/* 26, 15, 14, 6, 5
 		 * A_PWRDN  DA_DPM DA_SBR DA_IOM_DA
 		 * DA_APP(parallel) */
@@ -820,15 +835,15 @@
 	case BTTV_BOARD_NEBULA_DIGITV:
 	case BTTV_BOARD_AVDVBT_761:
 		card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5);
-		card->op_sync_orin = 0;
-		card->irq_err_ignore = 0;
+		card->op_sync_orin = BT878_RISC_SYNC_MASK;
+		card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
 		/* A_PWRDN DA_SBR DA_APP (high speed serial) */
 		break;
 
 	case BTTV_BOARD_AVDVBT_771: //case 0x07711461:
 		card->gpio_mode = 0x0400402B;
 		card->op_sync_orin = BT878_RISC_SYNC_MASK;
-		card->irq_err_ignore = 0;
+		card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
 		/* A_PWRDN DA_SBR  DA_APP[0] PKTP=10 RISC_ENABLE FIFO_ENABLE*/
 		break;
 
@@ -852,8 +867,8 @@
 
 	case BTTV_BOARD_PC_HDTV:
 		card->gpio_mode = 0x0100EC7B;
-		card->op_sync_orin = 0;
-		card->irq_err_ignore = 0;
+		card->op_sync_orin = BT878_RISC_SYNC_MASK;
+		card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
 		break;
 
 	default:
@@ -881,7 +896,7 @@
 		return -EFAULT;
 	}
 
-	init_MUTEX(&card->bt->gpio_lock);
+	mutex_init(&card->bt->gpio_lock);
 	card->bt->bttv_nr = sub->core->nr;
 
 	if ( (ret = dvb_bt8xx_load_card(card, sub->core->type)) ) {
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.h b/drivers/media/dvb/bt8xx/dvb-bt8xx.h
index cf035a8..00dd9fa 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.h
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.h
@@ -26,6 +26,7 @@
 #define DVB_BT8XX_H
 
 #include <linux/i2c.h>
+#include <linux/mutex.h>
 #include "dvbdev.h"
 #include "dvb_net.h"
 #include "bttv.h"
@@ -38,7 +39,7 @@
 #include "lgdt330x.h"
 
 struct dvb_bt8xx_card {
-	struct semaphore lock;
+	struct mutex lock;
 	int nfeeds;
 	char card_name[32];
 	struct dvb_adapter dvb_adapter;
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
index c4b4c5b..71b575d 100644
--- a/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ b/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -30,6 +30,7 @@
 #include <linux/pci.h>
 #include <linux/input.h>
 #include <linux/dvb/frontend.h>
+#include <linux/mutex.h>
 
 #include "dmxdev.h"
 #include "dvb_demux.h"
@@ -116,7 +117,7 @@
 struct cinergyt2 {
 	struct dvb_demux demux;
 	struct usb_device *udev;
-	struct semaphore sem;
+	struct mutex sem;
 	struct dvb_adapter adapter;
 	struct dvb_device *fedev;
 	struct dmxdev dmxdev;
@@ -345,14 +346,14 @@
 	struct dvb_demux *demux = dvbdmxfeed->demux;
 	struct cinergyt2 *cinergyt2 = demux->priv;
 
-	if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+	if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
 		return -ERESTARTSYS;
 
 	if (cinergyt2->streaming == 0)
 		cinergyt2_start_stream_xfer(cinergyt2);
 
 	cinergyt2->streaming++;
-	up(&cinergyt2->sem);
+	mutex_unlock(&cinergyt2->sem);
 	return 0;
 }
 
@@ -361,13 +362,13 @@
 	struct dvb_demux *demux = dvbdmxfeed->demux;
 	struct cinergyt2 *cinergyt2 = demux->priv;
 
-	if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+	if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
 		return -ERESTARTSYS;
 
 	if (--cinergyt2->streaming == 0)
 		cinergyt2_stop_stream_xfer(cinergyt2);
 
-	up(&cinergyt2->sem);
+	mutex_unlock(&cinergyt2->sem);
 	return 0;
 }
 
@@ -483,11 +484,11 @@
 	struct cinergyt2 *cinergyt2 = dvbdev->priv;
 	int err = -ERESTARTSYS;
 
-	if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+	if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
 		return -ERESTARTSYS;
 
 	if ((err = dvb_generic_open(inode, file))) {
-		up(&cinergyt2->sem);
+		mutex_unlock(&cinergyt2->sem);
 		return err;
 	}
 
@@ -499,12 +500,15 @@
 
 	atomic_inc(&cinergyt2->inuse);
 
-	up(&cinergyt2->sem);
+	mutex_unlock(&cinergyt2->sem);
 	return 0;
 }
 
 static void cinergyt2_unregister(struct cinergyt2 *cinergyt2)
 {
+	dvb_net_release(&cinergyt2->dvbnet);
+	dvb_dmxdev_release(&cinergyt2->dmxdev);
+	dvb_dmx_release(&cinergyt2->demux);
 	dvb_unregister_device(cinergyt2->fedev);
 	dvb_unregister_adapter(&cinergyt2->adapter);
 
@@ -517,7 +521,7 @@
 	struct dvb_device *dvbdev = file->private_data;
 	struct cinergyt2 *cinergyt2 = dvbdev->priv;
 
-	if (down_interruptible(&cinergyt2->sem))
+	if (mutex_lock_interruptible(&cinergyt2->sem))
 		return -ERESTARTSYS;
 
 	if (!cinergyt2->disconnect_pending && (file->f_flags & O_ACCMODE) != O_RDONLY) {
@@ -526,7 +530,7 @@
 		cinergyt2_sleep(cinergyt2, 1);
 	}
 
-	up(&cinergyt2->sem);
+	mutex_unlock(&cinergyt2->sem);
 
 	if (atomic_dec_and_test(&cinergyt2->inuse) && cinergyt2->disconnect_pending) {
 		warn("delayed unregister in release");
@@ -541,12 +545,12 @@
 	struct dvb_device *dvbdev = file->private_data;
 	struct cinergyt2 *cinergyt2 = dvbdev->priv;
 
-	if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+	if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
 		return -ERESTARTSYS;
 
 	poll_wait(file, &cinergyt2->poll_wq, wait);
 
-	up(&cinergyt2->sem);
+	mutex_unlock(&cinergyt2->sem);
 
 	return (POLLIN | POLLRDNORM | POLLPRI);
 }
@@ -613,7 +617,7 @@
 		if (copy_from_user(&p, (void  __user*) arg, sizeof(p)))
 			return -EFAULT;
 
-		if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+		if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
 			return -ERESTARTSYS;
 
 		param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
@@ -629,7 +633,7 @@
 					(char *) param, sizeof(*param),
 					NULL, 0);
 
-		up(&cinergyt2->sem);
+		mutex_unlock(&cinergyt2->sem);
 
 		return (err < 0) ? err : 0;
 	}
@@ -724,7 +728,7 @@
 	struct cinergyt2_rc_event rc_events[12];
 	int n, len, i;
 
-	if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+	if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
 		return;
 
 	len = cinergyt2_command(cinergyt2, buf, sizeof(buf),
@@ -784,7 +788,7 @@
 	schedule_delayed_work(&cinergyt2->rc_query_work,
 			      msecs_to_jiffies(RC_QUERY_INTERVAL));
 
-	up(&cinergyt2->sem);
+	mutex_unlock(&cinergyt2->sem);
 }
 
 static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2)
@@ -849,7 +853,7 @@
 	uint8_t lock_bits;
 	uint32_t unc;
 
-	if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+	if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
 		return;
 
 	unc = s->uncorrected_block_count;
@@ -868,7 +872,7 @@
 	schedule_delayed_work(&cinergyt2->query_work,
 			      msecs_to_jiffies(QUERY_INTERVAL));
 
-	up(&cinergyt2->sem);
+	mutex_unlock(&cinergyt2->sem);
 }
 
 static int cinergyt2_probe (struct usb_interface *intf,
@@ -885,7 +889,7 @@
 	memset (cinergyt2, 0, sizeof (struct cinergyt2));
 	usb_set_intfdata (intf, (void *) cinergyt2);
 
-	init_MUTEX(&cinergyt2->sem);
+	mutex_init(&cinergyt2->sem);
 	init_waitqueue_head (&cinergyt2->poll_wq);
 	INIT_WORK(&cinergyt2->query_work, cinergyt2_query, cinergyt2);
 
@@ -937,6 +941,7 @@
 	return 0;
 
 bailout:
+	dvb_net_release(&cinergyt2->dvbnet);
 	dvb_dmxdev_release(&cinergyt2->dmxdev);
 	dvb_dmx_release(&cinergyt2->demux);
 	dvb_unregister_adapter(&cinergyt2->adapter);
@@ -967,7 +972,7 @@
 {
 	struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
 
-	if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+	if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
 		return -ERESTARTSYS;
 
 	if (state.event > PM_EVENT_ON) {
@@ -981,7 +986,7 @@
 		cinergyt2_sleep(cinergyt2, 1);
 	}
 
-	up(&cinergyt2->sem);
+	mutex_unlock(&cinergyt2->sem);
 	return 0;
 }
 
@@ -990,7 +995,7 @@
 	struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
 	struct dvbt_set_parameters_msg *param = &cinergyt2->param;
 
-	if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+	if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
 		return -ERESTARTSYS;
 
 	if (!cinergyt2->sleeping) {
@@ -1003,7 +1008,7 @@
 
 	cinergyt2_resume_rc(cinergyt2);
 
-	up(&cinergyt2->sem);
+	mutex_unlock(&cinergyt2->sem);
 	return 0;
 }
 
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 7b8373a..09e96e9 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -1,9 +1,8 @@
 /*
  * dmxdev.c - DVB demultiplexer device
  *
- * Copyright (C) 2000 Ralph  Metzler <ralph@convergence.de>
- *		  & Marcus Metzler <marcus@convergence.de>
-		      for convergence integrated media GmbH
+ * Copyright (C) 2000 Ralph Metzler & Marcus Metzler
+ *		      for convergence integrated media GmbH
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
@@ -32,7 +31,6 @@
 #include <linux/wait.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
-
 #include "dmxdev.h"
 
 static int debug;
@@ -42,177 +40,133 @@
 
 #define dprintk	if (debug) printk
 
-static inline void dvb_dmxdev_buffer_init(struct dmxdev_buffer *buffer)
+static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf,
+				   const u8 *src, size_t len)
 {
-	buffer->data=NULL;
-	buffer->size=8192;
-	buffer->pread=0;
-	buffer->pwrite=0;
-	buffer->error=0;
-	init_waitqueue_head(&buffer->queue);
-}
-
-static inline int dvb_dmxdev_buffer_write(struct dmxdev_buffer *buf, const u8 *src, int len)
-{
-	int split;
-	int free;
-	int todo;
+	ssize_t free;
 
 	if (!len)
 		return 0;
 	if (!buf->data)
 		return 0;
 
-	free=buf->pread-buf->pwrite;
-	split=0;
-	if (free<=0) {
-		free+=buf->size;
-		split=buf->size-buf->pwrite;
-	}
-	if (len>=free) {
+	free = dvb_ringbuffer_free(buf);
+	if (len > free) {
 		dprintk("dmxdev: buffer overflow\n");
-		return -1;
+		return -EOVERFLOW;
 	}
-	if (split>=len)
-		split=0;
-	todo=len;
-	if (split) {
-		memcpy(buf->data + buf->pwrite, src, split);
-		todo-=split;
-		buf->pwrite=0;
-	}
-	memcpy(buf->data + buf->pwrite, src+split, todo);
-	buf->pwrite=(buf->pwrite+todo)%buf->size;
-	return len;
+
+	return dvb_ringbuffer_write(buf, src, len);
 }
 
-static ssize_t dvb_dmxdev_buffer_read(struct dmxdev_buffer *src,
-		int non_blocking, char __user *buf, size_t count, loff_t *ppos)
+static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,
+				      int non_blocking, char __user *buf,
+				      size_t count, loff_t *ppos)
 {
-	unsigned long todo=count;
-	int split, avail, error;
+	size_t todo;
+	ssize_t avail;
+	ssize_t ret = 0;
 
 	if (!src->data)
 		return 0;
 
-	if ((error=src->error)) {
-		src->pwrite=src->pread;
-		src->error=0;
-		return error;
+	if (src->error) {
+		ret = src->error;
+		dvb_ringbuffer_flush(src);
+		return ret;
 	}
 
-	if (non_blocking && (src->pwrite==src->pread))
-		return -EWOULDBLOCK;
-
-	while (todo>0) {
-		if (non_blocking && (src->pwrite==src->pread))
-			return (count-todo) ? (count-todo) : -EWOULDBLOCK;
-
-		if (wait_event_interruptible(src->queue,
-					     (src->pread!=src->pwrite) ||
-					     (src->error))<0)
-			return count-todo;
-
-		if ((error=src->error)) {
-			src->pwrite=src->pread;
-			src->error=0;
-			return error;
+	for (todo = count; todo > 0; todo -= ret) {
+		if (non_blocking && dvb_ringbuffer_empty(src)) {
+			ret = -EWOULDBLOCK;
+			break;
 		}
 
-		split=src->size;
-		avail=src->pwrite - src->pread;
-		if (avail<0) {
-			avail+=src->size;
-			split=src->size - src->pread;
+		ret = wait_event_interruptible(src->queue,
+					       !dvb_ringbuffer_empty(src) ||
+					       (src->error != 0));
+		if (ret < 0)
+			break;
+
+		if (src->error) {
+			ret = src->error;
+			dvb_ringbuffer_flush(src);
+			break;
 		}
-		if (avail>todo)
-			avail=todo;
-		if (split<avail) {
-			if (copy_to_user(buf, src->data+src->pread, split))
-				  return -EFAULT;
-			buf+=split;
-			src->pread=0;
-			todo-=split;
-			avail-=split;
-		}
-		if (avail) {
-			if (copy_to_user(buf, src->data+src->pread, avail))
-				return -EFAULT;
-			src->pread = (src->pread + avail) % src->size;
-			todo-=avail;
-			buf+=avail;
-		}
+
+		avail = dvb_ringbuffer_avail(src);
+		if (avail > todo)
+			avail = todo;
+
+		ret = dvb_ringbuffer_read(src, buf, avail, 1);
+		if (ret < 0)
+			break;
+
+		buf += ret;
 	}
-	return count;
+
+	return (count - todo) ? (count - todo) : ret;
 }
 
-static struct dmx_frontend * get_fe(struct dmx_demux *demux, int type)
+static struct dmx_frontend *get_fe(struct dmx_demux *demux, int type)
 {
 	struct list_head *head, *pos;
 
-	head=demux->get_frontends(demux);
+	head = demux->get_frontends(demux);
 	if (!head)
 		return NULL;
 	list_for_each(pos, head)
-		if (DMX_FE_ENTRY(pos)->source==type)
+		if (DMX_FE_ENTRY(pos)->source == type)
 			return DMX_FE_ENTRY(pos);
 
 	return NULL;
 }
 
-static inline void dvb_dmxdev_dvr_state_set(struct dmxdev_dvr *dmxdevdvr, int state)
-{
-	spin_lock_irq(&dmxdevdvr->dev->lock);
-	dmxdevdvr->state=state;
-	spin_unlock_irq(&dmxdevdvr->dev->lock);
-}
-
 static int dvb_dvr_open(struct inode *inode, struct file *file)
 {
 	struct dvb_device *dvbdev = file->private_data;
 	struct dmxdev *dmxdev = dvbdev->priv;
 	struct dmx_frontend *front;
 
-	dprintk ("function : %s\n", __FUNCTION__);
+	dprintk("function : %s\n", __FUNCTION__);
 
-	if (down_interruptible (&dmxdev->mutex))
+	if (mutex_lock_interruptible(&dmxdev->mutex))
 		return -ERESTARTSYS;
 
-	if ((file->f_flags&O_ACCMODE)==O_RDWR) {
-		if (!(dmxdev->capabilities&DMXDEV_CAP_DUPLEX)) {
-			up(&dmxdev->mutex);
+	if ((file->f_flags & O_ACCMODE) == O_RDWR) {
+		if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) {
+			mutex_unlock(&dmxdev->mutex);
 			return -EOPNOTSUPP;
 		}
 	}
 
-	if ((file->f_flags&O_ACCMODE)==O_RDONLY) {
-	      dvb_dmxdev_buffer_init(&dmxdev->dvr_buffer);
-	      dmxdev->dvr_buffer.size=DVR_BUFFER_SIZE;
-	      dmxdev->dvr_buffer.data=vmalloc(DVR_BUFFER_SIZE);
-	      if (!dmxdev->dvr_buffer.data) {
-		      up(&dmxdev->mutex);
-		      return -ENOMEM;
-	      }
+	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
+		void *mem = vmalloc(DVR_BUFFER_SIZE);
+		if (!mem) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ENOMEM;
+		}
+		dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE);
 	}
 
-	if ((file->f_flags&O_ACCMODE)==O_WRONLY) {
-		dmxdev->dvr_orig_fe=dmxdev->demux->frontend;
+	if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
+		dmxdev->dvr_orig_fe = dmxdev->demux->frontend;
 
 		if (!dmxdev->demux->write) {
-			up(&dmxdev->mutex);
+			mutex_unlock(&dmxdev->mutex);
 			return -EOPNOTSUPP;
 		}
 
-		front=get_fe(dmxdev->demux, DMX_MEMORY_FE);
+		front = get_fe(dmxdev->demux, DMX_MEMORY_FE);
 
 		if (!front) {
-			up(&dmxdev->mutex);
+			mutex_unlock(&dmxdev->mutex);
 			return -EINVAL;
 		}
 		dmxdev->demux->disconnect_frontend(dmxdev->demux);
 		dmxdev->demux->connect_frontend(dmxdev->demux, front);
 	}
-	up(&dmxdev->mutex);
+	mutex_unlock(&dmxdev->mutex);
 	return 0;
 }
 
@@ -221,30 +175,30 @@
 	struct dvb_device *dvbdev = file->private_data;
 	struct dmxdev *dmxdev = dvbdev->priv;
 
-	if (down_interruptible (&dmxdev->mutex))
+	if (mutex_lock_interruptible(&dmxdev->mutex))
 		return -ERESTARTSYS;
 
-	if ((file->f_flags&O_ACCMODE)==O_WRONLY) {
+	if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
 		dmxdev->demux->disconnect_frontend(dmxdev->demux);
 		dmxdev->demux->connect_frontend(dmxdev->demux,
 						dmxdev->dvr_orig_fe);
 	}
-	if ((file->f_flags&O_ACCMODE)==O_RDONLY) {
+	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
 		if (dmxdev->dvr_buffer.data) {
-			void *mem=dmxdev->dvr_buffer.data;
+			void *mem = dmxdev->dvr_buffer.data;
 			mb();
 			spin_lock_irq(&dmxdev->lock);
-			dmxdev->dvr_buffer.data=NULL;
+			dmxdev->dvr_buffer.data = NULL;
 			spin_unlock_irq(&dmxdev->lock);
 			vfree(mem);
 		}
 	}
-	up(&dmxdev->mutex);
+	mutex_unlock(&dmxdev->mutex);
 	return 0;
 }
 
 static ssize_t dvb_dvr_write(struct file *file, const char __user *buf,
-		size_t count, loff_t *ppos)
+			     size_t count, loff_t *ppos)
 {
 	struct dvb_device *dvbdev = file->private_data;
 	struct dmxdev *dmxdev = dvbdev->priv;
@@ -252,60 +206,62 @@
 
 	if (!dmxdev->demux->write)
 		return -EOPNOTSUPP;
-	if ((file->f_flags&O_ACCMODE)!=O_WRONLY)
+	if ((file->f_flags & O_ACCMODE) != O_WRONLY)
 		return -EINVAL;
-	if (down_interruptible (&dmxdev->mutex))
+	if (mutex_lock_interruptible(&dmxdev->mutex))
 		return -ERESTARTSYS;
-	ret=dmxdev->demux->write(dmxdev->demux, buf, count);
-	up(&dmxdev->mutex);
+	ret = dmxdev->demux->write(dmxdev->demux, buf, count);
+	mutex_unlock(&dmxdev->mutex);
 	return ret;
 }
 
 static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count,
-		loff_t *ppos)
+			    loff_t *ppos)
 {
 	struct dvb_device *dvbdev = file->private_data;
 	struct dmxdev *dmxdev = dvbdev->priv;
 	int ret;
 
-	//down(&dmxdev->mutex);
-	ret= dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
-			      file->f_flags&O_NONBLOCK,
-			      buf, count, ppos);
-	//up(&dmxdev->mutex);
+	//mutex_lock(&dmxdev->mutex);
+	ret = dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
+				     file->f_flags & O_NONBLOCK,
+				     buf, count, ppos);
+	//mutex_unlock(&dmxdev->mutex);
 	return ret;
 }
 
-static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter *dmxdevfilter, int state)
+static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter
+					       *dmxdevfilter, int state)
 {
 	spin_lock_irq(&dmxdevfilter->dev->lock);
-	dmxdevfilter->state=state;
+	dmxdevfilter->state = state;
 	spin_unlock_irq(&dmxdevfilter->dev->lock);
 }
 
-static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter, unsigned long size)
+static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter,
+				      unsigned long size)
 {
-	struct dmxdev_buffer *buf=&dmxdevfilter->buffer;
+	struct dvb_ringbuffer *buf = &dmxdevfilter->buffer;
 	void *mem;
 
-	if (buf->size==size)
+	if (buf->size == size)
 		return 0;
-	if (dmxdevfilter->state>=DMXDEV_STATE_GO)
+	if (dmxdevfilter->state >= DMXDEV_STATE_GO)
 		return -EBUSY;
 	spin_lock_irq(&dmxdevfilter->dev->lock);
-	mem=buf->data;
-	buf->data=NULL;
-	buf->size=size;
-	buf->pwrite=buf->pread=0;
+	mem = buf->data;
+	buf->data = NULL;
+	buf->size = size;
+	dvb_ringbuffer_flush(buf);
 	spin_unlock_irq(&dmxdevfilter->dev->lock);
 	vfree(mem);
 
 	if (buf->size) {
-		mem=vmalloc(dmxdevfilter->buffer.size);
+		mem = vmalloc(dmxdevfilter->buffer.size);
 		if (!mem)
 			return -ENOMEM;
 		spin_lock_irq(&dmxdevfilter->dev->lock);
-		buf->data=mem;
+		buf->data = mem;
 		spin_unlock_irq(&dmxdevfilter->dev->lock);
 	}
 	return 0;
@@ -313,31 +269,33 @@
 
 static void dvb_dmxdev_filter_timeout(unsigned long data)
 {
-	struct dmxdev_filter *dmxdevfilter=(struct dmxdev_filter *)data;
+	struct dmxdev_filter *dmxdevfilter = (struct dmxdev_filter *)data;
 
-	dmxdevfilter->buffer.error=-ETIMEDOUT;
+	dmxdevfilter->buffer.error = -ETIMEDOUT;
 	spin_lock_irq(&dmxdevfilter->dev->lock);
-	dmxdevfilter->state=DMXDEV_STATE_TIMEDOUT;
+	dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT;
 	spin_unlock_irq(&dmxdevfilter->dev->lock);
 	wake_up(&dmxdevfilter->buffer.queue);
 }
 
 static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)
 {
-	struct dmx_sct_filter_params *para=&dmxdevfilter->params.sec;
+	struct dmx_sct_filter_params *para = &dmxdevfilter->params.sec;
 
 	del_timer(&dmxdevfilter->timer);
 	if (para->timeout) {
-		dmxdevfilter->timer.function=dvb_dmxdev_filter_timeout;
-		dmxdevfilter->timer.data=(unsigned long) dmxdevfilter;
-		dmxdevfilter->timer.expires=jiffies+1+(HZ/2+HZ*para->timeout)/1000;
+		dmxdevfilter->timer.function = dvb_dmxdev_filter_timeout;
+		dmxdevfilter->timer.data = (unsigned long)dmxdevfilter;
+		dmxdevfilter->timer.expires =
+		    jiffies + 1 + (HZ / 2 + HZ * para->timeout) / 1000;
 		add_timer(&dmxdevfilter->timer);
 	}
 }
 
 static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
-			    const u8 *buffer2, size_t buffer2_len,
-			    struct dmx_section_filter *filter, enum dmx_success success)
+				       const u8 *buffer2, size_t buffer2_len,
+				       struct dmx_section_filter *filter,
+				       enum dmx_success success)
 {
 	struct dmxdev_filter *dmxdevfilter = filter->priv;
 	int ret;
@@ -347,68 +305,68 @@
 		return 0;
 	}
 	spin_lock(&dmxdevfilter->dev->lock);
-	if (dmxdevfilter->state!=DMXDEV_STATE_GO) {
+	if (dmxdevfilter->state != DMXDEV_STATE_GO) {
 		spin_unlock(&dmxdevfilter->dev->lock);
 		return 0;
 	}
 	del_timer(&dmxdevfilter->timer);
 	dprintk("dmxdev: section callback %02x %02x %02x %02x %02x %02x\n",
 		buffer1[0], buffer1[1],
-		buffer1[2], buffer1[3],
-		buffer1[4], buffer1[5]);
-	ret=dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1, buffer1_len);
-	if (ret==buffer1_len) {
-		ret=dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2, buffer2_len);
+		buffer1[2], buffer1[3], buffer1[4], buffer1[5]);
+	ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1,
+				      buffer1_len);
+	if (ret == buffer1_len) {
+		ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2,
+					      buffer2_len);
 	}
-	if (ret<0) {
-		dmxdevfilter->buffer.pwrite=dmxdevfilter->buffer.pread;
-		dmxdevfilter->buffer.error=-EOVERFLOW;
+	if (ret < 0) {
+		dvb_ringbuffer_flush(&dmxdevfilter->buffer);
+		dmxdevfilter->buffer.error = ret;
 	}
-	if (dmxdevfilter->params.sec.flags&DMX_ONESHOT)
-		dmxdevfilter->state=DMXDEV_STATE_DONE;
+	if (dmxdevfilter->params.sec.flags & DMX_ONESHOT)
+		dmxdevfilter->state = DMXDEV_STATE_DONE;
 	spin_unlock(&dmxdevfilter->dev->lock);
 	wake_up(&dmxdevfilter->buffer.queue);
 	return 0;
 }
 
 static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
-		       const u8 *buffer2, size_t buffer2_len,
-		       struct dmx_ts_feed *feed, enum dmx_success success)
+				  const u8 *buffer2, size_t buffer2_len,
+				  struct dmx_ts_feed *feed,
+				  enum dmx_success success)
 {
 	struct dmxdev_filter *dmxdevfilter = feed->priv;
-	struct dmxdev_buffer *buffer;
+	struct dvb_ringbuffer *buffer;
 	int ret;
 
 	spin_lock(&dmxdevfilter->dev->lock);
-	if (dmxdevfilter->params.pes.output==DMX_OUT_DECODER) {
+	if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) {
 		spin_unlock(&dmxdevfilter->dev->lock);
 		return 0;
 	}
 
-	if (dmxdevfilter->params.pes.output==DMX_OUT_TAP)
-		buffer=&dmxdevfilter->buffer;
+	if (dmxdevfilter->params.pes.output == DMX_OUT_TAP)
+		buffer = &dmxdevfilter->buffer;
 	else
-		buffer=&dmxdevfilter->dev->dvr_buffer;
+		buffer = &dmxdevfilter->dev->dvr_buffer;
 	if (buffer->error) {
 		spin_unlock(&dmxdevfilter->dev->lock);
 		wake_up(&buffer->queue);
 		return 0;
 	}
-	ret=dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
-	if (ret==buffer1_len)
-		ret=dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len);
-	if (ret<0) {
-		buffer->pwrite=buffer->pread;
-		buffer->error=-EOVERFLOW;
+	ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
+	if (ret == buffer1_len)
+		ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len);
+	if (ret < 0) {
+		dvb_ringbuffer_flush(buffer);
+		buffer->error = ret;
 	}
 	spin_unlock(&dmxdevfilter->dev->lock);
 	wake_up(&buffer->queue);
 	return 0;
 }
 
-
 /* stop feed but only mark the specified filter as stopped (state set) */
-
 static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter)
 {
 	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
@@ -427,20 +385,16 @@
 	return 0;
 }
 
-
 /* start feed associated with the specified filter */
-
 static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter)
 {
-	dvb_dmxdev_filter_state_set (filter, DMXDEV_STATE_GO);
+	dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
 
 	switch (filter->type) {
 	case DMXDEV_TYPE_SEC:
 		return filter->feed.sec->start_filtering(filter->feed.sec);
-		break;
 	case DMXDEV_TYPE_PES:
 		return filter->feed.ts->start_filtering(filter->feed.ts);
-		break;
 	default:
 		return -EINVAL;
 	}
@@ -448,32 +402,31 @@
 	return 0;
 }
 
-
 /* restart section feed if it has filters left associated with it,
    otherwise release the feed */
-
 static int dvb_dmxdev_feed_restart(struct dmxdev_filter *filter)
 {
 	int i;
 	struct dmxdev *dmxdev = filter->dev;
 	u16 pid = filter->params.sec.pid;
 
-	for (i=0; i<dmxdev->filternum; i++)
-		if (dmxdev->filter[i].state>=DMXDEV_STATE_GO &&
-		    dmxdev->filter[i].type==DMXDEV_TYPE_SEC &&
-		    dmxdev->filter[i].pid==pid) {
+	for (i = 0; i < dmxdev->filternum; i++)
+		if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&
+		    dmxdev->filter[i].type == DMXDEV_TYPE_SEC &&
+		    dmxdev->filter[i].params.sec.pid == pid) {
 			dvb_dmxdev_feed_start(&dmxdev->filter[i]);
 			return 0;
 		}
 
-	filter->dev->demux->release_section_feed(dmxdev->demux, filter->feed.sec);
+	filter->dev->demux->release_section_feed(dmxdev->demux,
+						 filter->feed.sec);
 
 	return 0;
 }
 
 static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter)
 {
-	if (dmxdevfilter->state<DMXDEV_STATE_GO)
+	if (dmxdevfilter->state < DMXDEV_STATE_GO)
 		return 0;
 
 	switch (dmxdevfilter->type) {
@@ -483,36 +436,36 @@
 		dvb_dmxdev_feed_stop(dmxdevfilter);
 		if (dmxdevfilter->filter.sec)
 			dmxdevfilter->feed.sec->
-				release_filter(dmxdevfilter->feed.sec,
-					       dmxdevfilter->filter.sec);
+			    release_filter(dmxdevfilter->feed.sec,
+					   dmxdevfilter->filter.sec);
 		dvb_dmxdev_feed_restart(dmxdevfilter);
-		dmxdevfilter->feed.sec=NULL;
+		dmxdevfilter->feed.sec = NULL;
 		break;
 	case DMXDEV_TYPE_PES:
 		if (!dmxdevfilter->feed.ts)
 			break;
 		dvb_dmxdev_feed_stop(dmxdevfilter);
 		dmxdevfilter->dev->demux->
-			release_ts_feed(dmxdevfilter->dev->demux,
-					dmxdevfilter->feed.ts);
-		dmxdevfilter->feed.ts=NULL;
+		    release_ts_feed(dmxdevfilter->dev->demux,
+				    dmxdevfilter->feed.ts);
+		dmxdevfilter->feed.ts = NULL;
 		break;
 	default:
-		if (dmxdevfilter->state==DMXDEV_STATE_ALLOCATED)
+		if (dmxdevfilter->state == DMXDEV_STATE_ALLOCATED)
 			return 0;
 		return -EINVAL;
 	}
-	dmxdevfilter->buffer.pwrite=dmxdevfilter->buffer.pread=0;
+
+	dvb_ringbuffer_flush(&dmxdevfilter->buffer);
 	return 0;
 }
 
 static inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter)
 {
-	if (dmxdevfilter->state<DMXDEV_STATE_SET)
+	if (dmxdevfilter->state < DMXDEV_STATE_SET)
 		return 0;
 
-	dmxdevfilter->type=DMXDEV_TYPE_NONE;
-	dmxdevfilter->pid=0xffff;
+	dmxdevfilter->type = DMXDEV_TYPE_NONE;
 	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
 	return 0;
 }
@@ -529,32 +482,33 @@
 	if (filter->state >= DMXDEV_STATE_GO)
 		dvb_dmxdev_filter_stop(filter);
 
-	if (!(mem = filter->buffer.data)) {
+	if (!filter->buffer.data) {
 		mem = vmalloc(filter->buffer.size);
-		spin_lock_irq(&filter->dev->lock);
-		filter->buffer.data=mem;
-		spin_unlock_irq(&filter->dev->lock);
-		if (!filter->buffer.data)
+		if (!mem)
 			return -ENOMEM;
+		spin_lock_irq(&filter->dev->lock);
+		filter->buffer.data = mem;
+		spin_unlock_irq(&filter->dev->lock);
 	}
 
-	filter->buffer.pwrite = filter->buffer.pread = 0;
+	dvb_ringbuffer_flush(&filter->buffer);
 
 	switch (filter->type) {
 	case DMXDEV_TYPE_SEC:
 	{
-		struct dmx_sct_filter_params *para=&filter->params.sec;
-		struct dmx_section_filter **secfilter=&filter->filter.sec;
-		struct dmx_section_feed **secfeed=&filter->feed.sec;
+		struct dmx_sct_filter_params *para = &filter->params.sec;
+		struct dmx_section_filter **secfilter = &filter->filter.sec;
+		struct dmx_section_feed **secfeed = &filter->feed.sec;
 
-		*secfilter=NULL;
-		*secfeed=NULL;
+		*secfilter = NULL;
+		*secfeed = NULL;
+
 
 		/* find active filter/feed with same PID */
-		for (i=0; i<dmxdev->filternum; i++) {
+		for (i = 0; i < dmxdev->filternum; i++) {
 			if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&
-			    dmxdev->filter[i].pid == para->pid &&
-			    dmxdev->filter[i].type == DMXDEV_TYPE_SEC) {
+			    dmxdev->filter[i].type == DMXDEV_TYPE_SEC &&
+			    dmxdev->filter[i].params.sec.pid == para->pid) {
 				*secfeed = dmxdev->filter[i].feed.sec;
 				break;
 			}
@@ -562,21 +516,20 @@
 
 		/* if no feed found, try to allocate new one */
 		if (!*secfeed) {
-			ret=dmxdev->demux->allocate_section_feed(dmxdev->demux,
-								 secfeed,
-						   dvb_dmxdev_section_callback);
-			if (ret<0) {
-				printk ("DVB (%s): could not alloc feed\n",
-					__FUNCTION__);
+			ret = dmxdev->demux->allocate_section_feed(dmxdev->demux,
+								   secfeed,
+								   dvb_dmxdev_section_callback);
+			if (ret < 0) {
+				printk("DVB (%s): could not alloc feed\n",
+				       __FUNCTION__);
 				return ret;
 			}
 
-			ret=(*secfeed)->set(*secfeed, para->pid, 32768,
-					    (para->flags & DMX_CHECK_CRC) ? 1 : 0);
-
-			if (ret<0) {
-				printk ("DVB (%s): could not set feed\n",
-					__FUNCTION__);
+			ret = (*secfeed)->set(*secfeed, para->pid, 32768,
+					      (para->flags & DMX_CHECK_CRC) ? 1 : 0);
+			if (ret < 0) {
+				printk("DVB (%s): could not set feed\n",
+				       __FUNCTION__);
 				dvb_dmxdev_feed_restart(filter);
 				return ret;
 			}
@@ -584,41 +537,38 @@
 			dvb_dmxdev_feed_stop(filter);
 		}
 
-		ret=(*secfeed)->allocate_filter(*secfeed, secfilter);
-
+		ret = (*secfeed)->allocate_filter(*secfeed, secfilter);
 		if (ret < 0) {
 			dvb_dmxdev_feed_restart(filter);
 			filter->feed.sec->start_filtering(*secfeed);
-			dprintk ("could not get filter\n");
+			dprintk("could not get filter\n");
 			return ret;
 		}
 
 		(*secfilter)->priv = filter;
 
 		memcpy(&((*secfilter)->filter_value[3]),
-		       &(para->filter.filter[1]), DMX_FILTER_SIZE-1);
+		       &(para->filter.filter[1]), DMX_FILTER_SIZE - 1);
 		memcpy(&(*secfilter)->filter_mask[3],
-		       &para->filter.mask[1], DMX_FILTER_SIZE-1);
+		       &para->filter.mask[1], DMX_FILTER_SIZE - 1);
 		memcpy(&(*secfilter)->filter_mode[3],
-		       &para->filter.mode[1], DMX_FILTER_SIZE-1);
+		       &para->filter.mode[1], DMX_FILTER_SIZE - 1);
 
-		(*secfilter)->filter_value[0]=para->filter.filter[0];
-		(*secfilter)->filter_mask[0]=para->filter.mask[0];
-		(*secfilter)->filter_mode[0]=para->filter.mode[0];
-		(*secfilter)->filter_mask[1]=0;
-		(*secfilter)->filter_mask[2]=0;
+		(*secfilter)->filter_value[0] = para->filter.filter[0];
+		(*secfilter)->filter_mask[0] = para->filter.mask[0];
+		(*secfilter)->filter_mode[0] = para->filter.mode[0];
+		(*secfilter)->filter_mask[1] = 0;
+		(*secfilter)->filter_mask[2] = 0;
 
 		filter->todo = 0;
 
-		ret = filter->feed.sec->start_filtering (filter->feed.sec);
-
+		ret = filter->feed.sec->start_filtering(filter->feed.sec);
 		if (ret < 0)
 			return ret;
 
 		dvb_dmxdev_filter_timer(filter);
 		break;
 	}
-
 	case DMXDEV_TYPE_PES:
 	{
 		struct timespec timeout = { 0 };
@@ -630,41 +580,41 @@
 		struct dmx_ts_feed **tsfeed = &filter->feed.ts;
 
 		filter->feed.ts = NULL;
-		otype=para->output;
+		otype = para->output;
 
-		ts_pes=(enum dmx_ts_pes) para->pes_type;
+		ts_pes = (enum dmx_ts_pes)para->pes_type;
 
-		if (ts_pes<DMX_PES_OTHER)
-			ts_type=TS_DECODER;
+		if (ts_pes < DMX_PES_OTHER)
+			ts_type = TS_DECODER;
 		else
-			ts_type=0;
+			ts_type = 0;
 
 		if (otype == DMX_OUT_TS_TAP)
 			ts_type |= TS_PACKET;
 
 		if (otype == DMX_OUT_TAP)
-			ts_type |= TS_PAYLOAD_ONLY|TS_PACKET;
+			ts_type |= TS_PAYLOAD_ONLY | TS_PACKET;
 
-		ret=dmxdev->demux->allocate_ts_feed(dmxdev->demux,
-						    tsfeed,
-						    dvb_dmxdev_ts_callback);
-		if (ret<0)
+		ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux,
+						      tsfeed,
+						      dvb_dmxdev_ts_callback);
+		if (ret < 0)
 			return ret;
 
-		(*tsfeed)->priv = (void *) filter;
+		(*tsfeed)->priv = filter;
 
 		ret = (*tsfeed)->set(*tsfeed, para->pid, ts_type, ts_pes,
 				     32768, timeout);
-
 		if (ret < 0) {
-			dmxdev->demux->release_ts_feed(dmxdev->demux, *tsfeed);
+			dmxdev->demux->release_ts_feed(dmxdev->demux,
+						       *tsfeed);
 			return ret;
 		}
 
 		ret = filter->feed.ts->start_filtering(filter->feed.ts);
-
 		if (ret < 0) {
-			dmxdev->demux->release_ts_feed(dmxdev->demux, *tsfeed);
+			dmxdev->demux->release_ts_feed(dmxdev->demux,
+						       *tsfeed);
 			return ret;
 		}
 
@@ -688,41 +638,40 @@
 	if (!dmxdev->filter)
 		return -EINVAL;
 
-	if (down_interruptible(&dmxdev->mutex))
+	if (mutex_lock_interruptible(&dmxdev->mutex))
 		return -ERESTARTSYS;
 
-	for (i=0; i<dmxdev->filternum; i++)
-		if (dmxdev->filter[i].state==DMXDEV_STATE_FREE)
+	for (i = 0; i < dmxdev->filternum; i++)
+		if (dmxdev->filter[i].state == DMXDEV_STATE_FREE)
 			break;
 
-	if (i==dmxdev->filternum) {
-		up(&dmxdev->mutex);
+	if (i == dmxdev->filternum) {
+		mutex_unlock(&dmxdev->mutex);
 		return -EMFILE;
 	}
 
-	dmxdevfilter=&dmxdev->filter[i];
-	sema_init(&dmxdevfilter->mutex, 1);
-	dmxdevfilter->dvbdev=dmxdev->dvbdev;
-	file->private_data=dmxdevfilter;
+	dmxdevfilter = &dmxdev->filter[i];
+	mutex_init(&dmxdevfilter->mutex);
+	file->private_data = dmxdevfilter;
 
-	dvb_dmxdev_buffer_init(&dmxdevfilter->buffer);
-	dmxdevfilter->type=DMXDEV_TYPE_NONE;
+	dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
+	dmxdevfilter->type = DMXDEV_TYPE_NONE;
 	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
-	dmxdevfilter->feed.ts=NULL;
+	dmxdevfilter->feed.ts = NULL;
 	init_timer(&dmxdevfilter->timer);
 
-	up(&dmxdev->mutex);
+	mutex_unlock(&dmxdev->mutex);
 	return 0;
 }
 
-
-static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev, struct dmxdev_filter *dmxdevfilter)
+static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev,
+				  struct dmxdev_filter *dmxdevfilter)
 {
-	if (down_interruptible(&dmxdev->mutex))
+	if (mutex_lock_interruptible(&dmxdev->mutex))
 		return -ERESTARTSYS;
 
-	if (down_interruptible(&dmxdevfilter->mutex)) {
-		up(&dmxdev->mutex);
+	if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+		mutex_unlock(&dmxdev->mutex);
 		return -ERESTARTSYS;
 	}
 
@@ -730,18 +679,18 @@
 	dvb_dmxdev_filter_reset(dmxdevfilter);
 
 	if (dmxdevfilter->buffer.data) {
-		void *mem=dmxdevfilter->buffer.data;
+		void *mem = dmxdevfilter->buffer.data;
 
 		spin_lock_irq(&dmxdev->lock);
-		dmxdevfilter->buffer.data=NULL;
+		dmxdevfilter->buffer.data = NULL;
 		spin_unlock_irq(&dmxdev->lock);
 		vfree(mem);
 	}
 
 	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_FREE);
 	wake_up(&dmxdevfilter->buffer.queue);
-	up(&dmxdevfilter->mutex);
-	up(&dmxdev->mutex);
+	mutex_unlock(&dmxdevfilter->mutex);
+	mutex_unlock(&dmxdev->mutex);
 	return 0;
 }
 
@@ -749,173 +698,171 @@
 {
 	int i;
 
-	for (i=0; i<DMX_FILTER_SIZE; i++)
-		filter->mode[i]^=0xff;
+	for (i = 0; i < DMX_FILTER_SIZE; i++)
+		filter->mode[i] ^= 0xff;
 }
 
-
 static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev,
-		struct dmxdev_filter *dmxdevfilter,
-		struct dmx_sct_filter_params *params)
+				 struct dmxdev_filter *dmxdevfilter,
+				 struct dmx_sct_filter_params *params)
 {
-	dprintk ("function : %s\n", __FUNCTION__);
+	dprintk("function : %s\n", __FUNCTION__);
 
 	dvb_dmxdev_filter_stop(dmxdevfilter);
 
-	dmxdevfilter->type=DMXDEV_TYPE_SEC;
-	dmxdevfilter->pid=params->pid;
+	dmxdevfilter->type = DMXDEV_TYPE_SEC;
 	memcpy(&dmxdevfilter->params.sec,
 	       params, sizeof(struct dmx_sct_filter_params));
 	invert_mode(&dmxdevfilter->params.sec.filter);
 	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
 
-	if (params->flags&DMX_IMMEDIATE_START)
+	if (params->flags & DMX_IMMEDIATE_START)
 		return dvb_dmxdev_filter_start(dmxdevfilter);
 
 	return 0;
 }
 
 static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev,
-		   struct dmxdev_filter *dmxdevfilter,
-		   struct dmx_pes_filter_params *params)
+				     struct dmxdev_filter *dmxdevfilter,
+				     struct dmx_pes_filter_params *params)
 {
 	dvb_dmxdev_filter_stop(dmxdevfilter);
 
-	if (params->pes_type>DMX_PES_OTHER || params->pes_type<0)
+	if (params->pes_type > DMX_PES_OTHER || params->pes_type < 0)
 		return -EINVAL;
 
-	dmxdevfilter->type=DMXDEV_TYPE_PES;
-	dmxdevfilter->pid=params->pid;
-	memcpy(&dmxdevfilter->params, params, sizeof(struct dmx_pes_filter_params));
+	dmxdevfilter->type = DMXDEV_TYPE_PES;
+	memcpy(&dmxdevfilter->params, params,
+	       sizeof(struct dmx_pes_filter_params));
 
 	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
 
-	if (params->flags&DMX_IMMEDIATE_START)
+	if (params->flags & DMX_IMMEDIATE_START)
 		return dvb_dmxdev_filter_start(dmxdevfilter);
 
 	return 0;
 }
 
 static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil,
-		struct file *file, char __user *buf, size_t count, loff_t *ppos)
+				   struct file *file, char __user *buf,
+				   size_t count, loff_t *ppos)
 {
 	int result, hcount;
-	int done=0;
+	int done = 0;
 
-	if (dfil->todo<=0) {
-		hcount=3+dfil->todo;
-		if (hcount>count)
-			hcount=count;
-		result=dvb_dmxdev_buffer_read(&dfil->buffer, file->f_flags&O_NONBLOCK,
-					buf, hcount, ppos);
-		if (result<0) {
-			dfil->todo=0;
+	if (dfil->todo <= 0) {
+		hcount = 3 + dfil->todo;
+		if (hcount > count)
+			hcount = count;
+		result = dvb_dmxdev_buffer_read(&dfil->buffer,
+						file->f_flags & O_NONBLOCK,
+						buf, hcount, ppos);
+		if (result < 0) {
+			dfil->todo = 0;
 			return result;
 		}
-		if (copy_from_user(dfil->secheader-dfil->todo, buf, result))
+		if (copy_from_user(dfil->secheader - dfil->todo, buf, result))
 			return -EFAULT;
-		buf+=result;
-		done=result;
-		count-=result;
-		dfil->todo-=result;
-		if (dfil->todo>-3)
+		buf += result;
+		done = result;
+		count -= result;
+		dfil->todo -= result;
+		if (dfil->todo > -3)
 			return done;
-		dfil->todo=((dfil->secheader[1]<<8)|dfil->secheader[2])&0xfff;
+		dfil->todo = ((dfil->secheader[1] << 8) | dfil->secheader[2]) & 0xfff;
 		if (!count)
 			return done;
 	}
-	if (count>dfil->todo)
-		count=dfil->todo;
-	result=dvb_dmxdev_buffer_read(&dfil->buffer, file->f_flags&O_NONBLOCK,
-				buf, count, ppos);
-	if (result<0)
+	if (count > dfil->todo)
+		count = dfil->todo;
+	result = dvb_dmxdev_buffer_read(&dfil->buffer,
+					file->f_flags & O_NONBLOCK,
+					buf, count, ppos);
+	if (result < 0)
 		return result;
-	dfil->todo-=result;
-	return (result+done);
+	dfil->todo -= result;
+	return (result + done);
 }
 
-
 static ssize_t
-dvb_demux_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+dvb_demux_read(struct file *file, char __user *buf, size_t count,
+	       loff_t *ppos)
 {
-	struct dmxdev_filter *dmxdevfilter= file->private_data;
-	int ret=0;
+	struct dmxdev_filter *dmxdevfilter = file->private_data;
+	int ret;
 
-	if (down_interruptible(&dmxdevfilter->mutex))
+	if (mutex_lock_interruptible(&dmxdevfilter->mutex))
 		return -ERESTARTSYS;
 
-	if (dmxdevfilter->type==DMXDEV_TYPE_SEC)
-		ret=dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos);
+	if (dmxdevfilter->type == DMXDEV_TYPE_SEC)
+		ret = dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos);
 	else
-		ret=dvb_dmxdev_buffer_read(&dmxdevfilter->buffer,
-				     file->f_flags&O_NONBLOCK,
-				     buf, count, ppos);
+		ret = dvb_dmxdev_buffer_read(&dmxdevfilter->buffer,
+					     file->f_flags & O_NONBLOCK,
+					     buf, count, ppos);
 
-	up(&dmxdevfilter->mutex);
+	mutex_unlock(&dmxdevfilter->mutex);
 	return ret;
 }
 
-
 static int dvb_demux_do_ioctl(struct inode *inode, struct file *file,
 			      unsigned int cmd, void *parg)
 {
 	struct dmxdev_filter *dmxdevfilter = file->private_data;
-	struct dmxdev *dmxdev=dmxdevfilter->dev;
-	unsigned long arg=(unsigned long) parg;
-	int ret=0;
+	struct dmxdev *dmxdev = dmxdevfilter->dev;
+	unsigned long arg = (unsigned long)parg;
+	int ret = 0;
 
-	if (down_interruptible (&dmxdev->mutex))
+	if (mutex_lock_interruptible(&dmxdev->mutex))
 		return -ERESTARTSYS;
 
 	switch (cmd) {
 	case DMX_START:
-		if (down_interruptible(&dmxdevfilter->mutex)) {
-			up(&dmxdev->mutex);
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
 			return -ERESTARTSYS;
 		}
-		if (dmxdevfilter->state<DMXDEV_STATE_SET)
+		if (dmxdevfilter->state < DMXDEV_STATE_SET)
 			ret = -EINVAL;
 		else
 			ret = dvb_dmxdev_filter_start(dmxdevfilter);
-		up(&dmxdevfilter->mutex);
+		mutex_unlock(&dmxdevfilter->mutex);
 		break;
 
 	case DMX_STOP:
-		if (down_interruptible(&dmxdevfilter->mutex)) {
-			up(&dmxdev->mutex);
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
 			return -ERESTARTSYS;
 		}
-		ret=dvb_dmxdev_filter_stop(dmxdevfilter);
-		up(&dmxdevfilter->mutex);
+		ret = dvb_dmxdev_filter_stop(dmxdevfilter);
+		mutex_unlock(&dmxdevfilter->mutex);
 		break;
 
 	case DMX_SET_FILTER:
-		if (down_interruptible(&dmxdevfilter->mutex)) {
-			up(&dmxdev->mutex);
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
 			return -ERESTARTSYS;
 		}
-		ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter,
-				    (struct dmx_sct_filter_params *)parg);
-		up(&dmxdevfilter->mutex);
+		ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter, parg);
+		mutex_unlock(&dmxdevfilter->mutex);
 		break;
 
 	case DMX_SET_PES_FILTER:
-		if (down_interruptible(&dmxdevfilter->mutex)) {
-			up(&dmxdev->mutex);
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
 			return -ERESTARTSYS;
 		}
-		ret=dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter,
-					       (struct dmx_pes_filter_params *)parg);
-		up(&dmxdevfilter->mutex);
+		ret = dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter, parg);
+		mutex_unlock(&dmxdevfilter->mutex);
 		break;
 
 	case DMX_SET_BUFFER_SIZE:
-		if (down_interruptible(&dmxdevfilter->mutex)) {
-			up(&dmxdev->mutex);
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
 			return -ERESTARTSYS;
 		}
-		ret=dvb_dmxdev_set_buffer_size(dmxdevfilter, arg);
-		up(&dmxdevfilter->mutex);
+		ret = dvb_dmxdev_set_buffer_size(dmxdevfilter, arg);
+		mutex_unlock(&dmxdevfilter->mutex);
 		break;
 
 	case DMX_GET_EVENT:
@@ -923,10 +870,10 @@
 
 	case DMX_GET_PES_PIDS:
 		if (!dmxdev->demux->get_pes_pids) {
-			ret=-EINVAL;
+			ret = -EINVAL;
 			break;
 		}
-		dmxdev->demux->get_pes_pids(dmxdev->demux, (u16 *)parg);
+		dmxdev->demux->get_pes_pids(dmxdev->demux, parg);
 		break;
 
 	case DMX_GET_CAPS:
@@ -947,19 +894,20 @@
 
 	case DMX_GET_STC:
 		if (!dmxdev->demux->get_stc) {
-			ret=-EINVAL;
+			ret = -EINVAL;
 			break;
 		}
 		ret = dmxdev->demux->get_stc(dmxdev->demux,
-				((struct dmx_stc *)parg)->num,
-				&((struct dmx_stc *)parg)->stc,
-				&((struct dmx_stc *)parg)->base);
+					     ((struct dmx_stc *)parg)->num,
+					     &((struct dmx_stc *)parg)->stc,
+					     &((struct dmx_stc *)parg)->base);
 		break;
 
 	default:
-		ret=-EINVAL;
+		ret = -EINVAL;
+		break;
 	}
-	up(&dmxdev->mutex);
+	mutex_unlock(&dmxdev->mutex);
 	return ret;
 }
 
@@ -969,8 +917,7 @@
 	return dvb_usercopy(inode, file, cmd, arg, dvb_demux_do_ioctl);
 }
 
-
-static unsigned int dvb_demux_poll (struct file *file, poll_table *wait)
+static unsigned int dvb_demux_poll(struct file *file, poll_table *wait)
 {
 	struct dmxdev_filter *dmxdevfilter = file->private_data;
 	unsigned int mask = 0;
@@ -988,13 +935,12 @@
 	if (dmxdevfilter->buffer.error)
 		mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
 
-	if (dmxdevfilter->buffer.pread != dmxdevfilter->buffer.pwrite)
+	if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer))
 		mask |= (POLLIN | POLLRDNORM | POLLPRI);
 
 	return mask;
 }
 
-
 static int dvb_demux_release(struct inode *inode, struct file *file)
 {
 	struct dmxdev_filter *dmxdevfilter = file->private_data;
@@ -1003,72 +949,67 @@
 	return dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
 }
 
-
 static struct file_operations dvb_demux_fops = {
-	.owner		= THIS_MODULE,
-	.read		= dvb_demux_read,
-	.ioctl		= dvb_demux_ioctl,
-	.open		= dvb_demux_open,
-	.release	= dvb_demux_release,
-	.poll		= dvb_demux_poll,
+	.owner = THIS_MODULE,
+	.read = dvb_demux_read,
+	.ioctl = dvb_demux_ioctl,
+	.open = dvb_demux_open,
+	.release = dvb_demux_release,
+	.poll = dvb_demux_poll,
 };
 
-
 static struct dvb_device dvbdev_demux = {
-	.priv		= NULL,
-	.users		= 1,
-	.writers	= 1,
-	.fops		= &dvb_demux_fops
+	.priv = NULL,
+	.users = 1,
+	.writers = 1,
+	.fops = &dvb_demux_fops
 };
 
-
 static int dvb_dvr_do_ioctl(struct inode *inode, struct file *file,
-		     unsigned int cmd, void *parg)
+			    unsigned int cmd, void *parg)
 {
 	struct dvb_device *dvbdev = file->private_data;
 	struct dmxdev *dmxdev = dvbdev->priv;
+	int ret;
 
-	int ret=0;
-
-	if (down_interruptible (&dmxdev->mutex))
+	if (mutex_lock_interruptible(&dmxdev->mutex))
 		return -ERESTARTSYS;
 
 	switch (cmd) {
 	case DMX_SET_BUFFER_SIZE:
 		// FIXME: implement
-		ret=0;
+		ret = 0;
 		break;
 
 	default:
-		ret=-EINVAL;
+		ret = -EINVAL;
+		break;
 	}
-	up(&dmxdev->mutex);
+	mutex_unlock(&dmxdev->mutex);
 	return ret;
 }
 
-
 static int dvb_dvr_ioctl(struct inode *inode, struct file *file,
-		  unsigned int cmd, unsigned long arg)
+			 unsigned int cmd, unsigned long arg)
 {
 	return dvb_usercopy(inode, file, cmd, arg, dvb_dvr_do_ioctl);
 }
 
-
-static unsigned int dvb_dvr_poll (struct file *file, poll_table *wait)
+static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait)
 {
 	struct dvb_device *dvbdev = file->private_data;
 	struct dmxdev *dmxdev = dvbdev->priv;
 	unsigned int mask = 0;
 
-	dprintk ("function : %s\n", __FUNCTION__);
+	dprintk("function : %s\n", __FUNCTION__);
 
 	poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
 
-	if ((file->f_flags&O_ACCMODE) == O_RDONLY) {
+	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
 		if (dmxdev->dvr_buffer.error)
 			mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
 
-		if (dmxdev->dvr_buffer.pread!=dmxdev->dvr_buffer.pwrite)
+		if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer))
 			mask |= (POLLIN | POLLRDNORM | POLLPRI);
 	} else
 		mask |= (POLLOUT | POLLWRNORM | POLLPRI);
@@ -1076,73 +1017,63 @@
 	return mask;
 }
 
-
 static struct file_operations dvb_dvr_fops = {
-	.owner		= THIS_MODULE,
-	.read		= dvb_dvr_read,
-	.write		= dvb_dvr_write,
-	.ioctl		= dvb_dvr_ioctl,
-	.open		= dvb_dvr_open,
-	.release	= dvb_dvr_release,
-	.poll		= dvb_dvr_poll,
+	.owner = THIS_MODULE,
+	.read = dvb_dvr_read,
+	.write = dvb_dvr_write,
+	.ioctl = dvb_dvr_ioctl,
+	.open = dvb_dvr_open,
+	.release = dvb_dvr_release,
+	.poll = dvb_dvr_poll,
 };
 
 static struct dvb_device dvbdev_dvr = {
-	.priv		= NULL,
-	.users		= 1,
-	.writers	= 1,
-	.fops		= &dvb_dvr_fops
+	.priv = NULL,
+	.users = 1,
+	.writers = 1,
+	.fops = &dvb_dvr_fops
 };
 
-int
-dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
+int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
 {
 	int i;
 
 	if (dmxdev->demux->open(dmxdev->demux) < 0)
 		return -EUSERS;
 
-	dmxdev->filter = vmalloc(dmxdev->filternum*sizeof(struct dmxdev_filter));
+	dmxdev->filter = vmalloc(dmxdev->filternum * sizeof(struct dmxdev_filter));
 	if (!dmxdev->filter)
 		return -ENOMEM;
 
-	dmxdev->dvr = vmalloc(dmxdev->filternum*sizeof(struct dmxdev_dvr));
-	if (!dmxdev->dvr) {
-		vfree(dmxdev->filter);
-		dmxdev->filter = NULL;
-		return -ENOMEM;
-	}
-
-	sema_init(&dmxdev->mutex, 1);
+	mutex_init(&dmxdev->mutex);
 	spin_lock_init(&dmxdev->lock);
-	for (i=0; i<dmxdev->filternum; i++) {
-		dmxdev->filter[i].dev=dmxdev;
-		dmxdev->filter[i].buffer.data=NULL;
-		dvb_dmxdev_filter_state_set(&dmxdev->filter[i], DMXDEV_STATE_FREE);
-		dmxdev->dvr[i].dev=dmxdev;
-		dmxdev->dvr[i].buffer.data=NULL;
-		dvb_dmxdev_dvr_state_set(&dmxdev->dvr[i], DMXDEV_STATE_FREE);
+	for (i = 0; i < dmxdev->filternum; i++) {
+		dmxdev->filter[i].dev = dmxdev;
+		dmxdev->filter[i].buffer.data = NULL;
+		dvb_dmxdev_filter_state_set(&dmxdev->filter[i],
+					    DMXDEV_STATE_FREE);
 	}
 
-	dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev, DVB_DEVICE_DEMUX);
-	dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr, dmxdev, DVB_DEVICE_DVR);
+	dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev,
+			    DVB_DEVICE_DEMUX);
+	dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr,
+			    dmxdev, DVB_DEVICE_DVR);
 
-	dvb_dmxdev_buffer_init(&dmxdev->dvr_buffer);
+	dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192);
 
 	return 0;
 }
+
 EXPORT_SYMBOL(dvb_dmxdev_init);
 
-void
-dvb_dmxdev_release(struct dmxdev *dmxdev)
+void dvb_dmxdev_release(struct dmxdev *dmxdev)
 {
 	dvb_unregister_device(dmxdev->dvbdev);
 	dvb_unregister_device(dmxdev->dvr_dvbdev);
 
 	vfree(dmxdev->filter);
-	dmxdev->filter=NULL;
-	vfree(dmxdev->dvr);
-	dmxdev->dvr=NULL;
+	dmxdev->filter = NULL;
 	dmxdev->demux->close(dmxdev->demux);
 }
+
 EXPORT_SYMBOL(dvb_dmxdev_release);
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h
index fd72920..d2bee9f 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.h
+++ b/drivers/media/dvb/dvb-core/dmxdev.h
@@ -30,14 +30,15 @@
 #include <linux/wait.h>
 #include <linux/fs.h>
 #include <linux/string.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #include <linux/dvb/dmx.h>
 
 #include "dvbdev.h"
 #include "demux.h"
+#include "dvb_ringbuffer.h"
 
-enum dmxdevype {
+enum dmxdev_type {
 	DMXDEV_TYPE_NONE,
 	DMXDEV_TYPE_SEC,
 	DMXDEV_TYPE_PES,
@@ -52,18 +53,7 @@
 	DMXDEV_STATE_TIMEDOUT
 };
 
-struct dmxdev_buffer {
-	u8 *data;
-	int size;
-	int pread;
-	int pwrite;
-	wait_queue_head_t queue;
-	int error;
-};
-
 struct dmxdev_filter {
-	struct dvb_device *dvbdev;
-
 	union {
 		struct dmx_section_filter *sec;
 	} filter;
@@ -78,26 +68,17 @@
 		struct dmx_pes_filter_params pes;
 	} params;
 
-	int type;
+	enum dmxdev_type type;
 	enum dmxdev_state state;
 	struct dmxdev *dev;
-	struct dmxdev_buffer buffer;
+	struct dvb_ringbuffer buffer;
 
-	struct semaphore mutex;
+	struct mutex mutex;
 
 	/* only for sections */
 	struct timer_list timer;
 	int todo;
 	u8 secheader[3];
-
-	u16 pid;
-};
-
-
-struct dmxdev_dvr {
-	int state;
-	struct dmxdev *dev;
-	struct dmxdev_buffer buffer;
 };
 
 
@@ -106,7 +87,6 @@
 	struct dvb_device *dvr_dvbdev;
 
 	struct dmxdev_filter *filter;
-	struct dmxdev_dvr *dvr;
 	struct dmx_demux *demux;
 
 	int filternum;
@@ -114,10 +94,10 @@
 #define DMXDEV_CAP_DUPLEX 1
 	struct dmx_frontend *dvr_orig_fe;
 
-	struct dmxdev_buffer dvr_buffer;
+	struct dvb_ringbuffer dvr_buffer;
 #define DVR_BUFFER_SIZE (10*188*1024)
 
-	struct semaphore mutex;
+	struct mutex mutex;
 	spinlock_t lock;
 };
 
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index b4c899b..83ec5e0 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -589,18 +589,18 @@
 	if (pid > DMX_MAX_PID)
 		return -EINVAL;
 
-	if (down_interruptible(&demux->mutex))
+	if (mutex_lock_interruptible(&demux->mutex))
 		return -ERESTARTSYS;
 
 	if (ts_type & TS_DECODER) {
 		if (pes_type >= DMX_TS_PES_OTHER) {
-			up(&demux->mutex);
+			mutex_unlock(&demux->mutex);
 			return -EINVAL;
 		}
 
 		if (demux->pesfilter[pes_type] &&
 		    demux->pesfilter[pes_type] != feed) {
-			up(&demux->mutex);
+			mutex_unlock(&demux->mutex);
 			return -EINVAL;
 		}
 
@@ -622,14 +622,14 @@
 #else
 		feed->buffer = vmalloc(feed->buffer_size);
 		if (!feed->buffer) {
-			up(&demux->mutex);
+			mutex_unlock(&demux->mutex);
 			return -ENOMEM;
 		}
 #endif
 	}
 
 	feed->state = DMX_STATE_READY;
-	up(&demux->mutex);
+	mutex_unlock(&demux->mutex);
 
 	return 0;
 }
@@ -640,21 +640,21 @@
 	struct dvb_demux *demux = feed->demux;
 	int ret;
 
-	if (down_interruptible(&demux->mutex))
+	if (mutex_lock_interruptible(&demux->mutex))
 		return -ERESTARTSYS;
 
 	if (feed->state != DMX_STATE_READY || feed->type != DMX_TYPE_TS) {
-		up(&demux->mutex);
+		mutex_unlock(&demux->mutex);
 		return -EINVAL;
 	}
 
 	if (!demux->start_feed) {
-		up(&demux->mutex);
+		mutex_unlock(&demux->mutex);
 		return -ENODEV;
 	}
 
 	if ((ret = demux->start_feed(feed)) < 0) {
-		up(&demux->mutex);
+		mutex_unlock(&demux->mutex);
 		return ret;
 	}
 
@@ -662,7 +662,7 @@
 	ts_feed->is_filtering = 1;
 	feed->state = DMX_STATE_GO;
 	spin_unlock_irq(&demux->lock);
-	up(&demux->mutex);
+	mutex_unlock(&demux->mutex);
 
 	return 0;
 }
@@ -673,16 +673,16 @@
 	struct dvb_demux *demux = feed->demux;
 	int ret;
 
-	if (down_interruptible(&demux->mutex))
+	if (mutex_lock_interruptible(&demux->mutex))
 		return -ERESTARTSYS;
 
 	if (feed->state < DMX_STATE_GO) {
-		up(&demux->mutex);
+		mutex_unlock(&demux->mutex);
 		return -EINVAL;
 	}
 
 	if (!demux->stop_feed) {
-		up(&demux->mutex);
+		mutex_unlock(&demux->mutex);
 		return -ENODEV;
 	}
 
@@ -692,7 +692,7 @@
 	ts_feed->is_filtering = 0;
 	feed->state = DMX_STATE_ALLOCATED;
 	spin_unlock_irq(&demux->lock);
-	up(&demux->mutex);
+	mutex_unlock(&demux->mutex);
 
 	return ret;
 }
@@ -704,11 +704,11 @@
 	struct dvb_demux *demux = (struct dvb_demux *)dmx;
 	struct dvb_demux_feed *feed;
 
-	if (down_interruptible(&demux->mutex))
+	if (mutex_lock_interruptible(&demux->mutex))
 		return -ERESTARTSYS;
 
 	if (!(feed = dvb_dmx_feed_alloc(demux))) {
-		up(&demux->mutex);
+		mutex_unlock(&demux->mutex);
 		return -EBUSY;
 	}
 
@@ -729,7 +729,7 @@
 
 	if (!(feed->filter = dvb_dmx_filter_alloc(demux))) {
 		feed->state = DMX_STATE_FREE;
-		up(&demux->mutex);
+		mutex_unlock(&demux->mutex);
 		return -EBUSY;
 	}
 
@@ -737,7 +737,7 @@
 	feed->filter->feed = feed;
 	feed->filter->state = DMX_STATE_READY;
 
-	up(&demux->mutex);
+	mutex_unlock(&demux->mutex);
 
 	return 0;
 }
@@ -748,11 +748,11 @@
 	struct dvb_demux *demux = (struct dvb_demux *)dmx;
 	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
 
-	if (down_interruptible(&demux->mutex))
+	if (mutex_lock_interruptible(&demux->mutex))
 		return -ERESTARTSYS;
 
 	if (feed->state == DMX_STATE_FREE) {
-		up(&demux->mutex);
+		mutex_unlock(&demux->mutex);
 		return -EINVAL;
 	}
 #ifndef NOBUFS
@@ -770,7 +770,7 @@
 	if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_TS_PES_OTHER)
 		demux->pesfilter[feed->pes_type] = NULL;
 
-	up(&demux->mutex);
+	mutex_unlock(&demux->mutex);
 	return 0;
 }
 
@@ -785,12 +785,12 @@
 	struct dvb_demux *dvbdemux = dvbdmxfeed->demux;
 	struct dvb_demux_filter *dvbdmxfilter;
 
-	if (down_interruptible(&dvbdemux->mutex))
+	if (mutex_lock_interruptible(&dvbdemux->mutex))
 		return -ERESTARTSYS;
 
 	dvbdmxfilter = dvb_dmx_filter_alloc(dvbdemux);
 	if (!dvbdmxfilter) {
-		up(&dvbdemux->mutex);
+		mutex_unlock(&dvbdemux->mutex);
 		return -EBUSY;
 	}
 
@@ -805,7 +805,7 @@
 	dvbdmxfeed->filter = dvbdmxfilter;
 	spin_unlock_irq(&dvbdemux->lock);
 
-	up(&dvbdemux->mutex);
+	mutex_unlock(&dvbdemux->mutex);
 	return 0;
 }
 
@@ -819,7 +819,7 @@
 	if (pid > 0x1fff)
 		return -EINVAL;
 
-	if (down_interruptible(&dvbdmx->mutex))
+	if (mutex_lock_interruptible(&dvbdmx->mutex))
 		return -ERESTARTSYS;
 
 	dvb_demux_feed_add(dvbdmxfeed);
@@ -833,13 +833,13 @@
 #else
 	dvbdmxfeed->buffer = vmalloc(dvbdmxfeed->buffer_size);
 	if (!dvbdmxfeed->buffer) {
-		up(&dvbdmx->mutex);
+		mutex_unlock(&dvbdmx->mutex);
 		return -ENOMEM;
 	}
 #endif
 
 	dvbdmxfeed->state = DMX_STATE_READY;
-	up(&dvbdmx->mutex);
+	mutex_unlock(&dvbdmx->mutex);
 	return 0;
 }
 
@@ -871,16 +871,16 @@
 	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
 	int ret;
 
-	if (down_interruptible(&dvbdmx->mutex))
+	if (mutex_lock_interruptible(&dvbdmx->mutex))
 		return -ERESTARTSYS;
 
 	if (feed->is_filtering) {
-		up(&dvbdmx->mutex);
+		mutex_unlock(&dvbdmx->mutex);
 		return -EBUSY;
 	}
 
 	if (!dvbdmxfeed->filter) {
-		up(&dvbdmx->mutex);
+		mutex_unlock(&dvbdmx->mutex);
 		return -EINVAL;
 	}
 
@@ -890,14 +890,14 @@
 	dvbdmxfeed->feed.sec.seclen = 0;
 
 	if (!dvbdmx->start_feed) {
-		up(&dvbdmx->mutex);
+		mutex_unlock(&dvbdmx->mutex);
 		return -ENODEV;
 	}
 
 	prepare_secfilters(dvbdmxfeed);
 
 	if ((ret = dvbdmx->start_feed(dvbdmxfeed)) < 0) {
-		up(&dvbdmx->mutex);
+		mutex_unlock(&dvbdmx->mutex);
 		return ret;
 	}
 
@@ -906,7 +906,7 @@
 	dvbdmxfeed->state = DMX_STATE_GO;
 	spin_unlock_irq(&dvbdmx->lock);
 
-	up(&dvbdmx->mutex);
+	mutex_unlock(&dvbdmx->mutex);
 	return 0;
 }
 
@@ -916,11 +916,11 @@
 	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
 	int ret;
 
-	if (down_interruptible(&dvbdmx->mutex))
+	if (mutex_lock_interruptible(&dvbdmx->mutex))
 		return -ERESTARTSYS;
 
 	if (!dvbdmx->stop_feed) {
-		up(&dvbdmx->mutex);
+		mutex_unlock(&dvbdmx->mutex);
 		return -ENODEV;
 	}
 
@@ -931,7 +931,7 @@
 	feed->is_filtering = 0;
 	spin_unlock_irq(&dvbdmx->lock);
 
-	up(&dvbdmx->mutex);
+	mutex_unlock(&dvbdmx->mutex);
 	return ret;
 }
 
@@ -942,11 +942,11 @@
 	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
 	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
 
-	if (down_interruptible(&dvbdmx->mutex))
+	if (mutex_lock_interruptible(&dvbdmx->mutex))
 		return -ERESTARTSYS;
 
 	if (dvbdmxfilter->feed != dvbdmxfeed) {
-		up(&dvbdmx->mutex);
+		mutex_unlock(&dvbdmx->mutex);
 		return -EINVAL;
 	}
 
@@ -966,7 +966,7 @@
 
 	dvbdmxfilter->state = DMX_STATE_FREE;
 	spin_unlock_irq(&dvbdmx->lock);
-	up(&dvbdmx->mutex);
+	mutex_unlock(&dvbdmx->mutex);
 	return 0;
 }
 
@@ -977,11 +977,11 @@
 	struct dvb_demux *dvbdmx = (struct dvb_demux *)demux;
 	struct dvb_demux_feed *dvbdmxfeed;
 
-	if (down_interruptible(&dvbdmx->mutex))
+	if (mutex_lock_interruptible(&dvbdmx->mutex))
 		return -ERESTARTSYS;
 
 	if (!(dvbdmxfeed = dvb_dmx_feed_alloc(dvbdmx))) {
-		up(&dvbdmx->mutex);
+		mutex_unlock(&dvbdmx->mutex);
 		return -EBUSY;
 	}
 
@@ -1006,7 +1006,7 @@
 	(*feed)->stop_filtering = dmx_section_feed_stop_filtering;
 	(*feed)->release_filter = dmx_section_feed_release_filter;
 
-	up(&dvbdmx->mutex);
+	mutex_unlock(&dvbdmx->mutex);
 	return 0;
 }
 
@@ -1016,11 +1016,11 @@
 	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
 	struct dvb_demux *dvbdmx = (struct dvb_demux *)demux;
 
-	if (down_interruptible(&dvbdmx->mutex))
+	if (mutex_lock_interruptible(&dvbdmx->mutex))
 		return -ERESTARTSYS;
 
 	if (dvbdmxfeed->state == DMX_STATE_FREE) {
-		up(&dvbdmx->mutex);
+		mutex_unlock(&dvbdmx->mutex);
 		return -EINVAL;
 	}
 #ifndef NOBUFS
@@ -1033,7 +1033,7 @@
 
 	dvbdmxfeed->pid = 0xffff;
 
-	up(&dvbdmx->mutex);
+	mutex_unlock(&dvbdmx->mutex);
 	return 0;
 }
 
@@ -1071,10 +1071,10 @@
 	if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE))
 		return -EINVAL;
 
-	if (down_interruptible(&dvbdemux->mutex))
+	if (mutex_lock_interruptible(&dvbdemux->mutex))
 		return -ERESTARTSYS;
 	dvb_dmx_swfilter(dvbdemux, buf, count);
-	up(&dvbdemux->mutex);
+	mutex_unlock(&dvbdemux->mutex);
 
 	if (signal_pending(current))
 		return -EINTR;
@@ -1126,11 +1126,11 @@
 	if (demux->frontend)
 		return -EINVAL;
 
-	if (down_interruptible(&dvbdemux->mutex))
+	if (mutex_lock_interruptible(&dvbdemux->mutex))
 		return -ERESTARTSYS;
 
 	demux->frontend = frontend;
-	up(&dvbdemux->mutex);
+	mutex_unlock(&dvbdemux->mutex);
 	return 0;
 }
 
@@ -1138,11 +1138,11 @@
 {
 	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
 
-	if (down_interruptible(&dvbdemux->mutex))
+	if (mutex_lock_interruptible(&dvbdemux->mutex))
 		return -ERESTARTSYS;
 
 	demux->frontend = NULL;
-	up(&dvbdemux->mutex);
+	mutex_unlock(&dvbdemux->mutex);
 	return 0;
 }
 
@@ -1215,7 +1215,7 @@
 	dmx->disconnect_frontend = dvbdmx_disconnect_frontend;
 	dmx->get_pes_pids = dvbdmx_get_pes_pids;
 
-	sema_init(&dvbdemux->mutex, 1);
+	mutex_init(&dvbdemux->mutex);
 	spin_lock_init(&dvbdemux->lock);
 
 	return 0;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index 0cc8883..2c5f915 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -26,7 +26,7 @@
 #include <linux/time.h>
 #include <linux/timer.h>
 #include <linux/spinlock.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #include "demux.h"
 
@@ -125,7 +125,7 @@
 	u8 tsbuf[204];
 	int tsbufp;
 
-	struct semaphore mutex;
+	struct mutex mutex;
 	spinlock_t lock;
 };
 
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 771f32d..2c3ea8f 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -37,7 +37,6 @@
 #include <linux/suspend.h>
 #include <linux/jiffies.h>
 #include <asm/processor.h>
-#include <asm/semaphore.h>
 
 #include "dvb_frontend.h"
 #include "dvbdev.h"
@@ -50,13 +49,13 @@
 
 module_param_named(frontend_debug, dvb_frontend_debug, int, 0644);
 MODULE_PARM_DESC(frontend_debug, "Turn on/off frontend core debugging (default:off).");
-module_param(dvb_shutdown_timeout, int, 0444);
+module_param(dvb_shutdown_timeout, int, 0644);
 MODULE_PARM_DESC(dvb_shutdown_timeout, "wait <shutdown_timeout> seconds after close() before suspending hardware");
-module_param(dvb_force_auto_inversion, int, 0444);
+module_param(dvb_force_auto_inversion, int, 0644);
 MODULE_PARM_DESC(dvb_force_auto_inversion, "0: normal (default), 1: INVERSION_AUTO forced always");
-module_param(dvb_override_tune_delay, int, 0444);
+module_param(dvb_override_tune_delay, int, 0644);
 MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt");
-module_param(dvb_powerdown_on_sleep, int, 0444);
+module_param(dvb_powerdown_on_sleep, int, 0644);
 MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB volatage off on sleep (default)");
 
 #define dprintk if (dvb_frontend_debug) printk
@@ -88,7 +87,7 @@
  * FESTATE_LOSTLOCK. When the lock has been lost, and we're searching it again.
  */
 
-static DECLARE_MUTEX(frontend_mutex);
+static DEFINE_MUTEX(frontend_mutex);
 
 struct dvb_frontend_private {
 
@@ -1021,12 +1020,12 @@
 
 	dprintk ("%s\n", __FUNCTION__);
 
-	if (down_interruptible (&frontend_mutex))
+	if (mutex_lock_interruptible(&frontend_mutex))
 		return -ERESTARTSYS;
 
 	fe->frontend_priv = kzalloc(sizeof(struct dvb_frontend_private), GFP_KERNEL);
 	if (fe->frontend_priv == NULL) {
-		up(&frontend_mutex);
+		mutex_unlock(&frontend_mutex);
 		return -ENOMEM;
 	}
 	fepriv = fe->frontend_priv;
@@ -1045,7 +1044,7 @@
 	dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template,
 			     fe, DVB_DEVICE_FRONTEND);
 
-	up (&frontend_mutex);
+	mutex_unlock(&frontend_mutex);
 	return 0;
 }
 EXPORT_SYMBOL(dvb_register_frontend);
@@ -1055,7 +1054,7 @@
 	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 	dprintk ("%s\n", __FUNCTION__);
 
-	down (&frontend_mutex);
+	mutex_lock(&frontend_mutex);
 	dvb_unregister_device (fepriv->dvbdev);
 	dvb_frontend_stop (fe);
 	if (fe->ops->release)
@@ -1064,7 +1063,7 @@
 		printk("dvb_frontend: Demodulator (%s) does not have a release callback!\n", fe->ops->info.name);
 	/* fe is invalid now */
 	kfree(fepriv);
-	up (&frontend_mutex);
+	mutex_unlock(&frontend_mutex);
 	return 0;
 }
 EXPORT_SYMBOL(dvb_unregister_frontend);
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index 70a6d14..d5aee5a 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -104,6 +104,7 @@
 	struct dvb_adapter *dvb;
 	void* demodulator_priv;
 	void* frontend_priv;
+	void* misc_priv;
 };
 
 extern int dvb_register_frontend(struct dvb_adapter* dvb,
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index 6711eb6..2f0f358 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -62,6 +62,7 @@
 #include <linux/uio.h>
 #include <asm/uaccess.h>
 #include <linux/crc32.h>
+#include <linux/mutex.h>
 
 #include "dvb_demux.h"
 #include "dvb_net.h"
@@ -151,8 +152,7 @@
 	unsigned char ule_bridged;		/* Whether the ULE_BRIDGED extension header was found. */
 	int ule_sndu_remain;			/* Nr. of bytes still required for current ULE SNDU. */
 	unsigned long ts_count;			/* Current ts cell counter. */
-
-	struct semaphore mutex;
+	struct mutex mutex;
 };
 
 
@@ -889,7 +889,7 @@
 	unsigned char *mac = (unsigned char *) dev->dev_addr;
 
 	dprintk("%s: rx_mode %i\n", __FUNCTION__, priv->rx_mode);
-	down(&priv->mutex);
+	mutex_lock(&priv->mutex);
 	if (priv->tsfeed || priv->secfeed || priv->secfilter || priv->multi_secfilter[0])
 		printk("%s: BUG %d\n", __FUNCTION__, __LINE__);
 
@@ -974,7 +974,7 @@
 		ret = -EINVAL;
 
 error:
-	up(&priv->mutex);
+	mutex_unlock(&priv->mutex);
 	return ret;
 }
 
@@ -984,7 +984,7 @@
 	int i, ret = 0;
 
 	dprintk("%s\n", __FUNCTION__);
-	down(&priv->mutex);
+	mutex_lock(&priv->mutex);
 	if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) {
 		if (priv->secfeed) {
 			if (priv->secfeed->is_filtering) {
@@ -1026,7 +1026,7 @@
 			printk("%s: no ts feed to stop\n", dev->name);
 	} else
 		ret = -EINVAL;
-	up(&priv->mutex);
+	mutex_unlock(&priv->mutex);
 	return ret;
 }
 
@@ -1208,7 +1208,7 @@
 
 	INIT_WORK(&priv->set_multicast_list_wq, wq_set_multicast_list, net);
 	INIT_WORK(&priv->restart_net_feed_wq, wq_restart_net_feed, net);
-	init_MUTEX(&priv->mutex);
+	mutex_init(&priv->mutex);
 
 	net->base_addr = pid;
 
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
index 77ad241..c972fe0 100644
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
+++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
@@ -45,6 +45,7 @@
 	rbuf->pread=rbuf->pwrite=0;
 	rbuf->data=data;
 	rbuf->size=len;
+	rbuf->error=0;
 
 	init_waitqueue_head(&rbuf->queue);
 
@@ -87,6 +88,7 @@
 void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf)
 {
 	rbuf->pread = rbuf->pwrite;
+	rbuf->error = 0;
 }
 
 
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
index 6d25609..d97714e 100644
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
+++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
@@ -35,6 +35,7 @@
 	ssize_t           size;
 	ssize_t           pread;
 	ssize_t           pwrite;
+	int               error;
 
 	wait_queue_head_t queue;
 	spinlock_t        lock;
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index 162f979..e14bf43 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -77,7 +77,7 @@
 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
 	int i;
 
-	if (down_interruptible(&d->i2c_sem) < 0)
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
 		return -EAGAIN;
 
 	if (num > 2)
@@ -126,7 +126,7 @@
 		}
 	}
 
-	up(&d->i2c_sem);
+	mutex_unlock(&d->i2c_mutex);
 	return i;
 }
 
diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c
index 269d899..2d52b76 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-common.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-common.c
@@ -128,7 +128,7 @@
 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
 	int i;
 
-	if (down_interruptible(&d->i2c_sem) < 0)
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
 		return -EAGAIN;
 
 	if (num > 2)
@@ -146,7 +146,7 @@
 				break;
 	}
 
-	up(&d->i2c_sem);
+	mutex_unlock(&d->i2c_mutex);
 	return i;
 }
 
diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
index caa1346..91136c0 100644
--- a/drivers/media/dvb/dvb-usb/digitv.c
+++ b/drivers/media/dvb/dvb-usb/digitv.c
@@ -48,7 +48,7 @@
 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
 	int i;
 
-	if (down_interruptible(&d->i2c_sem) < 0)
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
 		return -EAGAIN;
 
 	if (num > 2)
@@ -67,7 +67,7 @@
 				break;
 	}
 
-	up(&d->i2c_sem);
+	mutex_unlock(&d->i2c_mutex);
 	return i;
 }
 
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
index ce34a55..a1705ec 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
@@ -42,8 +42,8 @@
 {
 	int ret = 0;
 
-	sema_init(&d->usb_sem, 1);
-	sema_init(&d->i2c_sem, 1);
+	mutex_init(&d->usb_mutex);
+	mutex_init(&d->i2c_mutex);
 
 	d->state = DVB_USB_STATE_INIT;
 
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
index ee82197..9002f35 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
@@ -21,7 +21,7 @@
 	if (wbuf == NULL || wlen == 0)
 		return -EINVAL;
 
-	if ((ret = down_interruptible(&d->usb_sem)))
+	if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
 		return ret;
 
 	deb_xfer(">>> ");
@@ -53,7 +53,7 @@
 		}
 	}
 
-	up(&d->usb_sem);
+	mutex_unlock(&d->usb_mutex);
 	return ret;
 }
 EXPORT_SYMBOL(dvb_usb_generic_rw);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
index d4909e5..fead958 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb.h
@@ -12,6 +12,7 @@
 #include <linux/input.h>
 #include <linux/usb.h>
 #include <linux/firmware.h>
+#include <linux/mutex.h>
 
 #include "dvb_frontend.h"
 #include "dvb_demux.h"
@@ -227,8 +228,8 @@
  * @feedcount: number of reqested feeds (used for streaming-activation)
  * @pid_filtering: is hardware pid_filtering used or not.
  *
- * @usb_sem: semaphore of USB control messages (reading needs two messages)
- * @i2c_sem: semaphore for i2c-transfers
+ * @usb_mutex: semaphore of USB control messages (reading needs two messages)
+ * @i2c_mutex: semaphore for i2c-transfers
  *
  * @i2c_adap: device's i2c_adapter if it uses I2CoverUSB
  * @pll_addr: I2C address of the tuner for programming
@@ -283,10 +284,10 @@
 	int pid_filtering;
 
 	/* locking */
-	struct semaphore usb_sem;
+	struct mutex usb_mutex;
 
 	/* i2c */
-	struct semaphore i2c_sem;
+	struct mutex i2c_mutex;
 	struct i2c_adapter i2c_adap;
 
 	/* tuner programming information */
diff --git a/drivers/media/dvb/dvb-usb/vp702x.c b/drivers/media/dvb/dvb-usb/vp702x.c
index 4a95eca..b2f098a 100644
--- a/drivers/media/dvb/dvb-usb/vp702x.c
+++ b/drivers/media/dvb/dvb-usb/vp702x.c
@@ -75,7 +75,7 @@
 {
 	int ret;
 
-	if ((ret = down_interruptible(&d->usb_sem)))
+	if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
 		return ret;
 
 	if ((ret = vp702x_usb_out_op(d,REQUEST_OUT,0,0,o,olen)) < 0)
@@ -84,7 +84,7 @@
 	ret = vp702x_usb_in_op(d,REQUEST_IN,0,0,i,ilen);
 
 unlock:
-	up(&d->usb_sem);
+	mutex_unlock(&d->usb_mutex);
 
 	return ret;
 }
diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c
index 3835235..8ea3834 100644
--- a/drivers/media/dvb/dvb-usb/vp7045.c
+++ b/drivers/media/dvb/dvb-usb/vp7045.c
@@ -38,7 +38,7 @@
 	deb_xfer("out buffer: ");
 	debug_dump(outbuf,outlen+1,deb_xfer);
 
-	if ((ret = down_interruptible(&d->usb_sem)))
+	if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
 		return ret;
 
 	if (usb_control_msg(d->udev,
@@ -68,7 +68,7 @@
 		memcpy(in,&inbuf[1],inlen);
 
 unlock:
-	up(&d->usb_sem);
+	mutex_unlock(&d->usb_mutex);
 
 	return ret;
 }
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index c676b1e..9423316 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -116,6 +116,12 @@
 	help
 	  A DVB-T tuner module. Say Y when you want to support this frontend.
 
+config DVB_ZL10353
+	tristate "Zarlink ZL10353 based"
+	depends on DVB_CORE
+	help
+	  A DVB-T tuner module. Say Y when you want to support this frontend.
+
 config DVB_DIB3000MB
 	tristate "DiBcom 3000M-B"
 	depends on DVB_CORE
@@ -155,7 +161,7 @@
 	depends on DVB_CORE
 
 config DVB_NXT200X
-	tristate "Nextwave NXT2002/NXT2004 based"
+	tristate "NxtWave Communications NXT2002/NXT2004 based"
 	depends on DVB_CORE
 	select FW_LOADER
 	help
@@ -169,14 +175,14 @@
 	  or /lib/firmware (depending on configuration of firmware hotplug).
 
 config DVB_OR51211
-	tristate "or51211 based (pcHDTV HD2000 card)"
+	tristate "Oren OR51211 based"
 	depends on DVB_CORE
 	select FW_LOADER
 	help
 	  An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
 
 config DVB_OR51132
-	tristate "OR51132 based (pcHDTV HD3000 card)"
+	tristate "Oren OR51132 based"
 	depends on DVB_CORE
 	select FW_LOADER
 	help
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 1af769c..d09b607 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -20,6 +20,7 @@
 obj-$(CONFIG_DVB_SP887X) += sp887x.o
 obj-$(CONFIG_DVB_NXT6000) += nxt6000.o
 obj-$(CONFIG_DVB_MT352) += mt352.o
+obj-$(CONFIG_DVB_ZL10353) += zl10353.o
 obj-$(CONFIG_DVB_CX22702) += cx22702.o
 obj-$(CONFIG_DVB_TDA10021) += tda10021.o
 obj-$(CONFIG_DVB_STV0297) += stv0297.o
diff --git a/drivers/media/dvb/frontends/bcm3510.c b/drivers/media/dvb/frontends/bcm3510.c
index caaee89..1708a1d 100644
--- a/drivers/media/dvb/frontends/bcm3510.c
+++ b/drivers/media/dvb/frontends/bcm3510.c
@@ -39,6 +39,7 @@
 #include <linux/jiffies.h>
 #include <linux/string.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
 
 #include "dvb_frontend.h"
 #include "bcm3510.h"
@@ -52,7 +53,7 @@
 	struct dvb_frontend frontend;
 
 	/* demodulator private data */
-	struct semaphore hab_sem;
+	struct mutex hab_mutex;
 	u8 firmware_loaded:1;
 
 	unsigned long next_status_check;
@@ -213,7 +214,7 @@
 	dbufout(ob,olen+2,deb_hab);
 	deb_hab("\n");
 
-	if (down_interruptible(&st->hab_sem) < 0)
+	if (mutex_lock_interruptible(&st->hab_mutex) < 0)
 		return -EAGAIN;
 
 	if ((ret = bcm3510_hab_send_request(st, ob, olen+2)) < 0 ||
@@ -226,7 +227,7 @@
 
 	memcpy(ibuf,&ib[2],ilen);
 error:
-	up(&st->hab_sem);
+	mutex_unlock(&st->hab_mutex);
 	return ret;
 }
 
@@ -796,7 +797,7 @@
 	state->frontend.ops = &state->ops;
 	state->frontend.demodulator_priv = state;
 
-	sema_init(&state->hab_sem, 1);
+	mutex_init(&state->hab_mutex);
 
 	if ((ret = bcm3510_readB(state,0xe0,&v)) < 0)
 		goto error;
diff --git a/drivers/media/dvb/frontends/bsbe1.h b/drivers/media/dvb/frontends/bsbe1.h
new file mode 100644
index 0000000..78573b2
--- /dev/null
+++ b/drivers/media/dvb/frontends/bsbe1.h
@@ -0,0 +1,123 @@
+/*
+ * bsbe1.h - ALPS BSBE1 tuner support (moved from av7110.c)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+
+#ifndef BSBE1_H
+#define BSBE1_H
+
+static u8 alps_bsbe1_inittab[] = {
+	0x01, 0x15,
+	0x02, 0x30,
+	0x03, 0x00,
+	0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+	0x05, 0x35,   /* I2CT = 0, SCLT = 1, SDAT = 1 */
+	0x06, 0x40,   /* DAC not used, set to high impendance mode */
+	0x07, 0x00,   /* DAC LSB */
+	0x08, 0x40,   /* DiSEqC off, LNB power on OP2/LOCK pin on */
+	0x09, 0x00,   /* FIFO */
+	0x0c, 0x51,   /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+	0x0d, 0x82,   /* DC offset compensation = ON, beta_agc1 = 2 */
+	0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
+	0x10, 0x3f,   // AGC2  0x3d
+	0x11, 0x84,
+	0x12, 0xb9,
+	0x15, 0xc9,   // lock detector threshold
+	0x16, 0x00,
+	0x17, 0x00,
+	0x18, 0x00,
+	0x19, 0x00,
+	0x1a, 0x00,
+	0x1f, 0x50,
+	0x20, 0x00,
+	0x21, 0x00,
+	0x22, 0x00,
+	0x23, 0x00,
+	0x28, 0x00,  // out imp: normal  out type: parallel FEC mode:0
+	0x29, 0x1e,  // 1/2 threshold
+	0x2a, 0x14,  // 2/3 threshold
+	0x2b, 0x0f,  // 3/4 threshold
+	0x2c, 0x09,  // 5/6 threshold
+	0x2d, 0x05,  // 7/8 threshold
+	0x2e, 0x01,
+	0x31, 0x1f,  // test all FECs
+	0x32, 0x19,  // viterbi and synchro search
+	0x33, 0xfc,  // rs control
+	0x34, 0x93,  // error control
+	0x0f, 0x92,
+	0xff, 0xff
+};
+
+
+static int alps_bsbe1_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
+{
+	u8 aclk = 0;
+	u8 bclk = 0;
+
+	if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
+	else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
+	else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
+	else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
+	else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
+	else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
+
+	stv0299_writereg(fe, 0x13, aclk);
+	stv0299_writereg(fe, 0x14, bclk);
+	stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
+	stv0299_writereg(fe, 0x20, (ratio >>  8) & 0xff);
+	stv0299_writereg(fe, 0x21, (ratio      ) & 0xf0);
+
+	return 0;
+}
+
+static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
+{
+	int ret;
+	u8 data[4];
+	u32 div;
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+	if ((params->frequency < 950000) || (params->frequency > 2150000))
+		return -EINVAL;
+
+	div = (params->frequency + (125 - 1)) / 125; // round correctly
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+	data[3] = (params->frequency > 1530000) ? 0xE0 : 0xE4;
+
+	ret = i2c_transfer(i2c, &msg, 1);
+	return (ret != 1) ? -EIO : 0;
+}
+
+static struct stv0299_config alps_bsbe1_config = {
+	.demod_address = 0x68,
+	.inittab = alps_bsbe1_inittab,
+	.mclk = 88000000UL,
+	.invert = 1,
+	.skip_reinit = 0,
+	.min_delay_ms = 100,
+	.set_symbol_rate = alps_bsbe1_set_symbol_rate,
+	.pll_set = alps_bsbe1_pll_set,
+};
+
+#endif
diff --git a/drivers/media/dvb/frontends/bsru6.h b/drivers/media/dvb/frontends/bsru6.h
new file mode 100644
index 0000000..2a5366c
--- /dev/null
+++ b/drivers/media/dvb/frontends/bsru6.h
@@ -0,0 +1,140 @@
+/*
+ * bsru6.h - ALPS BSRU6 tuner support (moved from budget-ci.c)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+
+#ifndef BSRU6_H
+#define BSRU6_H
+
+static u8 alps_bsru6_inittab[] = {
+	0x01, 0x15,
+	0x02, 0x00,
+	0x03, 0x00,
+	0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+	0x05, 0x35,   /* I2CT = 0, SCLT = 1, SDAT = 1 */
+	0x06, 0x40,   /* DAC not used, set to high impendance mode */
+	0x07, 0x00,   /* DAC LSB */
+	0x08, 0x40,   /* DiSEqC off, LNB power on OP2/LOCK pin on */
+	0x09, 0x00,   /* FIFO */
+	0x0c, 0x51,   /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+	0x0d, 0x82,   /* DC offset compensation = ON, beta_agc1 = 2 */
+	0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
+	0x10, 0x3f,   // AGC2  0x3d
+	0x11, 0x84,
+	0x12, 0xb9,
+	0x15, 0xc9,   // lock detector threshold
+	0x16, 0x00,
+	0x17, 0x00,
+	0x18, 0x00,
+	0x19, 0x00,
+	0x1a, 0x00,
+	0x1f, 0x50,
+	0x20, 0x00,
+	0x21, 0x00,
+	0x22, 0x00,
+	0x23, 0x00,
+	0x28, 0x00,  // out imp: normal  out type: parallel FEC mode:0
+	0x29, 0x1e,  // 1/2 threshold
+	0x2a, 0x14,  // 2/3 threshold
+	0x2b, 0x0f,  // 3/4 threshold
+	0x2c, 0x09,  // 5/6 threshold
+	0x2d, 0x05,  // 7/8 threshold
+	0x2e, 0x01,
+	0x31, 0x1f,  // test all FECs
+	0x32, 0x19,  // viterbi and synchro search
+	0x33, 0xfc,  // rs control
+	0x34, 0x93,  // error control
+	0x0f, 0x52,
+	0xff, 0xff
+};
+
+static int alps_bsru6_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
+{
+	u8 aclk = 0;
+	u8 bclk = 0;
+
+	if (srate < 1500000) {
+		aclk = 0xb7;
+		bclk = 0x47;
+	} else if (srate < 3000000) {
+		aclk = 0xb7;
+		bclk = 0x4b;
+	} else if (srate < 7000000) {
+		aclk = 0xb7;
+		bclk = 0x4f;
+	} else if (srate < 14000000) {
+		aclk = 0xb7;
+		bclk = 0x53;
+	} else if (srate < 30000000) {
+		aclk = 0xb6;
+		bclk = 0x53;
+	} else if (srate < 45000000) {
+		aclk = 0xb4;
+		bclk = 0x51;
+	}
+
+	stv0299_writereg(fe, 0x13, aclk);
+	stv0299_writereg(fe, 0x14, bclk);
+	stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
+	stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
+	stv0299_writereg(fe, 0x21, ratio & 0xf0);
+
+	return 0;
+}
+
+static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params)
+{
+	u8 buf[4];
+	u32 div;
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+
+	if ((params->frequency < 950000) || (params->frequency > 2150000))
+		return -EINVAL;
+
+	div = (params->frequency + (125 - 1)) / 125;	// round correctly
+	buf[0] = (div >> 8) & 0x7f;
+	buf[1] = div & 0xff;
+	buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+	buf[3] = 0xC4;
+
+	if (params->frequency > 1530000)
+		buf[3] = 0xc0;
+
+	if (i2c_transfer(i2c, &msg, 1) != 1)
+		return -EIO;
+	return 0;
+}
+
+static struct stv0299_config alps_bsru6_config = {
+	.demod_address = 0x68,
+	.inittab = alps_bsru6_inittab,
+	.mclk = 88000000UL,
+	.invert = 1,
+	.skip_reinit = 0,
+	.lock_output = STV0229_LOCKOUTPUT_1,
+	.volt13_op0_op1 = STV0299_VOLT13_OP1,
+	.min_delay_ms = 100,
+	.set_symbol_rate = alps_bsru6_set_symbol_rate,
+	.pll_set = alps_bsru6_pll_set,
+};
+
+#endif
diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c
index d15d32c..f3edf8b 100644
--- a/drivers/media/dvb/frontends/cx24110.c
+++ b/drivers/media/dvb/frontends/cx24110.c
@@ -371,6 +371,15 @@
 	return 0;
 }
 
+static int cx24110_sleep(struct dvb_frontend *fe)
+{
+	struct cx24110_state *state = fe->demodulator_priv;
+
+	if (state->config->pll_sleep)
+		  return state->config->pll_sleep(fe);
+	return 0;
+}
+
 static int cx24110_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
 {
 	struct cx24110_state *state = fe->demodulator_priv;
@@ -418,6 +427,9 @@
 	struct cx24110_state *state = fe->demodulator_priv;
 	unsigned long timeout;
 
+	if (cmd->msg_len < 3 || cmd->msg_len > 6)
+		return -EINVAL;  /* not implemented */
+
 	for (i = 0; i < cmd->msg_len; i++)
 		cx24110_writereg(state, 0x79 + i, cmd->msg[i]);
 
@@ -639,6 +651,7 @@
 	.release = cx24110_release,
 
 	.init = cx24110_initfe,
+	.sleep = cx24110_sleep,
 	.set_frontend = cx24110_set_frontend,
 	.get_frontend = cx24110_get_frontend,
 	.read_status = cx24110_read_status,
diff --git a/drivers/media/dvb/frontends/cx24110.h b/drivers/media/dvb/frontends/cx24110.h
index b63ecf2..609ac64 100644
--- a/drivers/media/dvb/frontends/cx24110.h
+++ b/drivers/media/dvb/frontends/cx24110.h
@@ -35,6 +35,7 @@
 	/* PLL maintenance */
 	int (*pll_init)(struct dvb_frontend* fe);
 	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+	int (*pll_sleep)(struct dvb_frontend* fe);
 };
 
 extern struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index 4dcb605..b6e2c38 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -362,6 +362,63 @@
 };
 EXPORT_SYMBOL(dvb_pll_philips_sd1878_tda8261);
 
+/*
+ * Philips TD1316 Tuner.
+ */
+static void td1316_bw(u8 *buf, u32 freq, int bandwidth)
+{
+	u8 band;
+
+	/* determine band */
+	if (freq < 161000000)
+		band = 1;
+	else if (freq < 444000000)
+		band = 2;
+	else
+		band = 4;
+
+	buf[3] |= band;
+
+	/* setup PLL filter */
+	if (bandwidth == BANDWIDTH_8_MHZ)
+		buf[3] |= 1 << 3;
+}
+
+struct dvb_pll_desc dvb_pll_philips_td1316 = {
+	.name  = "Philips TD1316",
+	.min   =  87000000,
+	.max   = 895000000,
+	.setbw = td1316_bw,
+	.count = 9,
+	.entries = {
+		{  93834000, 36166000, 166666, 0xca, 0x60},
+		{ 123834000, 36166000, 166666, 0xca, 0xa0},
+		{ 163834000, 36166000, 166666, 0xca, 0xc0},
+		{ 253834000, 36166000, 166666, 0xca, 0x60},
+		{ 383834000, 36166000, 166666, 0xca, 0xa0},
+		{ 443834000, 36166000, 166666, 0xca, 0xc0},
+		{ 583834000, 36166000, 166666, 0xca, 0x60},
+		{ 793834000, 36166000, 166666, 0xca, 0xa0},
+		{ 858834000, 36166000, 166666, 0xca, 0xe0},
+	},
+};
+EXPORT_SYMBOL(dvb_pll_philips_td1316);
+
+/* FE6600 used on DViCO Hybrid */
+struct dvb_pll_desc dvb_pll_thomson_fe6600 = {
+	.name = "Thomson FE6600",
+	.min =  44250000,
+	.max = 858000000,
+	.count = 4,
+	.entries = {
+		{ 250000000, 36213333, 166667, 0xb4, 0x12 },
+		{ 455000000, 36213333, 166667, 0xfe, 0x11 },
+		{ 775500000, 36213333, 166667, 0xbc, 0x18 },
+		{ 999999999, 36213333, 166667, 0xf4, 0x18 },
+	}
+};
+EXPORT_SYMBOL(dvb_pll_thomson_fe6600);
+
 /* ----------------------------------------------------------- */
 /* code                                                        */
 
@@ -391,8 +448,8 @@
 	div = (freq + desc->entries[i].offset) / desc->entries[i].stepsize;
 	buf[0] = div >> 8;
 	buf[1] = div & 0xff;
-	buf[2] = desc->entries[i].cb1;
-	buf[3] = desc->entries[i].cb2;
+	buf[2] = desc->entries[i].config;
+	buf[3] = desc->entries[i].cb;
 
 	if (desc->setbw)
 		desc->setbw(buf, freq, bandwidth);
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
index bb8d4b4..2b84617 100644
--- a/drivers/media/dvb/frontends/dvb-pll.h
+++ b/drivers/media/dvb/frontends/dvb-pll.h
@@ -15,8 +15,8 @@
 		u32 limit;
 		u32 offset;
 		u32 stepsize;
-		u8  cb1;
-		u8  cb2;
+		u8  config;
+		u8  cb;
 	} entries[12];
 };
 
@@ -40,6 +40,9 @@
 extern struct dvb_pll_desc dvb_pll_tdhu2;
 extern struct dvb_pll_desc dvb_pll_samsung_tbmv;
 extern struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261;
+extern struct dvb_pll_desc dvb_pll_philips_td1316;
+
+extern struct dvb_pll_desc dvb_pll_thomson_fe6600;
 
 int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
 		      u32 freq, int bandwidth);
diff --git a/drivers/media/dvb/frontends/lnbp21.h b/drivers/media/dvb/frontends/lnbp21.h
new file mode 100644
index 0000000..0dcbe61
--- /dev/null
+++ b/drivers/media/dvb/frontends/lnbp21.h
@@ -0,0 +1,139 @@
+/*
+ * lnbp21.h - driver for lnb supply and control ic lnbp21
+ *
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+
+#ifndef _LNBP21_H
+#define _LNBP21_H
+
+/* system register */
+#define LNBP21_OLF	0x01
+#define LNBP21_OTF	0x02
+#define LNBP21_EN	0x04
+#define LNBP21_VSEL	0x08
+#define LNBP21_LLC	0x10
+#define LNBP21_TEN	0x20
+#define LNBP21_ISEL	0x40
+#define LNBP21_PCL	0x80
+
+struct lnbp21 {
+	u8			config;
+	u8			override_or;
+	u8			override_and;
+	struct i2c_adapter	*i2c;
+	void			(*release_chain)(struct dvb_frontend* fe);
+};
+
+static int lnbp21_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+	struct i2c_msg msg = {	.addr = 0x08, .flags = 0,
+				.buf = &lnbp21->config,
+				.len = sizeof(lnbp21->config) };
+
+	lnbp21->config &= ~(LNBP21_VSEL | LNBP21_EN);
+
+	switch(voltage) {
+	case SEC_VOLTAGE_OFF:
+		break;
+	case SEC_VOLTAGE_13:
+		lnbp21->config |= LNBP21_EN;
+		break;
+	case SEC_VOLTAGE_18:
+		lnbp21->config |= (LNBP21_EN | LNBP21_VSEL);
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	lnbp21->config |= lnbp21->override_or;
+	lnbp21->config &= lnbp21->override_and;
+
+	return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
+{
+	struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+	struct i2c_msg msg = {	.addr = 0x08, .flags = 0,
+				.buf = &lnbp21->config,
+				.len = sizeof(lnbp21->config) };
+
+	if (arg)
+		lnbp21->config |= LNBP21_LLC;
+	else
+		lnbp21->config &= ~LNBP21_LLC;
+
+	lnbp21->config |= lnbp21->override_or;
+	lnbp21->config &= lnbp21->override_and;
+
+	return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static void lnbp21_exit(struct dvb_frontend *fe)
+{
+	struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+
+	/* LNBP power off */
+	lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+	/* free data & call next release routine */
+	fe->ops->release = lnbp21->release_chain;
+	kfree(fe->misc_priv);
+	fe->misc_priv = NULL;
+	if (fe->ops->release)
+		fe->ops->release(fe);
+}
+
+static int lnbp21_init(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
+{
+	struct lnbp21 *lnbp21 = kmalloc(sizeof(struct lnbp21), GFP_KERNEL);
+
+	if (!lnbp21)
+		return -ENOMEM;
+
+	/* default configuration */
+	lnbp21->config = LNBP21_ISEL;
+
+	/* bits which should be forced to '1' */
+	lnbp21->override_or = override_set;
+
+	/* bits which should be forced to '0' */
+	lnbp21->override_and = ~override_clear;
+
+	/* install release callback */
+	lnbp21->release_chain = fe->ops->release;
+	fe->ops->release = lnbp21_exit;
+
+	/* override frontend ops */
+	fe->ops->set_voltage = lnbp21_set_voltage;
+	fe->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
+
+	lnbp21->i2c = i2c;
+	fe->misc_priv = lnbp21;
+
+	return lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
+}
+
+#endif
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
index c63e9a5..8e8df7b 100644
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb/frontends/tda1004x.c
@@ -229,7 +229,7 @@
 	dprintk("%s\n", __FUNCTION__);
 
 	result = tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 2);
-	msleep(1);
+	msleep(20);
 	return result;
 }
 
@@ -502,7 +502,12 @@
 	const struct firmware *fw;
 
 	/* reset + wake up chip */
-	tda1004x_write_byteI(state, TDA1004X_CONFC4, 0);
+	if (state->config->xtal_freq == TDA10046_XTAL_4M) {
+		tda1004x_write_byteI(state, TDA1004X_CONFC4, 0);
+	} else {
+		dprintk("%s: 16MHz Xtal, reducing I2C speed\n", __FUNCTION__);
+		tda1004x_write_byteI(state, TDA1004X_CONFC4, 0x80);
+	}
 	tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0);
 	/* let the clocks recover from sleep */
 	msleep(5);
@@ -651,7 +656,7 @@
 	// tda setup
 	tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
 	tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87);    // 100 ppm crystal, select HP stream
-	tda1004x_write_byteI(state, TDA1004X_CONFC1, 8);      // disable pulse killer
+	tda1004x_write_byteI(state, TDA1004X_CONFC1, 0x88);      // enable pulse killer
 
 	switch (state->config->agc_config) {
 	case TDA10046_AGC_DEFAULT:
@@ -672,6 +677,12 @@
 		tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
 		tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x6a); // set AGC polarities
 		break;
+	case TDA10046_AGC_TDA827X_GPL:
+		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02);   // AGC setup
+		tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70);    // AGC Threshold
+		tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
+		tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities
+		break;
 	}
 	tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38);
 	tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x61); // Turn both AGC outputs on
@@ -683,6 +694,7 @@
 	tda1004x_write_byteI(state, TDA10046H_CVBER_CTRL, 0x1a); // 10^6 VBER measurement bits
 	tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config
 	tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config
+	// tda1004x_write_mask(state, 0x50, 0x80, 0x80);         // handle out of guard echoes
 	tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7);
 
 	state->initialised = 1;
@@ -1027,6 +1039,7 @@
 		if (status == -1)
 			return -EIO;
 		cber |= (status << 8);
+		// The address 0x20 should be read to cope with a TDA10046 bug
 		tda1004x_read_byte(state, TDA1004X_CBER_RESET);
 
 		if (cber != 65535)
@@ -1047,7 +1060,8 @@
 		status = tda1004x_read_byte(state, TDA1004X_VBER_MSB);
 		if (status == -1)
 			return -EIO;
-		vber |= ((status << 16) & 0x0f);
+		vber |= (status & 0x0f) << 16;
+		// The CVBER_LUT should be read to cope with TDA10046 hardware bug
 		tda1004x_read_byte(state, TDA1004X_CVBER_LUT);
 
 		// if RS has passed some valid TS packets, then we must be
@@ -1161,6 +1175,7 @@
 	if (tmp < 0)
 		return -EIO;
 	*ber |= (tmp << 9);
+	// The address 0x20 should be read to cope with a TDA10046 bug
 	tda1004x_read_byte(state, TDA1004X_CBER_RESET);
 
 	dprintk("%s: ber=0x%x\n", __FUNCTION__, *ber);
@@ -1187,6 +1202,8 @@
 				tda1004x_disable_tuner_i2c(state);
 			}
 		}
+		/* set outputs to tristate */
+		tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0xff);
 		tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1);
 		break;
 	}
diff --git a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h
index 8659c52..cc0c4af 100644
--- a/drivers/media/dvb/frontends/tda1004x.h
+++ b/drivers/media/dvb/frontends/tda1004x.h
@@ -35,7 +35,8 @@
 	TDA10046_AGC_DEFAULT,		/* original configuration */
 	TDA10046_AGC_IFO_AUTO_NEG,	/* IF AGC only, automatic, negtive */
 	TDA10046_AGC_IFO_AUTO_POS,	/* IF AGC only, automatic, positive */
-	TDA10046_AGC_TDA827X,	    /* IF AGC only, special setup for tda827x */
+	TDA10046_AGC_TDA827X,		/* IF AGC only, special setup for tda827x */
+	TDA10046_AGC_TDA827X_GPL,	/* same as above, but GPIOs 0 */
 };
 
 enum tda10046_if {
diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c
new file mode 100644
index 0000000..d7d9f59
--- /dev/null
+++ b/drivers/media/dvb/frontends/zl10353.c
@@ -0,0 +1,311 @@
+/*
+ * Driver for Zarlink DVB-T ZL10353 demodulator
+ *
+ * Copyright (C) 2006 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "zl10353_priv.h"
+#include "zl10353.h"
+
+struct zl10353_state {
+	struct i2c_adapter *i2c;
+	struct dvb_frontend frontend;
+	struct dvb_frontend_ops ops;
+
+	struct zl10353_config config;
+};
+
+static int debug_regs = 0;
+
+static int zl10353_single_write(struct dvb_frontend *fe, u8 reg, u8 val)
+{
+	struct zl10353_state *state = fe->demodulator_priv;
+	u8 buf[2] = { reg, val };
+	struct i2c_msg msg = { .addr = state->config.demod_address, .flags = 0,
+			       .buf = buf, .len = 2 };
+	int err = i2c_transfer(state->i2c, &msg, 1);
+	if (err != 1) {
+		printk("zl10353: write to reg %x failed (err = %d)!\n", reg, err);
+		return err;
+	}
+	return 0;
+}
+
+int zl10353_write(struct dvb_frontend *fe, u8 *ibuf, int ilen)
+{
+	int err, i;
+	for (i = 0; i < ilen - 1; i++)
+		if ((err = zl10353_single_write(fe, ibuf[0] + i, ibuf[i + 1])))
+			return err;
+
+	return 0;
+}
+
+static int zl10353_read_register(struct zl10353_state *state, u8 reg)
+{
+	int ret;
+	u8 b0[1] = { reg };
+	u8 b1[1] = { 0 };
+	struct i2c_msg msg[2] = { { .addr = state->config.demod_address,
+				    .flags = 0,
+				    .buf = b0, .len = 1 },
+				  { .addr = state->config.demod_address,
+				    .flags = I2C_M_RD,
+				    .buf = b1, .len = 1 } };
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2) {
+		printk("%s: readreg error (reg=%d, ret==%i)\n",
+		       __FUNCTION__, reg, ret);
+		return ret;
+	}
+
+	return b1[0];
+}
+
+static void zl10353_dump_regs(struct dvb_frontend *fe)
+{
+	struct zl10353_state *state = fe->demodulator_priv;
+	char buf[52], buf2[4];
+	int ret;
+	u8 reg;
+
+	/* Dump all registers. */
+	for (reg = 0; ; reg++) {
+		if (reg % 16 == 0) {
+			if (reg)
+				printk(KERN_DEBUG "%s\n", buf);
+			sprintf(buf, "%02x: ", reg);
+		}
+		ret = zl10353_read_register(state, reg);
+		if (ret >= 0)
+			sprintf(buf2, "%02x ", (u8)ret);
+		else
+			strcpy(buf2, "-- ");
+		strcat(buf, buf2);
+		if (reg == 0xff)
+			break;
+	}
+	printk(KERN_DEBUG "%s\n", buf);
+}
+
+static int zl10353_sleep(struct dvb_frontend *fe)
+{
+	static u8 zl10353_softdown[] = { 0x50, 0x0C, 0x44 };
+
+	zl10353_write(fe, zl10353_softdown, sizeof(zl10353_softdown));
+	return 0;
+}
+
+static int zl10353_set_parameters(struct dvb_frontend *fe,
+				  struct dvb_frontend_parameters *param)
+{
+	struct zl10353_state *state = fe->demodulator_priv;
+	u8 pllbuf[6] = { 0x67 };
+
+	/* These settings set "auto-everything" and start the FSM. */
+	zl10353_single_write(fe, 0x55, 0x80);
+	udelay(200);
+	zl10353_single_write(fe, 0xEA, 0x01);
+	udelay(200);
+	zl10353_single_write(fe, 0xEA, 0x00);
+
+	zl10353_single_write(fe, 0x56, 0x28);
+	zl10353_single_write(fe, 0x89, 0x20);
+	zl10353_single_write(fe, 0x5E, 0x00);
+	zl10353_single_write(fe, 0x65, 0x5A);
+	zl10353_single_write(fe, 0x66, 0xE9);
+	zl10353_single_write(fe, 0x62, 0x0A);
+
+	state->config.pll_set(fe, param, pllbuf + 1);
+	zl10353_write(fe, pllbuf, sizeof(pllbuf));
+
+	zl10353_single_write(fe, 0x70, 0x01);
+	udelay(250);
+	zl10353_single_write(fe, 0xE4, 0x00);
+	zl10353_single_write(fe, 0xE5, 0x2A);
+	zl10353_single_write(fe, 0xE9, 0x02);
+	zl10353_single_write(fe, 0xE7, 0x40);
+	zl10353_single_write(fe, 0xE8, 0x10);
+
+	return 0;
+}
+
+static int zl10353_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct zl10353_state *state = fe->demodulator_priv;
+	int s6, s7, s8;
+
+	if ((s6 = zl10353_read_register(state, STATUS_6)) < 0)
+		return -EREMOTEIO;
+	if ((s7 = zl10353_read_register(state, STATUS_7)) < 0)
+		return -EREMOTEIO;
+	if ((s8 = zl10353_read_register(state, STATUS_8)) < 0)
+		return -EREMOTEIO;
+
+	*status = 0;
+	if (s6 & (1 << 2))
+		*status |= FE_HAS_CARRIER;
+	if (s6 & (1 << 1))
+		*status |= FE_HAS_VITERBI;
+	if (s6 & (1 << 5))
+		*status |= FE_HAS_LOCK;
+	if (s7 & (1 << 4))
+		*status |= FE_HAS_SYNC;
+	if (s8 & (1 << 6))
+		*status |= FE_HAS_SIGNAL;
+
+	if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) !=
+	    (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC))
+		*status &= ~FE_HAS_LOCK;
+
+	return 0;
+}
+
+static int zl10353_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct zl10353_state *state = fe->demodulator_priv;
+	u8 _snr;
+
+	if (debug_regs)
+		zl10353_dump_regs(fe);
+
+	_snr = zl10353_read_register(state, SNR);
+	*snr = (_snr << 8) | _snr;
+
+	return 0;
+}
+
+static int zl10353_get_tune_settings(struct dvb_frontend *fe,
+				     struct dvb_frontend_tune_settings
+					 *fe_tune_settings)
+{
+	fe_tune_settings->min_delay_ms = 1000;
+	fe_tune_settings->step_size = 0;
+	fe_tune_settings->max_drift = 0;
+
+	return 0;
+}
+
+static int zl10353_init(struct dvb_frontend *fe)
+{
+	struct zl10353_state *state = fe->demodulator_priv;
+	u8 zl10353_reset_attach[6] = { 0x50, 0x03, 0x64, 0x46, 0x15, 0x0F };
+	int rc = 0;
+
+	if (debug_regs)
+		zl10353_dump_regs(fe);
+
+	/* Do a "hard" reset if not already done */
+	if (zl10353_read_register(state, 0x50) != 0x03) {
+		rc = zl10353_write(fe, zl10353_reset_attach,
+				   sizeof(zl10353_reset_attach));
+		if (debug_regs)
+			zl10353_dump_regs(fe);
+	}
+
+	return 0;
+}
+
+static void zl10353_release(struct dvb_frontend *fe)
+{
+	struct zl10353_state *state = fe->demodulator_priv;
+
+	kfree(state);
+}
+
+static struct dvb_frontend_ops zl10353_ops;
+
+struct dvb_frontend *zl10353_attach(const struct zl10353_config *config,
+				    struct i2c_adapter *i2c)
+{
+	struct zl10353_state *state = NULL;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct zl10353_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->i2c = i2c;
+	memcpy(&state->config, config, sizeof(struct zl10353_config));
+	memcpy(&state->ops, &zl10353_ops, sizeof(struct dvb_frontend_ops));
+
+	/* check if the demod is there */
+	if (zl10353_read_register(state, CHIP_ID) != ID_ZL10353)
+		goto error;
+
+	/* create dvb_frontend */
+	state->frontend.ops = &state->ops;
+	state->frontend.demodulator_priv = state;
+
+	return &state->frontend;
+error:
+	kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops zl10353_ops = {
+
+	.info = {
+		.name			= "Zarlink ZL10353 DVB-T",
+		.type			= FE_OFDM,
+		.frequency_min		= 174000000,
+		.frequency_max		= 862000000,
+		.frequency_stepsize	= 166667,
+		.frequency_tolerance	= 0,
+		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
+			FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+			FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER |
+			FE_CAN_MUTE_TS
+	},
+
+	.release = zl10353_release,
+
+	.init = zl10353_init,
+	.sleep = zl10353_sleep,
+
+	.set_frontend = zl10353_set_parameters,
+	.get_tune_settings = zl10353_get_tune_settings,
+
+	.read_status = zl10353_read_status,
+	.read_snr = zl10353_read_snr,
+};
+
+module_param(debug_regs, int, 0644);
+MODULE_PARM_DESC(debug_regs, "Turn on/off frontend register dumps (default:off).");
+
+MODULE_DESCRIPTION("Zarlink ZL10353 DVB-T demodulator driver");
+MODULE_AUTHOR("Chris Pascoe");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(zl10353_attach);
+EXPORT_SYMBOL(zl10353_write);
diff --git a/drivers/media/dvb/frontends/zl10353.h b/drivers/media/dvb/frontends/zl10353.h
new file mode 100644
index 0000000..5cc4ae71
--- /dev/null
+++ b/drivers/media/dvb/frontends/zl10353.h
@@ -0,0 +1,43 @@
+/*
+ *  Driver for Zarlink DVB-T ZL10353 demodulator
+ *
+ *  Copyright (C) 2006 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
+ *
+ *  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 ZL10353_H
+#define ZL10353_H
+
+#include <linux/dvb/frontend.h>
+
+struct zl10353_config
+{
+	/* demodulator's I2C address */
+	u8 demod_address;
+
+	/* function which configures the PLL buffer (for secondary I2C
+	 * connected tuner) or tunes the PLL (for direct connected tuner) */
+	int (*pll_set)(struct dvb_frontend *fe,
+		       struct dvb_frontend_parameters *params, u8 *pllbuf);
+};
+
+extern struct dvb_frontend* zl10353_attach(const struct zl10353_config *config,
+					   struct i2c_adapter *i2c);
+
+extern int zl10353_write(struct dvb_frontend *fe, u8 *ibuf, int ilen);
+
+#endif /* ZL10353_H */
diff --git a/drivers/media/dvb/frontends/zl10353_priv.h b/drivers/media/dvb/frontends/zl10353_priv.h
new file mode 100644
index 0000000..b72224b
--- /dev/null
+++ b/drivers/media/dvb/frontends/zl10353_priv.h
@@ -0,0 +1,42 @@
+/*
+ *  Driver for Zarlink DVB-T ZL10353 demodulator
+ *
+ *  Copyright (C) 2006 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
+ *
+ *  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 _ZL10353_PRIV_
+#define _ZL10353_PRIV_
+
+#define ID_ZL10353	0x14
+
+enum zl10353_reg_addr {
+	INTERRUPT_0	= 0x00,
+	INTERRUPT_1	= 0x01,
+	INTERRUPT_2	= 0x02,
+	INTERRUPT_3	= 0x03,
+	INTERRUPT_4	= 0x04,
+	INTERRUPT_5	= 0x05,
+	STATUS_6	= 0x06,
+	STATUS_7	= 0x07,
+	STATUS_8	= 0x08,
+	STATUS_9	= 0x09,
+	SNR		= 0x10,
+	CHIP_ID		= 0x7F,
+};
+
+#endif                          /* _ZL10353_PRIV_ */
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 7c6ccb9..840efec 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -54,7 +54,6 @@
 #include <linux/i2c.h>
 
 #include <asm/system.h>
-#include <asm/semaphore.h>
 
 #include <linux/dvb/frontend.h>
 
@@ -67,6 +66,10 @@
 #include "av7110_ca.h"
 #include "av7110_ipack.h"
 
+#include "bsbe1.h"
+#include "lnbp21.h"
+#include "bsru6.h"
+
 #define TS_WIDTH  376
 #define TS_HEIGHT 512
 #define TS_BUFLEN (TS_WIDTH*TS_HEIGHT)
@@ -82,6 +85,8 @@
 static int rgb_on;
 static int volume = 255;
 static int budgetpatch;
+static int wss_cfg_4_3 = 0x4008;
+static int wss_cfg_16_9 = 0x0007;
 
 module_param_named(debug, av7110_debug, int, 0644);
 MODULE_PARM_DESC(debug, "debug level (bitmask, default 0)");
@@ -100,6 +105,10 @@
 MODULE_PARM_DESC(volume, "initial volume: default 255 (range 0-255)");
 module_param(budgetpatch, int, 0444);
 MODULE_PARM_DESC(budgetpatch, "use budget-patch hardware modification: default 0 (0 no, 1 autodetect, 2 always)");
+module_param(wss_cfg_4_3, int, 0444);
+MODULE_PARM_DESC(wss_cfg_4_3, "WSS 4:3 - default 0x4008 - bit 15: disable, 14: burst mode, 13..0: wss data");
+module_param(wss_cfg_16_9, int, 0444);
+MODULE_PARM_DESC(wss_cfg_16_9, "WSS 16:9 - default 0x0007 - bit 15: disable, 14: burst mode, 13..0: wss data");
 
 static void restart_feeds(struct av7110 *av7110);
 
@@ -125,6 +134,13 @@
 	if (ret < 0)
 		printk("dvb-ttpci:cannot set internal volume to maximum:%d\n",ret);
 
+	ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 2, wss_cfg_4_3);
+	if (ret < 0)
+		printk("dvb-ttpci: unable to configure 4:3 wss\n");
+	ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 3, wss_cfg_16_9);
+	if (ret < 0)
+		printk("dvb-ttpci: unable to configure 16:9 wss\n");
+
 	ret = av7710_set_video_mode(av7110, vidmode);
 	if (ret < 0)
 		printk("dvb-ttpci:cannot set video mode:%d\n",ret);
@@ -242,10 +258,10 @@
 		if (!av7110->arm_ready)
 			continue;
 
-		if (down_interruptible(&av7110->dcomlock))
+		if (mutex_lock_interruptible(&av7110->dcomlock))
 			break;
 		newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2);
-		up(&av7110->dcomlock);
+		mutex_unlock(&av7110->dcomlock);
 
 		if (newloops == av7110->arm_loops || av7110->arm_errors > 3) {
 			printk(KERN_ERR "dvb-ttpci: ARM crashed @ card %d\n",
@@ -253,10 +269,10 @@
 
 			recover_arm(av7110);
 
-			if (down_interruptible(&av7110->dcomlock))
+			if (mutex_lock_interruptible(&av7110->dcomlock))
 				break;
 			newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2) - 1;
-			up(&av7110->dcomlock);
+			mutex_unlock(&av7110->dcomlock);
 		}
 		av7110->arm_loops = newloops;
 		av7110->arm_errors = 0;
@@ -741,7 +757,7 @@
 	int ret = 0;
 	dprintk(4, "%p\n", av7110);
 
-	if (down_interruptible(&av7110->pid_mutex))
+	if (mutex_lock_interruptible(&av7110->pid_mutex))
 		return -ERESTARTSYS;
 
 	if (!(vpid & 0x8000))
@@ -760,7 +776,7 @@
 		ret = SetPIDs(av7110, vpid, apid, ttpid, subpid, pcrpid);
 	}
 
-	up(&av7110->pid_mutex);
+	mutex_unlock(&av7110->pid_mutex);
 	return ret;
 }
 
@@ -1088,11 +1104,9 @@
 	struct av7110 *av7110;
 
 	/* pointer casting paranoia... */
-	if (!demux)
-		BUG();
+	BUG_ON(!demux);
 	dvbdemux = (struct dvb_demux *) demux->priv;
-	if (!dvbdemux)
-		BUG();
+	BUG_ON(!dvbdemux);
 	av7110 = (struct av7110 *) dvbdemux->priv;
 
 	dprintk(4, "%p\n", av7110);
@@ -1570,208 +1584,6 @@
 	.pll_set = alps_bsrv2_pll_set,
 };
 
-
-static u8 alps_bsru6_inittab[] = {
-	0x01, 0x15,
-	0x02, 0x30,
-	0x03, 0x00,
-	0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
-	0x05, 0x35,   /* I2CT = 0, SCLT = 1, SDAT = 1 */
-	0x06, 0x40,   /* DAC not used, set to high impendance mode */
-	0x07, 0x00,   /* DAC LSB */
-	0x08, 0x40,   /* DiSEqC off, LNB power on OP2/LOCK pin on */
-	0x09, 0x00,   /* FIFO */
-	0x0c, 0x51,   /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
-	0x0d, 0x82,   /* DC offset compensation = ON, beta_agc1 = 2 */
-	0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
-	0x10, 0x3f,   // AGC2  0x3d
-	0x11, 0x84,
-	0x12, 0xb9,
-	0x15, 0xc9,   // lock detector threshold
-	0x16, 0x00,
-	0x17, 0x00,
-	0x18, 0x00,
-	0x19, 0x00,
-	0x1a, 0x00,
-	0x1f, 0x50,
-	0x20, 0x00,
-	0x21, 0x00,
-	0x22, 0x00,
-	0x23, 0x00,
-	0x28, 0x00,  // out imp: normal  out type: parallel FEC mode:0
-	0x29, 0x1e,  // 1/2 threshold
-	0x2a, 0x14,  // 2/3 threshold
-	0x2b, 0x0f,  // 3/4 threshold
-	0x2c, 0x09,  // 5/6 threshold
-	0x2d, 0x05,  // 7/8 threshold
-	0x2e, 0x01,
-	0x31, 0x1f,  // test all FECs
-	0x32, 0x19,  // viterbi and synchro search
-	0x33, 0xfc,  // rs control
-	0x34, 0x93,  // error control
-	0x0f, 0x52,
-	0xff, 0xff
-};
-
-static int alps_bsru6_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
-{
-	u8 aclk = 0;
-	u8 bclk = 0;
-
-	if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
-	else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
-	else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
-	else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
-	else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
-	else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
-
-	stv0299_writereg(fe, 0x13, aclk);
-	stv0299_writereg(fe, 0x14, bclk);
-	stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
-	stv0299_writereg(fe, 0x20, (ratio >>  8) & 0xff);
-	stv0299_writereg(fe, 0x21, (ratio      ) & 0xf0);
-
-	return 0;
-}
-
-static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
-{
-	int ret;
-	u8 data[4];
-	u32 div;
-	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
-
-	if ((params->frequency < 950000) || (params->frequency > 2150000))
-		return -EINVAL;
-
-	div = (params->frequency + (125 - 1)) / 125; // round correctly
-	data[0] = (div >> 8) & 0x7f;
-	data[1] = div & 0xff;
-	data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
-	data[3] = 0xC4;
-
-	if (params->frequency > 1530000) data[3] = 0xc0;
-
-	ret = i2c_transfer(i2c, &msg, 1);
-	if (ret != 1)
-		return -EIO;
-	return 0;
-}
-
-static struct stv0299_config alps_bsru6_config = {
-
-	.demod_address = 0x68,
-	.inittab = alps_bsru6_inittab,
-	.mclk = 88000000UL,
-	.invert = 1,
-	.skip_reinit = 0,
-	.lock_output = STV0229_LOCKOUTPUT_1,
-	.volt13_op0_op1 = STV0299_VOLT13_OP1,
-	.min_delay_ms = 100,
-	.set_symbol_rate = alps_bsru6_set_symbol_rate,
-	.pll_set = alps_bsru6_pll_set,
-};
-
-
-static u8 alps_bsbe1_inittab[] = {
-	0x01, 0x15,
-	0x02, 0x30,
-	0x03, 0x00,
-	0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
-	0x05, 0x35,   /* I2CT = 0, SCLT = 1, SDAT = 1 */
-	0x06, 0x40,   /* DAC not used, set to high impendance mode */
-	0x07, 0x00,   /* DAC LSB */
-	0x08, 0x40,   /* DiSEqC off, LNB power on OP2/LOCK pin on */
-	0x09, 0x00,   /* FIFO */
-	0x0c, 0x51,   /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
-	0x0d, 0x82,   /* DC offset compensation = ON, beta_agc1 = 2 */
-	0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
-	0x10, 0x3f,   // AGC2  0x3d
-	0x11, 0x84,
-	0x12, 0xb9,
-	0x15, 0xc9,   // lock detector threshold
-	0x16, 0x00,
-	0x17, 0x00,
-	0x18, 0x00,
-	0x19, 0x00,
-	0x1a, 0x00,
-	0x1f, 0x50,
-	0x20, 0x00,
-	0x21, 0x00,
-	0x22, 0x00,
-	0x23, 0x00,
-	0x28, 0x00,  // out imp: normal  out type: parallel FEC mode:0
-	0x29, 0x1e,  // 1/2 threshold
-	0x2a, 0x14,  // 2/3 threshold
-	0x2b, 0x0f,  // 3/4 threshold
-	0x2c, 0x09,  // 5/6 threshold
-	0x2d, 0x05,  // 7/8 threshold
-	0x2e, 0x01,
-	0x31, 0x1f,  // test all FECs
-	0x32, 0x19,  // viterbi and synchro search
-	0x33, 0xfc,  // rs control
-	0x34, 0x93,  // error control
-	0x0f, 0x92,
-	0xff, 0xff
-};
-
-static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
-{
-	int ret;
-	u8 data[4];
-	u32 div;
-	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
-
-	if ((params->frequency < 950000) || (params->frequency > 2150000))
-		return -EINVAL;
-
-	div = (params->frequency + (125 - 1)) / 125; // round correctly
-	data[0] = (div >> 8) & 0x7f;
-	data[1] = div & 0xff;
-	data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
-	data[3] = (params->frequency > 1530000) ? 0xE0 : 0xE4;
-
-	ret = i2c_transfer(i2c, &msg, 1);
-	return (ret != 1) ? -EIO : 0;
-}
-
-static struct stv0299_config alps_bsbe1_config = {
-	.demod_address = 0x68,
-	.inittab = alps_bsbe1_inittab,
-	.mclk = 88000000UL,
-	.invert = 1,
-	.skip_reinit = 0,
-	.min_delay_ms = 100,
-	.set_symbol_rate = alps_bsru6_set_symbol_rate,
-	.pll_set = alps_bsbe1_pll_set,
-};
-
-static int lnbp21_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
-{
-	struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
-	int ret;
-	u8 data[1];
-	struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = data, .len = sizeof(data) };
-
-	switch(voltage) {
-	case SEC_VOLTAGE_OFF:
-		data[0] = 0x00;
-		break;
-	case SEC_VOLTAGE_13:
-		data[0] = 0x44;
-		break;
-	case SEC_VOLTAGE_18:
-		data[0] = 0x4c;
-		break;
-	default:
-		return -EINVAL;
-	};
-
-	ret = i2c_transfer(&av7110->i2c_adap, &msg, 1);
-	return (ret != 1) ? -EIO : 0;
-}
-
-
 static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
 	struct av7110* av7110 = fe->dvb->priv;
@@ -2096,7 +1908,7 @@
 	if (av7110->playing)
 		return 0;
 
-	if (down_interruptible(&av7110->pid_mutex))
+	if (mutex_lock_interruptible(&av7110->pid_mutex))
 		return -ERESTARTSYS;
 
 	if (synced) {
@@ -2118,7 +1930,7 @@
 	if (!ret)
 		av7110->fe_synced = synced;
 
-	up(&av7110->pid_mutex);
+	mutex_unlock(&av7110->pid_mutex);
 	return ret;
 }
 
@@ -2374,9 +2186,15 @@
 			/* ALPS BSBE1 */
 			av7110->fe = stv0299_attach(&alps_bsbe1_config, &av7110->i2c_adap);
 			if (av7110->fe) {
-				av7110->fe->ops->set_voltage = lnbp21_set_voltage;
-				av7110->fe->ops->dishnetwork_send_legacy_command = NULL;
-				av7110->recover = dvb_s_recover;
+				if (lnbp21_init(av7110->fe, &av7110->i2c_adap, 0, 0)) {
+					printk("dvb-ttpci: LNBP21 not found!\n");
+					if (av7110->fe->ops->release)
+						av7110->fe->ops->release(av7110->fe);
+					av7110->fe = NULL;
+				} else {
+					av7110->fe->ops->dishnetwork_send_legacy_command = NULL;
+					av7110->recover = dvb_s_recover;
+				}
 			}
 			break;
 		}
@@ -2714,16 +2532,16 @@
 	tasklet_init (&av7110->debi_tasklet, debiirq, (unsigned long) av7110);
 	tasklet_init (&av7110->gpio_tasklet, gpioirq, (unsigned long) av7110);
 
-	sema_init(&av7110->pid_mutex, 1);
+	mutex_init(&av7110->pid_mutex);
 
 	/* locks for data transfers from/to AV7110 */
 	spin_lock_init(&av7110->debilock);
-	sema_init(&av7110->dcomlock, 1);
+	mutex_init(&av7110->dcomlock);
 	av7110->debitype = -1;
 
 	/* default OSD window */
 	av7110->osdwin = 1;
-	sema_init(&av7110->osd_sema, 1);
+	mutex_init(&av7110->osd_mutex);
 
 	/* ARM "watchdog" */
 	init_waitqueue_head(&av7110->arm_wait);
diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h
index fafd25f..3e2e121 100644
--- a/drivers/media/dvb/ttpci/av7110.h
+++ b/drivers/media/dvb/ttpci/av7110.h
@@ -16,6 +16,7 @@
 #include <linux/dvb/ca.h>
 #include <linux/dvb/osd.h>
 #include <linux/dvb/net.h>
+#include <linux/mutex.h>
 
 #include "dvbdev.h"
 #include "demux.h"
@@ -127,7 +128,7 @@
 	/* DEBI and polled command interface */
 
 	spinlock_t		debilock;
-	struct semaphore	dcomlock;
+	struct mutex		dcomlock;
 	volatile int		debitype;
 	volatile int		debilen;
 
@@ -146,7 +147,7 @@
 
 	int			osdwin;      /* currently active window */
 	u16			osdbpp[8];
-	struct semaphore	osd_sema;
+	struct mutex		osd_mutex;
 
 	/* CA */
 
@@ -172,7 +173,7 @@
 	struct tasklet_struct   vpe_tasklet;
 
 	int			fe_synced;
-	struct semaphore	pid_mutex;
+	struct mutex		pid_mutex;
 
 	int			video_blank;
 	struct video_status	videostate;
diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c
index 0bb6e74..75736f2 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.c
+++ b/drivers/media/dvb/ttpci/av7110_hw.c
@@ -327,10 +327,10 @@
 	start = jiffies;
 	for (;;) {
 		err = time_after(jiffies, start + ARM_WAIT_FREE);
-		if (down_interruptible(&av7110->dcomlock))
+		if (mutex_lock_interruptible(&av7110->dcomlock))
 			return -ERESTARTSYS;
 		stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
-		up(&av7110->dcomlock);
+		mutex_unlock(&av7110->dcomlock);
 		if ((stat & flags) == 0)
 			break;
 		if (err) {
@@ -487,11 +487,11 @@
 		dprintk(1, "arm not ready.\n");
 		return -1;
 	}
-	if (down_interruptible(&av7110->dcomlock))
+	if (mutex_lock_interruptible(&av7110->dcomlock))
 		return -ERESTARTSYS;
 
 	ret = __av7110_send_fw_cmd(av7110, buf, length);
-	up(&av7110->dcomlock);
+	mutex_unlock(&av7110->dcomlock);
 	if (ret && ret!=-ERESTARTSYS)
 		printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n",
 		       __FUNCTION__, ret);
@@ -563,11 +563,11 @@
 		return -1;
 	}
 
-	if (down_interruptible(&av7110->dcomlock))
+	if (mutex_lock_interruptible(&av7110->dcomlock))
 		return -ERESTARTSYS;
 
 	if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) {
-		up(&av7110->dcomlock);
+		mutex_unlock(&av7110->dcomlock);
 		printk(KERN_ERR "dvb-ttpci: av7110_fw_request error %d\n", err);
 		return err;
 	}
@@ -579,7 +579,7 @@
 			break;
 		if (err) {
 			printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __FUNCTION__);
-			up(&av7110->dcomlock);
+			mutex_unlock(&av7110->dcomlock);
 			return -ETIMEDOUT;
 		}
 #ifdef _NOHANDSHAKE
@@ -595,7 +595,7 @@
 			break;
 		if (err) {
 			printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
-			up(&av7110->dcomlock);
+			mutex_unlock(&av7110->dcomlock);
 			return -ETIMEDOUT;
 		}
 		msleep(1);
@@ -606,12 +606,12 @@
 	stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
 	if (stat & GPMQOver) {
 		printk(KERN_ERR "%s: GPMQOver\n", __FUNCTION__);
-		up(&av7110->dcomlock);
+		mutex_unlock(&av7110->dcomlock);
 		return -1;
 	}
 	else if (stat & OSDQOver) {
 		printk(KERN_ERR "%s: OSDQOver\n", __FUNCTION__);
-		up(&av7110->dcomlock);
+		mutex_unlock(&av7110->dcomlock);
 		return -1;
 	}
 #endif
@@ -619,7 +619,7 @@
 	for (i = 0; i < reply_buf_len; i++)
 		reply_buf[i] = rdebi(av7110, DEBINOSWAP, COM_BUFF + 2 * i, 0, 2);
 
-	up(&av7110->dcomlock);
+	mutex_unlock(&av7110->dcomlock);
 	return 0;
 }
 
@@ -735,7 +735,7 @@
 	unsigned long start;
 	int err;
 
-	if (down_interruptible(&av7110->dcomlock))
+	if (mutex_lock_interruptible(&av7110->dcomlock))
 		return -ERESTARTSYS;
 	start = jiffies;
 	while (1) {
@@ -745,12 +745,12 @@
 		if (err) {
 			printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n",
 			       __FUNCTION__);
-			up(&av7110->dcomlock);
+			mutex_unlock(&av7110->dcomlock);
 			return -ETIMEDOUT;
 		}
 		msleep(1);
 	}
-	up(&av7110->dcomlock);
+	mutex_unlock(&av7110->dcomlock);
 	return 0;
 }
 
@@ -761,7 +761,7 @@
 	int length = strlen(buf) + 1;
 	u16 cbuf[5] = { (COMTYPE_OSD << 8) + DText, 3, win, x, y };
 
-	if (down_interruptible(&av7110->dcomlock))
+	if (mutex_lock_interruptible(&av7110->dcomlock))
 		return -ERESTARTSYS;
 
 	start = jiffies;
@@ -772,7 +772,7 @@
 		if (ret) {
 			printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n",
 			       __FUNCTION__);
-			up(&av7110->dcomlock);
+			mutex_unlock(&av7110->dcomlock);
 			return -ETIMEDOUT;
 		}
 		msleep(1);
@@ -786,7 +786,7 @@
 		if (ret) {
 			printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n",
 			       __FUNCTION__);
-			up(&av7110->dcomlock);
+			mutex_unlock(&av7110->dcomlock);
 			return -ETIMEDOUT;
 		}
 		msleep(1);
@@ -798,7 +798,7 @@
 	if (length & 1)
 		wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2);
 	ret = __av7110_send_fw_cmd(av7110, cbuf, 5);
-	up(&av7110->dcomlock);
+	mutex_unlock(&av7110->dcomlock);
 	if (ret && ret!=-ERESTARTSYS)
 		printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret);
 	return ret;
@@ -1062,7 +1062,7 @@
 {
 	int ret;
 
-	if (down_interruptible(&av7110->osd_sema))
+	if (mutex_lock_interruptible(&av7110->osd_mutex))
 		return -ERESTARTSYS;
 
 	switch (dc->cmd) {
@@ -1198,7 +1198,7 @@
 		break;
 	}
 
-	up(&av7110->osd_sema);
+	mutex_unlock(&av7110->osd_mutex);
 	if (ret==-ERESTARTSYS)
 		dprintk(1, "av7110_osd_cmd(%d) returns with -ERESTARTSYS\n",dc->cmd);
 	else if (ret)
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
index 94cf38c..2f23cea 100644
--- a/drivers/media/dvb/ttpci/av7110_v4l.c
+++ b/drivers/media/dvb/ttpci/av7110_v4l.c
@@ -579,14 +579,11 @@
 		return -EFAULT;
 	if ((d.id != 0 && d.id != V4L2_SLICED_WSS_625) || d.field != 0 || d.line != 23)
 		return -EINVAL;
-	if (d.id) {
+	if (d.id)
 		av7110->wssData = ((d.data[1] << 8) & 0x3f00) | d.data[0];
-		rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig,
-				   2, 1, av7110->wssData);
-	} else {
-		av7110->wssData = 0;
-		rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 1, 0);
-	}
+	else
+		av7110->wssData = 0x8000;
+	rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 1, av7110->wssData);
 	return (rc < 0) ? rc : count;
 }
 
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 1465c04..9dd4745 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -1000,6 +1000,7 @@
 
 #define SUBID_DVBS_TV_STAR	0x0014
 #define SUBID_DVBS_TV_STAR_CI	0x0016
+#define SUBID_DVBS_EASYWATCH	0x001e
 #define SUBID_DVBC_KNC1		0x0020
 #define SUBID_DVBC_KNC1_PLUS	0x0021
 #define SUBID_DVBC_CINERGY1200	0x1156
@@ -1038,6 +1039,7 @@
 	case SUBID_DVBS_TV_STAR:
 	case SUBID_DVBS_TV_STAR_CI:
 	case SUBID_DVBS_CYNERGY1200N:
+	case SUBID_DVBS_EASYWATCH:
 		fe = stv0299_attach(&philips_sd1878_config,
 				&budget_av->budget.i2c_adap);
 		break;
@@ -1285,6 +1287,7 @@
 MAKE_BUDGET_INFO(knc1c, "KNC1 DVB-C", BUDGET_KNC1C);
 MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T);
 MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR);
+MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR);
 MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP);
 MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP);
 MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP);
@@ -1300,6 +1303,7 @@
 	MAKE_EXTENSION_PCI(knc1sp, 0x1131, 0x0011),
 	MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014),
 	MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016),
+	MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
 	MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
 	MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021),
 	MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030),
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index b9b3cd9..5f91036 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -42,6 +42,9 @@
 #include "stv0299.h"
 #include "stv0297.h"
 #include "tda1004x.h"
+#include "lnbp21.h"
+#include "bsbe1.h"
+#include "bsru6.h"
 
 #define DEBIADDR_IR		0x1234
 #define DEBIADDR_CICONTROL	0x0000
@@ -474,123 +477,6 @@
 		tasklet_schedule(&budget_ci->ciintf_irq_tasklet);
 }
 
-
-static u8 alps_bsru6_inittab[] = {
-	0x01, 0x15,
-	0x02, 0x00,
-	0x03, 0x00,
-	0x04, 0x7d,		/* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
-	0x05, 0x35,		/* I2CT = 0, SCLT = 1, SDAT = 1 */
-	0x06, 0x40,		/* DAC not used, set to high impendance mode */
-	0x07, 0x00,		/* DAC LSB */
-	0x08, 0x40,		/* DiSEqC off, LNB power on OP2/LOCK pin on */
-	0x09, 0x00,		/* FIFO */
-	0x0c, 0x51,		/* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
-	0x0d, 0x82,		/* DC offset compensation = ON, beta_agc1 = 2 */
-	0x0e, 0x23,		/* alpha_tmg = 2, beta_tmg = 3 */
-	0x10, 0x3f,		// AGC2  0x3d
-	0x11, 0x84,
-	0x12, 0xb9,
-	0x15, 0xc9,		// lock detector threshold
-	0x16, 0x00,
-	0x17, 0x00,
-	0x18, 0x00,
-	0x19, 0x00,
-	0x1a, 0x00,
-	0x1f, 0x50,
-	0x20, 0x00,
-	0x21, 0x00,
-	0x22, 0x00,
-	0x23, 0x00,
-	0x28, 0x00,		// out imp: normal  out type: parallel FEC mode:0
-	0x29, 0x1e,		// 1/2 threshold
-	0x2a, 0x14,		// 2/3 threshold
-	0x2b, 0x0f,		// 3/4 threshold
-	0x2c, 0x09,		// 5/6 threshold
-	0x2d, 0x05,		// 7/8 threshold
-	0x2e, 0x01,
-	0x31, 0x1f,		// test all FECs
-	0x32, 0x19,		// viterbi and synchro search
-	0x33, 0xfc,		// rs control
-	0x34, 0x93,		// error control
-	0x0f, 0x52,
-	0xff, 0xff
-};
-
-static int alps_bsru6_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
-{
-	u8 aclk = 0;
-	u8 bclk = 0;
-
-	if (srate < 1500000) {
-		aclk = 0xb7;
-		bclk = 0x47;
-	} else if (srate < 3000000) {
-		aclk = 0xb7;
-		bclk = 0x4b;
-	} else if (srate < 7000000) {
-		aclk = 0xb7;
-		bclk = 0x4f;
-	} else if (srate < 14000000) {
-		aclk = 0xb7;
-		bclk = 0x53;
-	} else if (srate < 30000000) {
-		aclk = 0xb6;
-		bclk = 0x53;
-	} else if (srate < 45000000) {
-		aclk = 0xb4;
-		bclk = 0x51;
-	}
-
-	stv0299_writereg(fe, 0x13, aclk);
-	stv0299_writereg(fe, 0x14, bclk);
-	stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
-	stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
-	stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
-
-	return 0;
-}
-
-static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params)
-{
-	u8 buf[4];
-	u32 div;
-	struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) };
-
-	if ((params->frequency < 950000) || (params->frequency > 2150000))
-		return -EINVAL;
-
-	div = (params->frequency + (125 - 1)) / 125;	// round correctly
-	buf[0] = (div >> 8) & 0x7f;
-	buf[1] = div & 0xff;
-	buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
-	buf[3] = 0xC4;
-
-	if (params->frequency > 1530000)
-		buf[3] = 0xc0;
-
-	if (i2c_transfer(i2c, &msg, 1) != 1)
-		return -EIO;
-	return 0;
-}
-
-static struct stv0299_config alps_bsru6_config = {
-
-	.demod_address = 0x68,
-	.inittab = alps_bsru6_inittab,
-	.mclk = 88000000UL,
-	.invert = 1,
-	.skip_reinit = 0,
-	.lock_output = STV0229_LOCKOUTPUT_1,
-	.volt13_op0_op1 = STV0299_VOLT13_OP1,
-	.min_delay_ms = 100,
-	.set_symbol_rate = alps_bsru6_set_symbol_rate,
-	.pll_set = alps_bsru6_pll_set,
-};
-
-
-
-
 static u8 philips_su1278_tt_inittab[] = {
 	0x01, 0x0f,
 	0x02, 0x30,
@@ -1069,6 +955,20 @@
 			break;
 		}
 		break;
+
+	case 0x1017:		// TT S-1500 PCI
+		budget_ci->budget.dvb_frontend = stv0299_attach(&alps_bsbe1_config, &budget_ci->budget.i2c_adap);
+		if (budget_ci->budget.dvb_frontend) {
+			budget_ci->budget.dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
+			if (lnbp21_init(budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0)) {
+				printk("%s: No LNBP21 found!\n", __FUNCTION__);
+				if (budget_ci->budget.dvb_frontend->ops->release)
+					budget_ci->budget.dvb_frontend->ops->release(budget_ci->budget.dvb_frontend);
+				budget_ci->budget.dvb_frontend = NULL;
+			}
+		}
+
+		break;
 	}
 
 	if (budget_ci->budget.dvb_frontend == NULL) {
@@ -1146,6 +1046,7 @@
 
 static struct saa7146_extension budget_extension;
 
+MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT);
 MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
 MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T	 PCI", BUDGET_TT);
 MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
@@ -1157,6 +1058,7 @@
 	MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010),
 	MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
 	MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
+	MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
 	{
 	 .vendor = 0,
 	 }
diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c
index fc416cf..9fc9185 100644
--- a/drivers/media/dvb/ttpci/budget-patch.c
+++ b/drivers/media/dvb/ttpci/budget-patch.c
@@ -37,6 +37,8 @@
 #include "ves1x93.h"
 #include "tda8083.h"
 
+#include "bsru6.h"
+
 #define budget_patch budget
 
 static struct saa7146_extension budget_extension;
@@ -290,103 +292,6 @@
 	.pll_set = alps_bsrv2_pll_set,
 };
 
-static u8 alps_bsru6_inittab[] = {
-	0x01, 0x15,
-	0x02, 0x00,
-	0x03, 0x00,
-	0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
-	0x05, 0x35,   /* I2CT = 0, SCLT = 1, SDAT = 1 */
-	0x06, 0x40,   /* DAC not used, set to high impendance mode */
-	0x07, 0x00,   /* DAC LSB */
-	0x08, 0x40,   /* DiSEqC off, LNB power on OP2/LOCK pin on */
-	0x09, 0x00,   /* FIFO */
-	0x0c, 0x51,   /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
-	0x0d, 0x82,   /* DC offset compensation = ON, beta_agc1 = 2 */
-	0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
-	0x10, 0x3f,   // AGC2  0x3d
-	0x11, 0x84,
-	0x12, 0xb9,
-	0x15, 0xc9,   // lock detector threshold
-	0x16, 0x00,
-	0x17, 0x00,
-	0x18, 0x00,
-	0x19, 0x00,
-	0x1a, 0x00,
-	0x1f, 0x50,
-	0x20, 0x00,
-	0x21, 0x00,
-	0x22, 0x00,
-	0x23, 0x00,
-	0x28, 0x00,  // out imp: normal  out type: parallel FEC mode:0
-	0x29, 0x1e,  // 1/2 threshold
-	0x2a, 0x14,  // 2/3 threshold
-	0x2b, 0x0f,  // 3/4 threshold
-	0x2c, 0x09,  // 5/6 threshold
-	0x2d, 0x05,  // 7/8 threshold
-	0x2e, 0x01,
-	0x31, 0x1f,  // test all FECs
-	0x32, 0x19,  // viterbi and synchro search
-	0x33, 0xfc,  // rs control
-	0x34, 0x93,  // error control
-	0x0f, 0x52,
-	0xff, 0xff
-};
-
-static int alps_bsru6_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
-{
-	u8 aclk = 0;
-	u8 bclk = 0;
-
-	if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
-	else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
-	else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
-	else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
-	else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
-	else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
-
-	stv0299_writereg (fe, 0x13, aclk);
-	stv0299_writereg (fe, 0x14, bclk);
-	stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
-	stv0299_writereg (fe, 0x20, (ratio >>  8) & 0xff);
-	stv0299_writereg (fe, 0x21, (ratio      ) & 0xf0);
-
-	return 0;
-}
-
-static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
-{
-	u8 data[4];
-	u32 div;
-	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
-
-	if ((params->frequency < 950000) || (params->frequency > 2150000)) return -EINVAL;
-
-	div = (params->frequency + (125 - 1)) / 125; // round correctly
-	data[0] = (div >> 8) & 0x7f;
-	data[1] = div & 0xff;
-	data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
-	data[3] = 0xC4;
-
-	if (params->frequency > 1530000) data[3] = 0xc0;
-
-	if (i2c_transfer(i2c, &msg, 1) != 1) return -EIO;
-	return 0;
-}
-
-static struct stv0299_config alps_bsru6_config = {
-
-	.demod_address = 0x68,
-	.inittab = alps_bsru6_inittab,
-	.mclk = 88000000UL,
-	.invert = 1,
-	.skip_reinit = 0,
-	.lock_output = STV0229_LOCKOUTPUT_1,
-	.volt13_op0_op1 = STV0299_VOLT13_OP1,
-	.min_delay_ms = 100,
-	.set_symbol_rate = alps_bsru6_set_symbol_rate,
-	.pll_set = alps_bsru6_pll_set,
-};
-
 static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
 	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index 238c77b..c23c02d 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -41,6 +41,8 @@
 #include "l64781.h"
 #include "tda8083.h"
 #include "s5h1420.h"
+#include "lnbp21.h"
+#include "bsru6.h"
 
 static void Set22K (struct budget *budget, int state)
 {
@@ -184,64 +186,6 @@
 	return 0;
 }
 
-static int lnbp21_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
-{
-	struct budget* budget = (struct budget*) fe->dvb->priv;
-	u8 buf;
-	struct i2c_msg msg = { .addr = 0x08, .flags = I2C_M_RD, .buf = &buf, .len = sizeof(buf) };
-
-	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
-
-	switch(voltage) {
-	case SEC_VOLTAGE_13:
-		buf = (buf & 0xf7) | 0x04;
-		break;
-
-	case SEC_VOLTAGE_18:
-		buf = (buf & 0xf7) | 0x0c;
-		break;
-
-	case SEC_VOLTAGE_OFF:
-		buf = buf & 0xf0;
-		break;
-	}
-
-	msg.flags = 0;
-	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
-
-	return 0;
-}
-
-static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend* fe, long arg)
-{
-	struct budget* budget = (struct budget*) fe->dvb->priv;
-	u8 buf;
-	struct i2c_msg msg = { .addr = 0x08, .flags = I2C_M_RD, .buf = &buf, .len = sizeof(buf) };
-
-	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
-
-	if (arg) {
-		buf = buf | 0x10;
-	} else {
-		buf = buf & 0xef;
-	}
-
-	msg.flags = 0;
-	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
-
-	return 0;
-}
-
-static int lnbp21_init(struct budget* budget)
-{
-	u8 buf = 0x00;
-	struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = &buf, .len = sizeof(buf) };
-
-	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1)
-		return -EIO;
-	return 0;
-}
-
 static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
 	struct budget* budget = (struct budget*) fe->dvb->priv;
@@ -277,176 +221,6 @@
 	.pll_set = alps_bsrv2_pll_set,
 };
 
-static u8 alps_bsru6_inittab[] = {
-	0x01, 0x15,
-	0x02, 0x00,
-	0x03, 0x00,
-	0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
-	0x05, 0x35,   /* I2CT = 0, SCLT = 1, SDAT = 1 */
-	0x06, 0x40,   /* DAC not used, set to high impendance mode */
-	0x07, 0x00,   /* DAC LSB */
-	0x08, 0x40,   /* DiSEqC off, LNB power on OP2/LOCK pin on */
-	0x09, 0x00,   /* FIFO */
-	0x0c, 0x51,   /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
-	0x0d, 0x82,   /* DC offset compensation = ON, beta_agc1 = 2 */
-	0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
-	0x10, 0x3f,   // AGC2  0x3d
-	0x11, 0x84,
-	0x12, 0xb9,
-	0x15, 0xc9,   // lock detector threshold
-	0x16, 0x00,
-	0x17, 0x00,
-	0x18, 0x00,
-	0x19, 0x00,
-	0x1a, 0x00,
-	0x1f, 0x50,
-	0x20, 0x00,
-	0x21, 0x00,
-	0x22, 0x00,
-	0x23, 0x00,
-	0x28, 0x00,  // out imp: normal  out type: parallel FEC mode:0
-	0x29, 0x1e,  // 1/2 threshold
-	0x2a, 0x14,  // 2/3 threshold
-	0x2b, 0x0f,  // 3/4 threshold
-	0x2c, 0x09,  // 5/6 threshold
-	0x2d, 0x05,  // 7/8 threshold
-	0x2e, 0x01,
-	0x31, 0x1f,  // test all FECs
-	0x32, 0x19,  // viterbi and synchro search
-	0x33, 0xfc,  // rs control
-	0x34, 0x93,  // error control
-	0x0f, 0x52,
-	0xff, 0xff
-};
-
-static int alps_bsru6_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
-{
-	u8 aclk = 0;
-	u8 bclk = 0;
-
-	if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
-	else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
-	else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
-	else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
-	else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
-	else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
-
-	stv0299_writereg (fe, 0x13, aclk);
-	stv0299_writereg (fe, 0x14, bclk);
-	stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
-	stv0299_writereg (fe, 0x20, (ratio >>  8) & 0xff);
-	stv0299_writereg (fe, 0x21, (ratio      ) & 0xf0);
-
-	return 0;
-}
-
-static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
-{
-	u8 data[4];
-	u32 div;
-	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
-
-	if ((params->frequency < 950000) || (params->frequency > 2150000)) return -EINVAL;
-
-	div = (params->frequency + (125 - 1)) / 125; // round correctly
-	data[0] = (div >> 8) & 0x7f;
-	data[1] = div & 0xff;
-	data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
-	data[3] = 0xC4;
-
-	if (params->frequency > 1530000) data[3] = 0xc0;
-
-	if (i2c_transfer(i2c, &msg, 1) != 1) return -EIO;
-	return 0;
-}
-
-static struct stv0299_config alps_bsru6_config = {
-
-	.demod_address = 0x68,
-	.inittab = alps_bsru6_inittab,
-	.mclk = 88000000UL,
-	.invert = 1,
-	.skip_reinit = 0,
-	.lock_output = STV0229_LOCKOUTPUT_1,
-	.volt13_op0_op1 = STV0299_VOLT13_OP1,
-	.min_delay_ms = 100,
-	.set_symbol_rate = alps_bsru6_set_symbol_rate,
-	.pll_set = alps_bsru6_pll_set,
-};
-
-static u8 alps_bsbe1_inittab[] = {
-	0x01, 0x15,
-	0x02, 0x30,
-	0x03, 0x00,
-	0x04, 0x7d,  /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
-	0x05, 0x35,  /* I2CT = 0, SCLT = 1, SDAT = 1 */
-	0x06, 0x40,  /* DAC not used, set to high impendance mode */
-	0x07, 0x00,  /* DAC LSB */
-	0x08, 0x40,  /* DiSEqC off, LNB power on OP2/LOCK pin on */
-	0x09, 0x00,  /* FIFO */
-	0x0c, 0x51,  /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
-	0x0d, 0x82,  /* DC offset compensation = ON, beta_agc1 = 2 */
-	0x0e, 0x23,  /* alpha_tmg = 2, beta_tmg = 3 */
-	0x10, 0x3f,  // AGC2 0x3d
-	0x11, 0x84,
-	0x12, 0xb9,
-	0x15, 0xc9,  // lock detector threshold
-	0x16, 0x00,
-	0x17, 0x00,
-	0x18, 0x00,
-	0x19, 0x00,
-	0x1a, 0x00,
-	0x1f, 0x50,
-	0x20, 0x00,
-	0x21, 0x00,
-	0x22, 0x00,
-	0x23, 0x00,
-	0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
-	0x29, 0x1e, // 1/2 threshold
-	0x2a, 0x14, // 2/3 threshold
-	0x2b, 0x0f, // 3/4 threshold
-	0x2c, 0x09, // 5/6 threshold
-	0x2d, 0x05, // 7/8 threshold
-	0x2e, 0x01,
-	0x31, 0x1f, // test all FECs
-	0x32, 0x19, // viterbi and synchro search
-	0x33, 0xfc, // rs control
-	0x34, 0x93, // error control
-	0x0f, 0x92, // 0x80 = inverse AGC
-	0xff, 0xff
-};
-
-static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
-{
-	int ret;
-	u8 data[4];
-	u32 div;
-	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
-
-	if ((params->frequency < 950000) || (params->frequency > 2150000))
-		return -EINVAL;
-
-	div = (params->frequency + (125 - 1)) / 125; // round correctly
-	data[0] = (div >> 8) & 0x7f;
-	data[1] = div & 0xff;
-	data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
-	data[3] = (params->frequency > 1530000) ? 0xE0 : 0xE4;
-
-	ret = i2c_transfer(i2c, &msg, 1);
-	return (ret != 1) ? -EIO : 0;
-}
-
-static struct stv0299_config alps_bsbe1_config = {
-	.demod_address = 0x68,
-	.inittab = alps_bsbe1_inittab,
-	.mclk = 88000000UL,
-	.invert = 1,
-	.skip_reinit = 0,
-	.min_delay_ms = 100,
-	.set_symbol_rate = alps_bsru6_set_symbol_rate,
-	.pll_set = alps_bsbe1_pll_set,
-};
-
 static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
 	struct budget* budget = (struct budget*) fe->dvb->priv;
@@ -580,20 +354,6 @@
 static void frontend_init(struct budget *budget)
 {
 	switch(budget->dev->pci->subsystem_device) {
-	case 0x1017:
-		// try the ALPS BSBE1 now
-		budget->dvb_frontend = stv0299_attach(&alps_bsbe1_config, &budget->i2c_adap);
-		if (budget->dvb_frontend) {
-			budget->dvb_frontend->ops->set_voltage = lnbp21_set_voltage;
-			budget->dvb_frontend->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
-			budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
-			if (lnbp21_init(budget)) {
-				printk("%s: No LNBP21 found!\n", __FUNCTION__);
-				goto error_out;
-			}
-		}
-
-		break;
 	case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659))
 	case 0x1013:
 		// try the ALPS BSRV2 first of all
@@ -646,9 +406,7 @@
 	case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260))
 		budget->dvb_frontend = s5h1420_attach(&s5h1420_config, &budget->i2c_adap);
 		if (budget->dvb_frontend) {
-			budget->dvb_frontend->ops->set_voltage = lnbp21_set_voltage;
-			budget->dvb_frontend->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
-			if (lnbp21_init(budget)) {
+			if (lnbp21_init(budget->dvb_frontend, &budget->i2c_adap, 0, 0)) {
 				printk("%s: No LNBP21 found!\n", __FUNCTION__);
 				goto error_out;
 			}
@@ -719,7 +477,6 @@
 
 static struct saa7146_extension budget_extension;
 
-MAKE_BUDGET_INFO(ttbs2, "TT-Budget/WinTV-NOVA-S PCI (rev AL/alps bsbe1 lnbp21 frontend)", BUDGET_TT);
 MAKE_BUDGET_INFO(ttbs,	"TT-Budget/WinTV-NOVA-S  PCI",	BUDGET_TT);
 MAKE_BUDGET_INFO(ttbc,	"TT-Budget/WinTV-NOVA-C  PCI",	BUDGET_TT);
 MAKE_BUDGET_INFO(ttbt,	"TT-Budget/WinTV-NOVA-T  PCI",	BUDGET_TT);
@@ -732,7 +489,6 @@
 	MAKE_EXTENSION_PCI(ttbc,  0x13c2, 0x1004),
 	MAKE_EXTENSION_PCI(ttbt,  0x13c2, 0x1005),
 	MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
-	MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
 	MAKE_EXTENSION_PCI(ttbs,  0x13c2, 0x1016),
 	MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60),
 	MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61),
diff --git a/drivers/media/dvb/ttpci/budget.h b/drivers/media/dvb/ttpci/budget.h
index c7bb63c..4ac0f4d 100644
--- a/drivers/media/dvb/ttpci/budget.h
+++ b/drivers/media/dvb/ttpci/budget.h
@@ -10,6 +10,8 @@
 #include "dvb_net.h"
 
 #include <linux/module.h>
+#include <linux/mutex.h>
+
 #include <media/saa7146.h>
 
 extern int budget_debug;
@@ -51,7 +53,7 @@
 	struct dmx_frontend mem_frontend;
 
 	int fe_synced;
-	struct semaphore pid_mutex;
+	struct mutex pid_mutex;
 
 	int ci_present;
 	int video_port;
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index 5a13c47..248fdc7 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -19,7 +19,7 @@
 #include <linux/time.h>
 #include <linux/errno.h>
 #include <linux/jiffies.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #include "dvb_frontend.h"
 #include "dmxdev.h"
@@ -35,7 +35,6 @@
 #include <linux/dvb/dmx.h>
 #include <linux/pci.h>
 
-
 /*
   TTUSB_HWSECTIONS:
     the DSP supports filtering in hardware, however, since the "muxstream"
@@ -83,8 +82,8 @@
 	struct dvb_net dvbnet;
 
 	/* and one for USB access. */
-	struct semaphore semi2c;
-	struct semaphore semusb;
+	struct mutex semi2c;
+	struct mutex semusb;
 
 	struct dvb_adapter adapter;
 	struct usb_device *dev;
@@ -150,7 +149,7 @@
 	printk("\n");
 #endif
 
-	if (down_interruptible(&ttusb->semusb) < 0)
+	if (mutex_lock_interruptible(&ttusb->semusb) < 0)
 		return -EAGAIN;
 
 	err = usb_bulk_msg(ttusb->dev, ttusb->bulk_out_pipe,
@@ -158,13 +157,13 @@
 	if (err != 0) {
 		dprintk("%s: usb_bulk_msg(send) failed, err == %i!\n",
 			__FUNCTION__, err);
-		up(&ttusb->semusb);
+		mutex_unlock(&ttusb->semusb);
 		return err;
 	}
 	if (actual_len != len) {
 		dprintk("%s: only wrote %d of %d bytes\n", __FUNCTION__,
 			actual_len, len);
-		up(&ttusb->semusb);
+		mutex_unlock(&ttusb->semusb);
 		return -1;
 	}
 
@@ -174,7 +173,7 @@
 	if (err != 0) {
 		printk("%s: failed, receive error %d\n", __FUNCTION__,
 		       err);
-		up(&ttusb->semusb);
+		mutex_unlock(&ttusb->semusb);
 		return err;
 	}
 #if DEBUG >= 3
@@ -185,14 +184,14 @@
 	printk("\n");
 #endif
 	if (!needresult)
-		up(&ttusb->semusb);
+		mutex_unlock(&ttusb->semusb);
 	return 0;
 }
 
 static int ttusb_result(struct ttusb *ttusb, u8 * data, int len)
 {
 	memcpy(data, ttusb->last_result, len);
-	up(&ttusb->semusb);
+	mutex_unlock(&ttusb->semusb);
 	return 0;
 }
 
@@ -250,7 +249,7 @@
 	int i = 0;
 	int inc;
 
-	if (down_interruptible(&ttusb->semi2c) < 0)
+	if (mutex_lock_interruptible(&ttusb->semi2c) < 0)
 		return -EAGAIN;
 
 	while (i < num) {
@@ -284,7 +283,7 @@
 		i += inc;
 	}
 
-	up(&ttusb->semi2c);
+	mutex_unlock(&ttusb->semi2c);
 	return i;
 }
 
@@ -689,8 +688,7 @@
 				memcpy(ttusb->muxpack + ttusb->muxpack_ptr,
 				       data, avail);
 				ttusb->muxpack_ptr += avail;
-				if (ttusb->muxpack_ptr > 264)
-					BUG();
+				BUG_ON(ttusb->muxpack_ptr > 264);
 				data += avail;
 				len -= avail;
 				/* determine length */
@@ -1495,8 +1493,11 @@
 	ttusb->dev = udev;
 	ttusb->c = 0;
 	ttusb->mux_state = 0;
-	sema_init(&ttusb->semi2c, 0);
-	sema_init(&ttusb->semusb, 1);
+	mutex_init(&ttusb->semi2c);
+
+	mutex_lock(&ttusb->semi2c);
+
+	mutex_init(&ttusb->semusb);
 
 	ttusb_setup_interfaces(ttusb);
 
@@ -1504,7 +1505,7 @@
 	if (ttusb_init_controller(ttusb))
 		printk("ttusb_init_controller: error\n");
 
-	up(&ttusb->semi2c);
+	mutex_unlock(&ttusb->semi2c);
 
 	dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE);
 	ttusb->adapter.priv = ttusb;
diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
index df83117..44dea32 100644
--- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
@@ -20,7 +20,8 @@
  *
  */
 
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
+
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -115,7 +116,7 @@
 	unsigned int			out_pipe;
 	unsigned int			irq_pipe;
 	enum ttusb_dec_interface	interface;
-	struct semaphore		usb_sem;
+	struct mutex			usb_mutex;
 
 	void			*irq_buffer;
 	struct urb		*irq_urb;
@@ -124,7 +125,7 @@
 	dma_addr_t		iso_dma_handle;
 	struct urb		*iso_urb[ISO_BUF_COUNT];
 	int			iso_stream_count;
-	struct semaphore	iso_sem;
+	struct mutex		iso_mutex;
 
 	u8				packet[MAX_PVA_LENGTH + 4];
 	enum ttusb_dec_packet_type	packet_type;
@@ -273,9 +274,9 @@
 	if (!b)
 		return -ENOMEM;
 
-	if ((result = down_interruptible(&dec->usb_sem))) {
+	if ((result = mutex_lock_interruptible(&dec->usb_mutex))) {
 		kfree(b);
-		printk("%s: Failed to down usb semaphore.\n", __FUNCTION__);
+		printk("%s: Failed to lock usb mutex.\n", __FUNCTION__);
 		return result;
 	}
 
@@ -300,7 +301,7 @@
 	if (result) {
 		printk("%s: command bulk message failed: error %d\n",
 		       __FUNCTION__, result);
-		up(&dec->usb_sem);
+		mutex_unlock(&dec->usb_mutex);
 		kfree(b);
 		return result;
 	}
@@ -311,7 +312,7 @@
 	if (result) {
 		printk("%s: result bulk message failed: error %d\n",
 		       __FUNCTION__, result);
-		up(&dec->usb_sem);
+		mutex_unlock(&dec->usb_mutex);
 		kfree(b);
 		return result;
 	} else {
@@ -327,7 +328,7 @@
 		if (cmd_result && b[3] > 0)
 			memcpy(cmd_result, &b[4], b[3]);
 
-		up(&dec->usb_sem);
+		mutex_unlock(&dec->usb_mutex);
 
 		kfree(b);
 		return 0;
@@ -835,7 +836,7 @@
 
 	dprintk("%s\n", __FUNCTION__);
 
-	if (down_interruptible(&dec->iso_sem))
+	if (mutex_lock_interruptible(&dec->iso_mutex))
 		return;
 
 	dec->iso_stream_count--;
@@ -845,7 +846,7 @@
 			usb_kill_urb(dec->iso_urb[i]);
 	}
 
-	up(&dec->iso_sem);
+	mutex_unlock(&dec->iso_mutex);
 }
 
 /* Setting the interface of the DEC tends to take down the USB communications
@@ -890,7 +891,7 @@
 
 	dprintk("%s\n", __FUNCTION__);
 
-	if (down_interruptible(&dec->iso_sem))
+	if (mutex_lock_interruptible(&dec->iso_mutex))
 		return -EAGAIN;
 
 	if (!dec->iso_stream_count) {
@@ -911,7 +912,7 @@
 					i--;
 				}
 
-				up(&dec->iso_sem);
+				mutex_unlock(&dec->iso_mutex);
 				return result;
 			}
 		}
@@ -919,7 +920,7 @@
 
 	dec->iso_stream_count++;
 
-	up(&dec->iso_sem);
+	mutex_unlock(&dec->iso_mutex);
 
 	return 0;
 }
@@ -1229,8 +1230,8 @@
 {
 	dprintk("%s\n", __FUNCTION__);
 
-	sema_init(&dec->usb_sem, 1);
-	sema_init(&dec->iso_sem, 1);
+	mutex_init(&dec->usb_mutex);
+	mutex_init(&dec->iso_mutex);
 
 	dec->command_pipe = usb_sndbulkpipe(dec->udev, COMMAND_PIPE);
 	dec->result_pipe = usb_rcvbulkpipe(dec->udev, RESULT_PIPE);
diff --git a/drivers/media/radio/miropcm20-rds-core.c b/drivers/media/radio/miropcm20-rds-core.c
index a917a90..b602c73 100644
--- a/drivers/media/radio/miropcm20-rds-core.c
+++ b/drivers/media/radio/miropcm20-rds-core.c
@@ -18,14 +18,15 @@
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
+
 #include <asm/io.h>
 #include "../../../sound/oss/aci.h"
 #include "miropcm20-rds-core.h"
 
 #define DEBUG 0
 
-static struct semaphore aci_rds_sem;
+static struct mutex aci_rds_mutex;
 
 #define RDS_DATASHIFT          2   /* Bit 2 */
 #define RDS_DATAMASK        (1 << RDS_DATASHIFT)
@@ -181,7 +182,7 @@
 {
 	int ret;
 
-	if (down_interruptible(&aci_rds_sem))
+	if (mutex_lock_interruptible(&aci_rds_mutex))
 		return -EINTR;
 
 	rds_write(cmd);
@@ -192,7 +193,7 @@
 	else
 		ret = 0;
 
-	up(&aci_rds_sem);
+	mutex_unlock(&aci_rds_mutex);
 	
 	return ret;
 }
@@ -200,7 +201,7 @@
 
 int __init attach_aci_rds(void)
 {
-	init_MUTEX(&aci_rds_sem);
+	mutex_init(&aci_rds_mutex);
 	return 0;
 }
 
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index 914deab..557fb5c 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -43,7 +43,7 @@
 
 static int io = CONFIG_RADIO_RTRACK_PORT; 
 static int radio_nr = -1;
-static struct semaphore lock;
+static struct mutex lock;
 
 struct rt_device
 {
@@ -83,23 +83,23 @@
 static void rt_mute(struct rt_device *dev)
 {
 	dev->muted = 1;
-	down(&lock);
+	mutex_lock(&lock);
 	outb(0xd0, io);			/* volume steady, off		*/
-	up(&lock);
+	mutex_unlock(&lock);
 }
 
 static int rt_setvol(struct rt_device *dev, int vol)
 {
 	int i;
 
-	down(&lock);
+	mutex_lock(&lock);
 	
 	if(vol == dev->curvol) {	/* requested volume = current */
 		if (dev->muted) {	/* user is unmuting the card  */
 			dev->muted = 0;
 			outb (0xd8, io);	/* enable card */
 		}	
-		up(&lock);
+		mutex_unlock(&lock);
 		return 0;
 	}
 
@@ -108,7 +108,7 @@
 		sleep_delay(2000000);	/* make sure it's totally down	*/
 		outb(0xd0, io);		/* volume steady, off		*/
 		dev->curvol = 0;	/* track the volume state!	*/
-		up(&lock);
+		mutex_unlock(&lock);
 		return 0;
 	}
 
@@ -121,7 +121,7 @@
 			rt_decvol();
 
 	dev->curvol = vol;
-	up(&lock);
+	mutex_unlock(&lock);
 	return 0;
 }
 
@@ -168,7 +168,7 @@
 	freq += 171200;			/* Add 10.7 MHz IF 		*/
 	freq /= 800;			/* Convert to 50 kHz units	*/
 	
-	down(&lock);			/* Stop other ops interfering */
+	mutex_lock(&lock);			/* Stop other ops interfering */
 	 
 	send_0_byte (io, dev);		/*  0: LSB of frequency		*/
 
@@ -196,7 +196,7 @@
 	else
 		outb (0xd8, io);	/* volume steady + sigstr + on */
 		
-	up(&lock);
+	mutex_unlock(&lock);
 
 	return 0;
 }
@@ -337,7 +337,7 @@
 
 	/* Set up the I/O locking */
 	
-	init_MUTEX(&lock);
+	mutex_init(&lock);
 	
  	/* mute card - prevents noisy bootups */
 
diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c
index 523be82..83bdae2 100644
--- a/drivers/media/radio/radio-aztech.c
+++ b/drivers/media/radio/radio-aztech.c
@@ -42,7 +42,7 @@
 static int io = CONFIG_RADIO_AZTECH_PORT; 
 static int radio_nr = -1;
 static int radio_wait_time = 1000;
-static struct semaphore lock;
+static struct mutex lock;
 
 struct az_device
 {
@@ -87,9 +87,9 @@
 
 static int az_setvol(struct az_device *dev, int vol)
 {
-	down(&lock);
+	mutex_lock(&lock);
 	outb (volconvert(vol), io);
-	up(&lock);
+	mutex_unlock(&lock);
 	return 0;
 }
 
@@ -122,7 +122,7 @@
 	frequency += 171200;		/* Add 10.7 MHz IF		*/
 	frequency /= 800;		/* Convert to 50 kHz units	*/
 					
-	down(&lock);
+	mutex_lock(&lock);
 	
 	send_0_byte (dev);		/*  0: LSB of frequency       */
 
@@ -152,7 +152,7 @@
 	udelay (radio_wait_time);
 	outb_p(128+64+volconvert(dev->curvol), io);
 	
-	up(&lock);
+	mutex_unlock(&lock);
 
 	return 0;
 }
@@ -283,7 +283,7 @@
 		return -EBUSY;
 	}
 
-	init_MUTEX(&lock);
+	mutex_init(&lock);
 	aztech_radio.priv=&aztech_unit;
 	
 	if(video_register_device(&aztech_radio, VFL_TYPE_RADIO, radio_nr)==-1)
diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c
index 36c9f5b..39c1d91 100644
--- a/drivers/media/radio/radio-maestro.c
+++ b/drivers/media/radio/radio-maestro.c
@@ -23,10 +23,11 @@
 #include <linux/sched.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <linux/pci.h>
 #include <linux/videodev.h>
 
+
 #define DRIVER_VERSION	"0.05"
 
 #define GPIO_DATA	0x60   /* port offset from ESS_IO_BASE */
@@ -104,7 +105,7 @@
 		muted,	/* VIDEO_AUDIO_MUTE */
 		stereo,	/* VIDEO_TUNER_STEREO_ON */	
 		tuned;	/* signal strength (0 or 0xffff) */
-	struct	semaphore lock;
+	struct mutex lock;
 };
 
 static u32 radio_bits_get(struct radio_device *dev)
@@ -258,9 +259,9 @@
 	struct radio_device *card = video_get_drvdata(dev);
 	int ret;
 
-	down(&card->lock);
+	mutex_lock(&card->lock);
 	ret = video_usercopy(inode, file, cmd, arg, radio_function);
-	up(&card->lock);
+	mutex_unlock(&card->lock);
 
 	return ret;
 }
@@ -311,7 +312,7 @@
 	}
 
 	radio_unit->io = pci_resource_start(pdev, 0) + GPIO_DATA;
-	init_MUTEX(&radio_unit->lock);
+	mutex_init(&radio_unit->lock);
 
 	maestro_radio_inst = video_device_alloc();
 	if (maestro_radio_inst == NULL) {
diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c
index c975ddd..f0bf47b 100644
--- a/drivers/media/radio/radio-maxiradio.c
+++ b/drivers/media/radio/radio-maxiradio.c
@@ -37,7 +37,8 @@
 #include <linux/sched.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
+
 #include <linux/pci.h>
 #include <linux/videodev.h>
 
@@ -101,7 +102,7 @@
 		
 	unsigned long freq;
 	
-	struct  semaphore lock;
+	struct mutex lock;
 } radio_unit = {0, 0, 0, 0, };
 
 
@@ -267,9 +268,9 @@
 	struct radio_device *card=dev->priv;
 	int ret;
 	
-	down(&card->lock);
+	mutex_lock(&card->lock);
 	ret = video_usercopy(inode, file, cmd, arg, radio_function);
-	up(&card->lock);
+	mutex_unlock(&card->lock);
 	return ret;
 }
 
@@ -290,7 +291,7 @@
 	        goto err_out_free_region;
 
 	radio_unit.io = pci_resource_start(pdev, 0);
-	init_MUTEX(&radio_unit.lock);
+	mutex_init(&radio_unit.lock);
 	maxiradio_radio.priv = &radio_unit;
 
 	if(video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr)==-1) {
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index 0229f79..53073b4 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -24,7 +24,7 @@
 #include <linux/isapnp.h>
 #include <asm/io.h>		/* outb, outb_p			*/
 #include <asm/uaccess.h>	/* copy to/from user		*/
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 struct fmi_device
 {
@@ -37,7 +37,7 @@
 static int io = -1; 
 static int radio_nr = -1;
 static struct pnp_dev *dev = NULL;
-static struct semaphore lock;
+static struct mutex lock;
 
 /* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */
 /* It is only useful to give freq in intervall of 800 (=0.05Mhz),
@@ -68,16 +68,16 @@
 
 static inline void fmi_mute(int port)
 {
-	down(&lock);
+	mutex_lock(&lock);
 	outb(0x00, port);
-	up(&lock);
+	mutex_unlock(&lock);
 }
 
 static inline void fmi_unmute(int port)
 {
-	down(&lock);
+	mutex_lock(&lock);
 	outb(0x08, port);
-	up(&lock);
+	mutex_unlock(&lock);
 }
 
 static inline int fmi_setfreq(struct fmi_device *dev)
@@ -85,12 +85,12 @@
 	int myport = dev->port;
 	unsigned long freq = dev->curfreq;
 
-	down(&lock);
+	mutex_lock(&lock);
 
 	outbits(16, RSF16_ENCODE(freq), myport);
 	outbits(8, 0xC0, myport);
 	msleep(143);		/* was schedule_timeout(HZ/7) */
-	up(&lock);
+	mutex_unlock(&lock);
 	if (dev->curvol) fmi_unmute(myport);
 	return 0;
 }
@@ -102,7 +102,7 @@
 	int myport = dev->port;
 
 	
-	down(&lock);
+	mutex_lock(&lock);
 	val = dev->curvol ? 0x08 : 0x00;	/* unmute/mute */
 	outb(val, myport);
 	outb(val | 0x10, myport);
@@ -110,7 +110,7 @@
 	res = (int)inb(myport+1);
 	outb(val, myport);
 	
-	up(&lock);
+	mutex_unlock(&lock);
 	return (res & 2) ? 0 : 0xFFFF;
 }
 
@@ -296,7 +296,7 @@
 	fmi_unit.flags = VIDEO_TUNER_LOW;
 	fmi_radio.priv = &fmi_unit;
 	
-	init_MUTEX(&lock);
+	mutex_init(&lock);
 	
 	if (video_register_device(&fmi_radio, VFL_TYPE_RADIO, radio_nr) == -1) {
 		release_region(io, 2);
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index 099ffb3..bcebd8c 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -19,9 +19,9 @@
 #include <asm/io.h>		/* outb, outb_p			*/
 #include <asm/uaccess.h>	/* copy to/from user		*/
 #include <linux/videodev.h>	/* kernel radio structs		*/
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
-static struct semaphore lock;
+static struct mutex lock;
 
 #undef DEBUG
 //#define DEBUG 1
@@ -238,9 +238,9 @@
 			if (fmr2->mute)
 				v->flags |= VIDEO_AUDIO_MUTE;
 			v->mode=VIDEO_MODE_AUTO;
-			down(&lock);
+			mutex_lock(&lock);
 			v->signal = fmr2_getsigstr(fmr2);
-			up(&lock);
+			mutex_unlock(&lock);
 			return 0;
 		}
 		case VIDIOCSTUNER:
@@ -274,9 +274,9 @@
 			/* set card freq (if not muted) */
 			if (fmr2->curvol && !fmr2->mute)
 			{
-				down(&lock);
+				mutex_lock(&lock);
 				fmr2_setfreq(fmr2);
-				up(&lock);
+				mutex_unlock(&lock);
 			}
 			return 0;
 		}
@@ -318,14 +318,14 @@
 			else
 				printk(KERN_DEBUG "mute\n");
 #endif
-			down(&lock);
+			mutex_lock(&lock);
 			if (fmr2->curvol && !fmr2->mute)
 			{
 				fmr2_setvolume(fmr2);
 				fmr2_setfreq(fmr2);
 			}
 			else fmr2_mute(fmr2->port);
-			up(&lock);
+			mutex_unlock(&lock);
 			return 0;
 		}
 		case VIDIOCGUNIT:
@@ -380,7 +380,7 @@
 	fmr2_unit.card_type = 0;
 	fmr2_radio.priv = &fmr2_unit;
 
-	init_MUTEX(&lock);
+	mutex_init(&lock);
 
 	if (request_region(io, 2, "sf16fmr2"))
 	{
@@ -397,10 +397,10 @@
 	printk(KERN_INFO "SF16FMR2 radio card driver at 0x%x.\n", io);
 	debug_print((KERN_DEBUG "Mute %d Low %d\n",VIDEO_AUDIO_MUTE,VIDEO_TUNER_LOW));
 	/* mute card - prevents noisy bootups */
-	down(&lock);
+	mutex_lock(&lock);
 	fmr2_mute(io);
 	fmr2_product_info(&fmr2_unit);
-	up(&lock);
+	mutex_unlock(&lock);
 	debug_print((KERN_DEBUG "card_type %d\n", fmr2_unit.card_type));
 	return 0;
 }
diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c
index 8ac9a8e..e509558 100644
--- a/drivers/media/radio/radio-typhoon.c
+++ b/drivers/media/radio/radio-typhoon.c
@@ -59,7 +59,7 @@
 	int muted;
 	unsigned long curfreq;
 	unsigned long mutefreq;
-	struct semaphore lock;
+	struct mutex lock;
 };
 
 static void typhoon_setvol_generic(struct typhoon_device *dev, int vol);
@@ -77,12 +77,12 @@
 
 static void typhoon_setvol_generic(struct typhoon_device *dev, int vol)
 {
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 	vol >>= 14;				/* Map 16 bit to 2 bit */
 	vol &= 3;
 	outb_p(vol / 2, dev->iobase);		/* Set the volume, high bit. */
 	outb_p(vol % 2, dev->iobase + 2);	/* Set the volume, low bit. */
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 }
 
 static int typhoon_setfreq_generic(struct typhoon_device *dev,
@@ -102,7 +102,7 @@
 	 *
 	 */
 
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 	x = frequency / 160;
 	outval = (x * x + 2500) / 5000;
 	outval = (outval * x + 5000) / 10000;
@@ -112,7 +112,7 @@
 	outb_p((outval >> 8) & 0x01, dev->iobase + 4);
 	outb_p(outval >> 9, dev->iobase + 6);
 	outb_p(outval & 0xff, dev->iobase + 8);
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 
 	return 0;
 }
@@ -337,7 +337,7 @@
 #endif /* MODULE */
 
 	printk(KERN_INFO BANNER);
-	init_MUTEX(&typhoon_unit.lock);
+	mutex_init(&typhoon_unit.lock);
 	io = typhoon_unit.iobase;
 	if (!request_region(io, 8, "typhoon")) {
 		printk(KERN_ERR "radio-typhoon: port 0x%x already in use\n",
diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c
index d590e80..7bf1a42 100644
--- a/drivers/media/radio/radio-zoltrix.c
+++ b/drivers/media/radio/radio-zoltrix.c
@@ -48,7 +48,7 @@
 	unsigned long curfreq;
 	int muted;
 	unsigned int stereo;
-	struct semaphore lock;
+	struct mutex lock;
 };
 
 static int zol_setvol(struct zol_device *dev, int vol)
@@ -57,30 +57,30 @@
 	if (dev->muted)
 		return 0;
 
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 	if (vol == 0) {
 		outb(0, io);
 		outb(0, io);
 		inb(io + 3);    /* Zoltrix needs to be read to confirm */
-		up(&dev->lock);
+		mutex_unlock(&dev->lock);
 		return 0;
 	}
 
 	outb(dev->curvol-1, io);
 	msleep(10);
 	inb(io + 2);
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 	return 0;
 }
 
 static void zol_mute(struct zol_device *dev)
 {
 	dev->muted = 1;
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 	outb(0, io);
 	outb(0, io);
 	inb(io + 3);            /* Zoltrix needs to be read to confirm */
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 }
 
 static void zol_unmute(struct zol_device *dev)
@@ -104,7 +104,7 @@
 	bitmask = 0xc480402c10080000ull;
 	i = 45;
 
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 	
 	outb(0, io);
 	outb(0, io);
@@ -149,7 +149,7 @@
 		udelay(1000);
 	}
 	
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 	
 	if(!dev->muted)
 	{
@@ -164,7 +164,7 @@
 {
 	int a, b;
 
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 	outb(0x00, io);         /* This stuff I found to do nothing */
 	outb(dev->curvol, io);
 	msleep(20);
@@ -173,7 +173,7 @@
 	msleep(10);
 	b = inb(io);
 
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 	
 	if (a != b)
 		return (0);
@@ -188,7 +188,7 @@
 {
 	int x1, x2;
 
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 	
 	outb(0x00, io);
 	outb(dev->curvol, io);
@@ -198,7 +198,7 @@
 	msleep(10);
 	x2 = inb(io);
 
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 	
 	if ((x1 == x2) && (x1 == 0xcf))
 		return 1;
@@ -350,7 +350,7 @@
 	}
 	printk(KERN_INFO "Zoltrix Radio Plus card driver.\n");
 
-	init_MUTEX(&zoltrix_unit.lock);
+	mutex_init(&zoltrix_unit.lock);
 	
 	/* mute card - prevents noisy bootups */
 
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index d82c8a3..c622a4d 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -26,6 +26,7 @@
 	select VIDEO_IR
 	select VIDEO_TUNER
 	select VIDEO_TVEEPROM
+	select VIDEO_MSP3400
 	---help---
 	  Support for BT848 based frame grabber/overlay boards. This includes
 	  the Miro, Hauppauge and STB boards. Please read the material in
@@ -142,6 +143,8 @@
 	  otherwise say N. This will not work with the Creative Webcam III.
 	  It is also available as a module (cpia_usb).
 
+source "drivers/media/video/cpia2/Kconfig"
+
 config VIDEO_SAA5246A
 	tristate "SAA5246A, SAA5281 Teletext processor"
 	depends on VIDEO_DEV && I2C
@@ -339,18 +342,53 @@
 	  Say Y here to use the Renesas M64278E-800 camera module,
 	  which supports VGA(640x480 pixcels) size of images.
 
-config VIDEO_AUDIO_DECODER
-	tristate "Add support for additional audio chipsets"
-	depends on VIDEO_DEV && I2C && EXPERIMENTAL
+config VIDEO_MSP3400
+	tristate "Micronas MSP34xx audio decoders"
+	depends on VIDEO_DEV && I2C
 	---help---
-	  Say Y here to compile drivers for WM8775 and CS53L32A audio
-	  decoders.
+	  Support for the Micronas MSP34xx series of audio decoders.
 
-config VIDEO_DECODER
-	tristate "Add support for additional video chipsets"
+	  To compile this driver as a module, choose M here: the
+	  module will be called msp3400
+
+config VIDEO_CS53L32A
+	tristate "Cirrus Logic CS53L32A audio ADC"
 	depends on VIDEO_DEV && I2C && EXPERIMENTAL
 	---help---
-	  Say Y here to compile drivers for SAA7115, SAA7127 and CX25840
-	  video decoders.
+	  Support for the Cirrus Logic CS53L32A low voltage
+	  stereo A/D converter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cs53l32a
+
+config VIDEO_WM8775
+	tristate "Wolfson Microelectronics WM8775 audio ADC"
+	depends on VIDEO_DEV && I2C && EXPERIMENTAL
+	---help---
+	  Support for the Wolfson Microelectronics WM8775
+	  high performance stereo A/D Converter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called wm8775
+
+source "drivers/media/video/cx25840/Kconfig"
+
+config VIDEO_SAA711X
+	tristate "Philips SAA7113/4/5 video decoders"
+	depends on VIDEO_DEV && I2C && EXPERIMENTAL
+	---help---
+	  Support for the Philips SAA7113/4/5 video decoders.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called saa7115
+
+config VIDEO_SAA7127
+	tristate "Philips SAA7127/9 digital video encoders"
+	depends on VIDEO_DEV && I2C && EXPERIMENTAL
+	---help---
+	  Support for the Philips SAA7127/9 digital video encoders.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called saa7127
 
 endmenu
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index faf7283..f2bd4c0 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -15,7 +15,7 @@
 
 obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o compat_ioctl32.o
 
-obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \
+obj-$(CONFIG_VIDEO_BT848) += bttv.o tvaudio.o \
 	tda7432.o tda9875.o ir-kbd-i2c.o
 obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
 
@@ -44,10 +44,13 @@
 obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/
 obj-$(CONFIG_VIDEO_CX88) += cx88/
 obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
-obj-$(CONFIG_VIDEO_EM28XX) += saa711x.o tvp5150.o
-obj-$(CONFIG_VIDEO_AUDIO_DECODER) += wm8775.o cs53l32a.o
+obj-$(CONFIG_VIDEO_EM28XX) += tvp5150.o
+obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
+obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
+obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
 obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
-obj-$(CONFIG_VIDEO_MXB) += saa7111.o tuner.o tda9840.o tea6415c.o tea6420.o mxb.o
+obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
+obj-$(CONFIG_VIDEO_MXB) += saa7111.o tda9840.o tea6415c.o tea6420.o mxb.o
 obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
 obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o
 obj-$(CONFIG_VIDEO_DPC) += saa7111.o dpc7146.o
@@ -61,6 +64,8 @@
 
 obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
 
-obj-$(CONFIG_VIDEO_DECODER)     += saa7115.o cx25840/ saa7127.o
+obj-$(CONFIG_VIDEO_CX25840) += cx25840/
+obj-$(CONFIG_VIDEO_SAA711X) += saa7115.o
+obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o
 
 EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core
diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c
index 994b75f..c586f64 100644
--- a/drivers/media/video/arv.c
+++ b/drivers/media/video/arv.c
@@ -31,8 +31,8 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/videodev.h>
+#include <linux/mutex.h>
 
-#include <asm/semaphore.h>
 #include <asm/uaccess.h>
 #include <asm/m32r.h>
 #include <asm/io.h>
@@ -117,7 +117,7 @@
 	int width, height;
 	int frame_bytes, line_bytes;
 	wait_queue_head_t wait;
-	struct semaphore lock;
+	struct mutex lock;
 };
 
 static int video_nr = -1;	/* video device number (first free) */
@@ -288,7 +288,7 @@
 	if (ar->mode == AR_MODE_NORMAL)
 		arvcr1 |= ARVCR1_NORMAL;
 
-	down(&ar->lock);
+	mutex_lock(&ar->lock);
 
 #if USE_INT
 	local_irq_save(flags);
@@ -392,7 +392,7 @@
 	}
 	DEBUG(1, "ret = %d\n", ret);
 out_up:
-	up(&ar->lock);
+	mutex_unlock(&ar->lock);
 	return ret;
 }
 
@@ -456,7 +456,7 @@
 		    (w->width != AR_WIDTH_QVGA || w->height != AR_HEIGHT_QVGA))
 				return -EINVAL;
 
-		down(&ar->lock);
+		mutex_lock(&ar->lock);
 		ar->width = w->width;
 		ar->height = w->height;
 		if (ar->width == AR_WIDTH_VGA) {
@@ -473,7 +473,7 @@
 			ar->line_bytes = AR_LINE_BYTES_QVGA;
 			ar->mode = AR_MODE_INTERLACE;
 		}
-		up(&ar->lock);
+		mutex_unlock(&ar->lock);
 		return 0;
 	}
 	case VIDIOCGFBUF:
@@ -734,7 +734,7 @@
 void ar_release(struct video_device *vfd)
 {
 	struct ar_device *ar = vfd->priv;
-	down(&ar->lock);
+	mutex_lock(&ar->lock);
 	video_device_release(vfd);
 }
 
@@ -824,7 +824,7 @@
 		ar->line_bytes	= AR_LINE_BYTES_QVGA;
 		ar->mode	= AR_MODE_INTERLACE;
 	}
-	init_MUTEX(&ar->lock);
+	mutex_init(&ar->lock);
 	init_waitqueue_head(&ar->wait);
 
 #if USE_INT
diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c
index 9749d6e..abfa6ad 100644
--- a/drivers/media/video/bttv-cards.c
+++ b/drivers/media/video/bttv-cards.c
@@ -137,6 +137,8 @@
 MODULE_PARM_DESC(pll,"specify installed crystal (0=none, 28=28 MHz, 35=35 MHz)");
 MODULE_PARM_DESC(tuner,"specify installed tuner type");
 MODULE_PARM_DESC(autoload,"automatically load i2c modules like tuner.o, default is 1 (yes)");
+MODULE_PARM_DESC(no_overlay,"allow override overlay default (0 disables, 1 enables)"
+		" [some VIA/SIS chipsets are known to have problem with overlay]");
 
 /* ----------------------------------------------------------------------- */
 /* list of card IDs for bt878+ cards                                       */
@@ -275,7 +277,6 @@
 	{ 0x03116000, BTTV_BOARD_SENSORAY311,   "Sensoray 311" },
 	{ 0x00790e11, BTTV_BOARD_WINDVR,        "Canopus WinDVR PCI" },
 	{ 0xa0fca1a0, BTTV_BOARD_ZOLTRIX,       "Face to Face Tvmax" },
-	{ 0x20007063, BTTV_BOARD_PC_HDTV,       "pcHDTV HD-2000 TV"},
 	{ 0x82b2aa6a, BTTV_BOARD_SIMUS_GVC1100, "SIMUS GVC1100" },
 	{ 0x146caa0c, BTTV_BOARD_PV951,         "ituner spectra8" },
 	{ 0x200a1295, BTTV_BOARD_PXC200,        "ImageNation PXC200A" },
@@ -297,13 +298,14 @@
 	* { 0x13eb0070, BTTV_BOARD_HAUPPAUGE_IMPACTVCB,  "Hauppauge ImpactVCB" }, */
 
 	/* DVB cards (using pci function .1 for mpeg data xfer) */
-	{ 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" },
-	{ 0x07611461, BTTV_BOARD_AVDVBT_761,    "AverMedia AverTV DVB-T 761" },
 	{ 0x001c11bd, BTTV_BOARD_PINNACLESAT,   "Pinnacle PCTV Sat" },
+	{ 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" },
+	{ 0x20007063, BTTV_BOARD_PC_HDTV,       "pcHDTV HD-2000 TV"},
 	{ 0x002611bd, BTTV_BOARD_TWINHAN_DST,   "Pinnacle PCTV SAT CI" },
 	{ 0x00011822, BTTV_BOARD_TWINHAN_DST,   "Twinhan VisionPlus DVB" },
 	{ 0xfc00270f, BTTV_BOARD_TWINHAN_DST,   "ChainTech digitop DST-1000 DVB-S" },
 	{ 0x07711461, BTTV_BOARD_AVDVBT_771,    "AVermedia AverTV DVB-T 771" },
+	{ 0x07611461, BTTV_BOARD_AVDVBT_761,    "AverMedia AverTV DVB-T 761" },
 	{ 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE,    "DViCO FusionHDTV DVB-T Lite" },
 	{ 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE,    "DViCO FusionHDTV 5 Lite" },
 
@@ -4944,12 +4946,14 @@
 	if (vsfx)
 		printk(KERN_INFO "bttv: Host bridge needs VSFX enabled.\n");
 	if (pcipci_fail) {
-		printk(KERN_WARNING "bttv: BT848 and your chipset may not work together.\n");
+		printk(KERN_INFO "bttv: bttv and your chipset may not work "
+							"together.\n");
 		if (!no_overlay) {
-			printk(KERN_WARNING "bttv: overlay will be disabled.\n");
+			printk(KERN_INFO "bttv: overlay will be disabled.\n");
 			no_overlay = 1;
 		} else {
-			printk(KERN_WARNING "bttv: overlay forced. Use this option at your own risk.\n");
+			printk(KERN_INFO "bttv: overlay forced. Use this "
+						"option at your own risk.\n");
 		}
 	}
 	if (UNSET != latency)
diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c
index 578b200..c0415d6 100644
--- a/drivers/media/video/bttv-driver.c
+++ b/drivers/media/video/bttv-driver.c
@@ -1965,7 +1965,7 @@
 		BUG();
 	}
 
-	down(&fh->cap.lock);
+	mutex_lock(&fh->cap.lock);
 		kfree(fh->ov.clips);
 	fh->ov.clips    = clips;
 	fh->ov.nclips   = n;
@@ -1986,7 +1986,7 @@
 		bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
 		retval = bttv_switch_overlay(btv,fh,new);
 	}
-	up(&fh->cap.lock);
+	mutex_unlock(&fh->cap.lock);
 	return retval;
 }
 
@@ -2166,7 +2166,7 @@
 		fmt = format_by_fourcc(f->fmt.pix.pixelformat);
 
 		/* update our state informations */
-		down(&fh->cap.lock);
+		mutex_lock(&fh->cap.lock);
 		fh->fmt              = fmt;
 		fh->cap.field        = f->fmt.pix.field;
 		fh->cap.last         = V4L2_FIELD_NONE;
@@ -2175,7 +2175,7 @@
 		btv->init.fmt        = fmt;
 		btv->init.width      = f->fmt.pix.width;
 		btv->init.height     = f->fmt.pix.height;
-		up(&fh->cap.lock);
+		mutex_unlock(&fh->cap.lock);
 
 		return 0;
 	}
@@ -2282,7 +2282,7 @@
 		fmt = format_by_palette(pic->palette);
 		if (NULL == fmt)
 			return -EINVAL;
-		down(&fh->cap.lock);
+		mutex_lock(&fh->cap.lock);
 		if (fmt->depth != pic->depth) {
 			retval = -EINVAL;
 			goto fh_unlock_and_return;
@@ -2313,7 +2313,7 @@
 		bt848_contrast(btv,pic->contrast);
 		bt848_hue(btv,pic->hue);
 		bt848_sat(btv,pic->colour);
-		up(&fh->cap.lock);
+		mutex_unlock(&fh->cap.lock);
 		return 0;
 	}
 
@@ -2379,7 +2379,7 @@
 			return -EPERM;
 		end = (unsigned long)fbuf->base +
 			fbuf->height * fbuf->bytesperline;
-		down(&fh->cap.lock);
+		mutex_lock(&fh->cap.lock);
 		retval = -EINVAL;
 
 		switch (fbuf->depth) {
@@ -2417,7 +2417,7 @@
 			btv->fbuf.fmt.bytesperline = fbuf->bytesperline;
 		else
 			btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fbuf->depth/8;
-		up(&fh->cap.lock);
+		mutex_unlock(&fh->cap.lock);
 		return 0;
 	}
 
@@ -2440,7 +2440,7 @@
 		if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY))
 			return -EBUSY;
 
-		down(&fh->cap.lock);
+		mutex_lock(&fh->cap.lock);
 		if (*on) {
 			fh->ov.tvnorm = btv->tvnorm;
 			new = videobuf_alloc(sizeof(*new));
@@ -2451,7 +2451,7 @@
 
 		/* switch over */
 		retval = bttv_switch_overlay(btv,fh,new);
-		up(&fh->cap.lock);
+		mutex_unlock(&fh->cap.lock);
 		return retval;
 	}
 
@@ -2460,7 +2460,7 @@
 		struct video_mbuf *mbuf = arg;
 		unsigned int i;
 
-		down(&fh->cap.lock);
+		mutex_lock(&fh->cap.lock);
 		retval = videobuf_mmap_setup(&fh->cap,gbuffers,gbufsize,
 					     V4L2_MEMORY_MMAP);
 		if (retval < 0)
@@ -2470,7 +2470,7 @@
 		mbuf->size   = gbuffers * gbufsize;
 		for (i = 0; i < gbuffers; i++)
 			mbuf->offsets[i] = i * gbufsize;
-		up(&fh->cap.lock);
+		mutex_unlock(&fh->cap.lock);
 		return 0;
 	}
 	case VIDIOCMCAPTURE:
@@ -2482,7 +2482,7 @@
 		if (vm->frame >= VIDEO_MAX_FRAME)
 			return -EINVAL;
 
-		down(&fh->cap.lock);
+		mutex_lock(&fh->cap.lock);
 		retval = -EINVAL;
 		buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame];
 		if (NULL == buf)
@@ -2504,7 +2504,7 @@
 		spin_lock_irqsave(&btv->s_lock,flags);
 		buffer_queue(&fh->cap,&buf->vb);
 		spin_unlock_irqrestore(&btv->s_lock,flags);
-		up(&fh->cap.lock);
+		mutex_unlock(&fh->cap.lock);
 		return 0;
 	}
 	case VIDIOCSYNC:
@@ -2515,7 +2515,7 @@
 		if (*frame >= VIDEO_MAX_FRAME)
 			return -EINVAL;
 
-		down(&fh->cap.lock);
+		mutex_lock(&fh->cap.lock);
 		retval = -EINVAL;
 		buf = (struct bttv_buffer *)fh->cap.bufs[*frame];
 		if (NULL == buf)
@@ -2535,7 +2535,7 @@
 			retval = -EINVAL;
 			break;
 		}
-		up(&fh->cap.lock);
+		mutex_unlock(&fh->cap.lock);
 		return retval;
 	}
 
@@ -2719,7 +2719,7 @@
 		if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
 			return -EINVAL;
 
-		down(&fh->cap.lock);
+		mutex_lock(&fh->cap.lock);
 		retval = -EINVAL;
 		if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
 			if (fb->fmt.width > bttv_tvnorms[btv->tvnorm].swidth)
@@ -2759,7 +2759,7 @@
 				retval = bttv_switch_overlay(btv,fh,new);
 			}
 		}
-		up(&fh->cap.lock);
+		mutex_unlock(&fh->cap.lock);
 		return retval;
 	}
 
@@ -2890,7 +2890,7 @@
 	return 0;
 
  fh_unlock_and_return:
-	up(&fh->cap.lock);
+	mutex_unlock(&fh->cap.lock);
 	return retval;
 }
 
@@ -2957,16 +2957,16 @@
 		buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
 	} else {
 		/* read() capture */
-		down(&fh->cap.lock);
+		mutex_lock(&fh->cap.lock);
 		if (NULL == fh->cap.read_buf) {
 			/* need to capture a new frame */
 			if (locked_btres(fh->btv,RESOURCE_VIDEO)) {
-				up(&fh->cap.lock);
+				mutex_unlock(&fh->cap.lock);
 				return POLLERR;
 			}
 			fh->cap.read_buf = videobuf_alloc(fh->cap.msize);
 			if (NULL == fh->cap.read_buf) {
-				up(&fh->cap.lock);
+				mutex_unlock(&fh->cap.lock);
 				return POLLERR;
 			}
 			fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR;
@@ -2974,13 +2974,13 @@
 			if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,field)) {
 				kfree (fh->cap.read_buf);
 				fh->cap.read_buf = NULL;
-				up(&fh->cap.lock);
+				mutex_unlock(&fh->cap.lock);
 				return POLLERR;
 			}
 			fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
 			fh->cap.read_off = 0;
 		}
-		up(&fh->cap.lock);
+		mutex_unlock(&fh->cap.lock);
 		buf = (struct bttv_buffer*)fh->cap.read_buf;
 	}
 
diff --git a/drivers/media/video/bttv-input.c b/drivers/media/video/bttv-input.c
index 221b36e..69efa0e 100644
--- a/drivers/media/video/bttv-input.c
+++ b/drivers/media/video/bttv-input.c
@@ -28,251 +28,6 @@
 #include "bttv.h"
 #include "bttvp.h"
 
-/* ---------------------------------------------------------------------- */
-
-static IR_KEYTAB_TYPE ir_codes_avermedia[IR_KEYTAB_SIZE] = {
-	[ 34 ] = KEY_KP0,
-	[ 40 ] = KEY_KP1,
-	[ 24 ] = KEY_KP2,
-	[ 56 ] = KEY_KP3,
-	[ 36 ] = KEY_KP4,
-	[ 20 ] = KEY_KP5,
-	[ 52 ] = KEY_KP6,
-	[ 44 ] = KEY_KP7,
-	[ 28 ] = KEY_KP8,
-	[ 60 ] = KEY_KP9,
-
-	[ 48 ] = KEY_EJECTCD,     // Unmarked on my controller
-	[  0 ] = KEY_POWER,
-	[ 18 ] = BTN_LEFT,        // DISPLAY/L
-	[ 50 ] = BTN_RIGHT,       // LOOP/R
-	[ 10 ] = KEY_MUTE,
-	[ 38 ] = KEY_RECORD,
-	[ 22 ] = KEY_PAUSE,
-	[ 54 ] = KEY_STOP,
-	[ 30 ] = KEY_VOLUMEDOWN,
-	[ 62 ] = KEY_VOLUMEUP,
-
-	[ 32 ] = KEY_TUNER,       // TV/FM
-	[ 16 ] = KEY_CD,
-	[  8 ] = KEY_VIDEO,
-	[  4 ] = KEY_AUDIO,
-	[ 12 ] = KEY_ZOOM,        // full screen
-	[  2 ] = KEY_INFO,        // preview
-	[ 42 ] = KEY_SEARCH,      // autoscan
-	[ 26 ] = KEY_STOP,        // freeze
-	[ 58 ] = KEY_RECORD,      // capture
-	[  6 ] = KEY_PLAY,        // unmarked
-	[ 46 ] = KEY_RED,         // unmarked
-	[ 14 ] = KEY_GREEN,       // unmarked
-
-	[ 33 ] = KEY_YELLOW,      // unmarked
-	[ 17 ] = KEY_CHANNELDOWN,
-	[ 49 ] = KEY_CHANNELUP,
-	[  1 ] = KEY_BLUE,        // unmarked
-};
-
-/* Matt Jesson <dvb@jesson.eclipse.co.uk */
-static IR_KEYTAB_TYPE ir_codes_avermedia_dvbt[IR_KEYTAB_SIZE] = {
-	[ 0x28 ] = KEY_KP0,         //'0' / 'enter'
-	[ 0x22 ] = KEY_KP1,         //'1'
-	[ 0x12 ] = KEY_KP2,         //'2' / 'up arrow'
-	[ 0x32 ] = KEY_KP3,         //'3'
-	[ 0x24 ] = KEY_KP4,         //'4' / 'left arrow'
-	[ 0x14 ] = KEY_KP5,         //'5'
-	[ 0x34 ] = KEY_KP6,         //'6' / 'right arrow'
-	[ 0x26 ] = KEY_KP7,         //'7'
-	[ 0x16 ] = KEY_KP8,         //'8' / 'down arrow'
-	[ 0x36 ] = KEY_KP9,         //'9'
-
-	[ 0x20 ] = KEY_LIST,        // 'source'
-	[ 0x10 ] = KEY_TEXT,        // 'teletext'
-	[ 0x00 ] = KEY_POWER,       // 'power'
-	[ 0x04 ] = KEY_AUDIO,       // 'audio'
-	[ 0x06 ] = KEY_ZOOM,        // 'full screen'
-	[ 0x18 ] = KEY_VIDEO,       // 'display'
-	[ 0x38 ] = KEY_SEARCH,      // 'loop'
-	[ 0x08 ] = KEY_INFO,        // 'preview'
-	[ 0x2a ] = KEY_REWIND,      // 'backward <<'
-	[ 0x1a ] = KEY_FASTFORWARD, // 'forward >>'
-	[ 0x3a ] = KEY_RECORD,      // 'capture'
-	[ 0x0a ] = KEY_MUTE,        // 'mute'
-	[ 0x2c ] = KEY_RECORD,      // 'record'
-	[ 0x1c ] = KEY_PAUSE,       // 'pause'
-	[ 0x3c ] = KEY_STOP,        // 'stop'
-	[ 0x0c ] = KEY_PLAY,        // 'play'
-	[ 0x2e ] = KEY_RED,         // 'red'
-	[ 0x01 ] = KEY_BLUE,        // 'blue' / 'cancel'
-	[ 0x0e ] = KEY_YELLOW,      // 'yellow' / 'ok'
-	[ 0x21 ] = KEY_GREEN,       // 'green'
-	[ 0x11 ] = KEY_CHANNELDOWN, // 'channel -'
-	[ 0x31 ] = KEY_CHANNELUP,   // 'channel +'
-	[ 0x1e ] = KEY_VOLUMEDOWN,  // 'volume -'
-	[ 0x3e ] = KEY_VOLUMEUP,    // 'volume +'
-};
-
-/* Attila Kondoros <attila.kondoros@chello.hu> */
-static IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE] = {
-
-	[  1 ] = KEY_KP1,
-	[  2 ] = KEY_KP2,
-	[  3 ] = KEY_KP3,
-	[  4 ] = KEY_KP4,
-	[  5 ] = KEY_KP5,
-	[  6 ] = KEY_KP6,
-	[  7 ] = KEY_KP7,
-	[  8 ] = KEY_KP8,
-	[  9 ] = KEY_KP9,
-	[  0 ] = KEY_KP0,
-	[ 23 ] = KEY_LAST,        // +100
-	[ 10 ] = KEY_LIST,        // recall
-
-
-	[ 28 ] = KEY_TUNER,       // TV/FM
-	[ 21 ] = KEY_SEARCH,      // scan
-	[ 18 ] = KEY_POWER,       // power
-	[ 31 ] = KEY_VOLUMEDOWN,  // vol up
-	[ 27 ] = KEY_VOLUMEUP,    // vol down
-	[ 30 ] = KEY_CHANNELDOWN, // chn up
-	[ 26 ] = KEY_CHANNELUP,   // chn down
-
-	[ 17 ] = KEY_VIDEO,       // video
-	[ 15 ] = KEY_ZOOM,        // full screen
-	[ 19 ] = KEY_MUTE,        // mute/unmute
-	[ 16 ] = KEY_TEXT,        // min
-
-	[ 13 ] = KEY_STOP,        // freeze
-	[ 14 ] = KEY_RECORD,      // record
-	[ 29 ] = KEY_PLAYPAUSE,   // stop
-	[ 25 ] = KEY_PLAY,        // play
-
-	[ 22 ] = KEY_GOTO,        // osd
-	[ 20 ] = KEY_REFRESH,     // default
-	[ 12 ] = KEY_KPPLUS,      // fine tune >>>>
-	[ 24 ] = KEY_KPMINUS      // fine tune <<<<
-};
-
-/* ---------------------------------------------------------------------- */
-
-static IR_KEYTAB_TYPE ir_codes_conceptronic[IR_KEYTAB_SIZE] = {
-
-	[ 30 ] = KEY_POWER,       // power
-	[ 7  ] = KEY_MEDIA,       // source
-	[ 28 ] = KEY_SEARCH,      // scan
-
-/* FIXME: duplicate keycodes?
- *
- * These four keys seem to share the same GPIO as CH+, CH-, <<< and >>>
- * The GPIO values are
- * 6397fb for both "Scan <" and "CH -",
- * 639ffb for "Scan >" and "CH+",
- * 6384fb for "Tune <" and "<<<",
- * 638cfb for "Tune >" and ">>>", regardless of the mask.
- *
- *	[ 23 ] = KEY_BACK,        // fm scan <<
- *	[ 31 ] = KEY_FORWARD,     // fm scan >>
- *
- *	[ 4  ] = KEY_LEFT,        // fm tuning <
- *	[ 12 ] = KEY_RIGHT,       // fm tuning >
- *
- * For now, these four keys are disabled. Pressing them will generate
- * the CH+/CH-/<<</>>> events
- */
-
-	[ 3  ] = KEY_TUNER,       // TV/FM
-
-	[ 0  ] = KEY_RECORD,
-	[ 8  ] = KEY_STOP,
-	[ 17 ] = KEY_PLAY,
-
-	[ 26 ] = KEY_PLAYPAUSE,   // freeze
-	[ 25 ] = KEY_ZOOM,        // zoom
-	[ 15 ] = KEY_TEXT,        // min
-
-	[ 1  ] = KEY_KP1,
-	[ 11 ] = KEY_KP2,
-	[ 27 ] = KEY_KP3,
-	[ 5  ] = KEY_KP4,
-	[ 9  ] = KEY_KP5,
-	[ 21 ] = KEY_KP6,
-	[ 6  ] = KEY_KP7,
-	[ 10 ] = KEY_KP8,
-	[ 18 ] = KEY_KP9,
-	[ 2  ] = KEY_KP0,
-	[ 16 ] = KEY_LAST,        // +100
-	[ 19 ] = KEY_LIST,        // recall
-
-	[ 31 ] = KEY_CHANNELUP,   // chn down
-	[ 23 ] = KEY_CHANNELDOWN, // chn up
-	[ 22 ] = KEY_VOLUMEUP,    // vol down
-	[ 20 ] = KEY_VOLUMEDOWN,  // vol up
-
-	[ 4  ] = KEY_KPMINUS,     // <<<
-	[ 14 ] = KEY_SETUP,       // function
-	[ 12 ] = KEY_KPPLUS,      // >>>
-
-	[ 13 ] = KEY_GOTO,        // mts
-	[ 29 ] = KEY_REFRESH,     // reset
-	[ 24 ] = KEY_MUTE         // mute/unmute
-};
-
-static IR_KEYTAB_TYPE ir_codes_nebula[IR_KEYTAB_SIZE] = {
-	[0x00] = KEY_KP0,
-	[0x01] = KEY_KP1,
-	[0x02] = KEY_KP2,
-	[0x03] = KEY_KP3,
-	[0x04] = KEY_KP4,
-	[0x05] = KEY_KP5,
-	[0x06] = KEY_KP6,
-	[0x07] = KEY_KP7,
-	[0x08] = KEY_KP8,
-	[0x09] = KEY_KP9,
-	[0x0a] = KEY_TV,
-	[0x0b] = KEY_AUX,
-	[0x0c] = KEY_DVD,
-	[0x0d] = KEY_POWER,
-	[0x0e] = KEY_MHP,	/* labelled 'Picture' */
-	[0x0f] = KEY_AUDIO,
-	[0x10] = KEY_INFO,
-	[0x11] = KEY_F13,	/* 16:9 */
-	[0x12] = KEY_F14,	/* 14:9 */
-	[0x13] = KEY_EPG,
-	[0x14] = KEY_EXIT,
-	[0x15] = KEY_MENU,
-	[0x16] = KEY_UP,
-	[0x17] = KEY_DOWN,
-	[0x18] = KEY_LEFT,
-	[0x19] = KEY_RIGHT,
-	[0x1a] = KEY_ENTER,
-	[0x1b] = KEY_CHANNELUP,
-	[0x1c] = KEY_CHANNELDOWN,
-	[0x1d] = KEY_VOLUMEUP,
-	[0x1e] = KEY_VOLUMEDOWN,
-	[0x1f] = KEY_RED,
-	[0x20] = KEY_GREEN,
-	[0x21] = KEY_YELLOW,
-	[0x22] = KEY_BLUE,
-	[0x23] = KEY_SUBTITLE,
-	[0x24] = KEY_F15,	/* AD */
-	[0x25] = KEY_TEXT,
-	[0x26] = KEY_MUTE,
-	[0x27] = KEY_REWIND,
-	[0x28] = KEY_STOP,
-	[0x29] = KEY_PLAY,
-	[0x2a] = KEY_FASTFORWARD,
-	[0x2b] = KEY_F16,	/* chapter */
-	[0x2c] = KEY_PAUSE,
-	[0x2d] = KEY_PLAY,
-	[0x2e] = KEY_RECORD,
-	[0x2f] = KEY_F17,	/* picture in picture */
-	[0x30] = KEY_KPPLUS,	/* zoom in */
-	[0x31] = KEY_KPMINUS,	/* zoom out */
-	[0x32] = KEY_F18,	/* capture */
-	[0x33] = KEY_F19,	/* web */
-	[0x34] = KEY_EMAIL,
-	[0x35] = KEY_PHONE,
-	[0x36] = KEY_PC
-};
 
 static int debug;
 module_param(debug, int, 0644);    /* debug level (0,1,2) */
@@ -573,7 +328,8 @@
 		ir->polling      = 50; // ms
 		break;
 	case BTTV_BOARD_CONCEPTRONIC_CTVFMI2:
-		ir_codes         = ir_codes_conceptronic;
+	case BTTV_BOARD_CONTVFMI:
+		ir_codes         = ir_codes_pixelview;
 		ir->mask_keycode = 0x001F00;
 		ir->mask_keyup   = 0x006000;
 		ir->polling      = 50; // ms
diff --git a/drivers/media/video/bttv-risc.c b/drivers/media/video/bttv-risc.c
index b40e973..344f84e 100644
--- a/drivers/media/video/bttv-risc.c
+++ b/drivers/media/video/bttv-risc.c
@@ -51,8 +51,10 @@
 	int rc;
 
 	/* estimate risc mem: worst case is one write per page border +
-	   one write per scan line + sync + jump (all 2 dwords) */
-	instructions  = (bpl * lines) / PAGE_SIZE + lines;
+	   one write per scan line + sync + jump (all 2 dwords).  padding
+	   can cause next bpl to start close to a page border.  First DMA
+	   region may be smaller than PAGE_SIZE */
+	instructions  = 1 + ((bpl + padding) * lines) / PAGE_SIZE + lines;
 	instructions += 2;
 	if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*8)) < 0)
 		return rc;
@@ -104,7 +106,7 @@
 
 	/* save pointer to jmp instruction address */
 	risc->jmp = rp;
-	BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size);
+	BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
 	return 0;
 }
 
@@ -222,7 +224,7 @@
 
 	/* save pointer to jmp instruction address */
 	risc->jmp = rp;
-	BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size);
+	BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
 	return 0;
 }
 
@@ -274,6 +276,8 @@
 		if (line > maxy)
 			btcx_calc_skips(line, ov->w.width, &maxy,
 					skips, &nskips, ov->clips, ov->nclips);
+		else
+			nskips = 0;
 
 		/* write out risc code */
 		for (start = 0, skip = 0; start < ov->w.width; start = end) {
@@ -307,7 +311,7 @@
 
 	/* save pointer to jmp instruction address */
 	risc->jmp = rp;
-	BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size);
+	BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
 	kfree(skips);
 	return 0;
 }
@@ -507,8 +511,7 @@
 void
 bttv_dma_free(struct bttv *btv, struct bttv_buffer *buf)
 {
-	if (in_interrupt())
-		BUG();
+	BUG_ON(in_interrupt());
 	videobuf_waiton(&buf->vb,0,0);
 	videobuf_dma_pci_unmap(btv->c.pci, &buf->vb.dma);
 	videobuf_dma_free(&buf->vb.dma);
diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c
index 6bad93e..d97b7d8 100644
--- a/drivers/media/video/bw-qcam.c
+++ b/drivers/media/video/bw-qcam.c
@@ -73,7 +73,7 @@
 #include <linux/parport.h>
 #include <linux/sched.h>
 #include <linux/videodev.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 #include "bw-qcam.h"
@@ -168,7 +168,7 @@
 	
 	memcpy(&q->vdev, &qcam_template, sizeof(qcam_template));
 	
-	init_MUTEX(&q->lock);
+	mutex_init(&q->lock);
 
 	q->port_mode = (QC_ANY | QC_NOTSET);
 	q->width = 320;
@@ -772,9 +772,9 @@
 			qcam->whitebal = p->whiteness>>8;
 			qcam->bpp = p->depth;
 
-			down(&qcam->lock);			
+			mutex_lock(&qcam->lock);
 			qc_setscanmode(qcam);
-			up(&qcam->lock);
+			mutex_unlock(&qcam->lock);
 			qcam->status |= QC_PARAM_CHANGE;
 
 			return 0;
@@ -805,9 +805,9 @@
 				qcam->height = 240;
 				qcam->transfer_scale = 1;
 			}
-			down(&qcam->lock);
+			mutex_lock(&qcam->lock);
 			qc_setscanmode(qcam);
-			up(&qcam->lock);
+			mutex_unlock(&qcam->lock);
 			
 			/* We must update the camera before we grab. We could
 			   just have changed the grab size */
@@ -854,7 +854,7 @@
 	int len;
 	parport_claim_or_block(qcam->pdev);
 	
-	down(&qcam->lock);
+	mutex_lock(&qcam->lock);
 	
 	qc_reset(qcam);
 
@@ -864,7 +864,7 @@
 
 	len=qc_capture(qcam, buf,count);
 	
-	up(&qcam->lock);
+	mutex_unlock(&qcam->lock);
 	
 	parport_release(qcam->pdev);
 	return len;
diff --git a/drivers/media/video/bw-qcam.h b/drivers/media/video/bw-qcam.h
index 723e8ad..6701daf 100644
--- a/drivers/media/video/bw-qcam.h
+++ b/drivers/media/video/bw-qcam.h
@@ -55,7 +55,7 @@
 	struct video_device vdev;
 	struct pardevice *pdev;
 	struct parport *pport;
-	struct semaphore lock;
+	struct mutex lock;
 	int width, height;
 	int bpp;
 	int mode;
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c
index 9976db4..8211fd8 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -34,7 +34,8 @@
 #include <linux/parport.h>
 #include <linux/sched.h>
 #include <linux/videodev.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
+
 #include <asm/uaccess.h>
 
 struct qcam_device {
@@ -47,7 +48,7 @@
 	int contrast, brightness, whitebal;
 	int top, left;
 	unsigned int bidirectional;
-	struct semaphore lock;
+	struct mutex lock;
 };
 
 /* cameras maximum */
@@ -581,11 +582,11 @@
 			qcam->contrast = p->contrast>>8;
 			qcam->whitebal = p->whiteness>>8;
 
-			down(&qcam->lock);			
+			mutex_lock(&qcam->lock);
 			parport_claim_or_block(qcam->pdev);
 			qc_setup(qcam); 
 			parport_release(qcam->pdev);
-			up(&qcam->lock);
+			mutex_unlock(&qcam->lock);
 			return 0;
 		}
 		case VIDIOCSWIN:
@@ -628,11 +629,11 @@
 #endif
 			/* Ok we figured out what to use from our 
 			   wide choice */
-			down(&qcam->lock);
+			mutex_lock(&qcam->lock);
 			parport_claim_or_block(qcam->pdev);
 			qc_setup(qcam);
 			parport_release(qcam->pdev);
-			up(&qcam->lock);
+			mutex_unlock(&qcam->lock);
 			return 0;
 		}
 		case VIDIOCGWIN:
@@ -672,12 +673,12 @@
 	struct qcam_device *qcam=(struct qcam_device *)v;
 	int len;
 
-	down(&qcam->lock);
+	mutex_lock(&qcam->lock);
 	parport_claim_or_block(qcam->pdev);
 	/* Probably should have a semaphore against multiple users */
 	len = qc_capture(qcam, buf,count); 
 	parport_release(qcam->pdev);
-	up(&qcam->lock);
+	mutex_unlock(&qcam->lock);
 	return len;
 }
 
@@ -727,7 +728,7 @@
 	
 	memcpy(&q->vdev, &qcam_template, sizeof(qcam_template));
 
-	init_MUTEX(&q->lock);
+	mutex_init(&q->lock);
 	q->width = q->ccd_width = 320;
 	q->height = q->ccd_height = 240;
 	q->mode = QC_MILLIONS | QC_DECIMATION_1;
diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c
index 85d964b..d93a561e 100644
--- a/drivers/media/video/cpia.c
+++ b/drivers/media/video/cpia.c
@@ -39,7 +39,7 @@
 #include <linux/pagemap.h>
 #include <linux/delay.h>
 #include <asm/io.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
@@ -622,7 +622,7 @@
 	
 	buffer = page;
 	
-	if (down_interruptible(&cam->param_lock))
+	if (mutex_lock_interruptible(&cam->param_lock))
 		return -ERESTARTSYS;
 	
 	/*
@@ -1350,7 +1350,7 @@
 	} else
 		DBG("error: %d\n", retval);
 	
-	up(&cam->param_lock);
+	mutex_unlock(&cam->param_lock);
 	
 out:
 	free_page((unsigned long)page);
@@ -1664,7 +1664,7 @@
 	case CPIA_COMMAND_GetColourParams:
 	case CPIA_COMMAND_GetColourBalance:
 	case CPIA_COMMAND_GetExposure:
-		down(&cam->param_lock);
+		mutex_lock(&cam->param_lock);
 		datasize=8;
 		break;
 	case CPIA_COMMAND_ReadMCPorts: 
@@ -1691,7 +1691,7 @@
 		if (command == CPIA_COMMAND_GetColourParams ||
 		    command == CPIA_COMMAND_GetColourBalance ||
 		    command == CPIA_COMMAND_GetExposure)
-			up(&cam->param_lock);
+			mutex_unlock(&cam->param_lock);
 	} else {
 		switch(command) {
 		case CPIA_COMMAND_GetCPIAVersion:
@@ -1726,13 +1726,13 @@
 			cam->params.colourParams.brightness = data[0];
 			cam->params.colourParams.contrast = data[1];
 			cam->params.colourParams.saturation = data[2];
-			up(&cam->param_lock);
+			mutex_unlock(&cam->param_lock);
 			break;
 		case CPIA_COMMAND_GetColourBalance:
 			cam->params.colourBalance.redGain = data[0];
 			cam->params.colourBalance.greenGain = data[1];
 			cam->params.colourBalance.blueGain = data[2];
-			up(&cam->param_lock);
+			mutex_unlock(&cam->param_lock);
 			break;
 		case CPIA_COMMAND_GetExposure:
 			cam->params.exposure.gain = data[0];
@@ -1743,7 +1743,7 @@
 			cam->params.exposure.green1Comp = data[5];
 			cam->params.exposure.green2Comp = data[6];
 			cam->params.exposure.blueComp = data[7];
-			up(&cam->param_lock);
+			mutex_unlock(&cam->param_lock);
 			break;
 
 		case CPIA_COMMAND_ReadMCPorts: 
@@ -2059,7 +2059,7 @@
 	int rows, cols, linesize, subsample_422;
 
 	/* make sure params don't change while we are decoding */
-	down(&cam->param_lock);
+	mutex_lock(&cam->param_lock);
 
 	obuf = cam->decompressed_frame.data;
 	end_obuf = obuf+CPIA_MAX_FRAME_SIZE;
@@ -2069,26 +2069,26 @@
 
 	if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) {
 		LOG("header not found\n");
-		up(&cam->param_lock);
+		mutex_unlock(&cam->param_lock);
 		return -1;
 	}
 
 	if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) {
 		LOG("wrong video size\n");
-		up(&cam->param_lock);
+		mutex_unlock(&cam->param_lock);
 		return -1;
 	}
 	
 	if (ibuf[17] != SUBSAMPLE_420 && ibuf[17] != SUBSAMPLE_422) {
 		LOG("illegal subtype %d\n",ibuf[17]);
-		up(&cam->param_lock);
+		mutex_unlock(&cam->param_lock);
 		return -1;
 	}
 	subsample_422 = ibuf[17] == SUBSAMPLE_422;
 	
 	if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) {
 		LOG("illegal yuvorder %d\n",ibuf[18]);
-		up(&cam->param_lock);
+		mutex_unlock(&cam->param_lock);
 		return -1;
 	}
 	in_uyvy = ibuf[18] == YUVORDER_UYVY;
@@ -2098,7 +2098,7 @@
 	    (ibuf[26] != cam->params.roi.rowStart) ||
 	    (ibuf[27] != cam->params.roi.rowEnd)) {
 		LOG("ROI mismatch\n");
-		up(&cam->param_lock);
+		mutex_unlock(&cam->param_lock);
 		return -1;
 	}
 	cols = 8*(ibuf[25] - ibuf[24]);
@@ -2107,14 +2107,14 @@
 	
 	if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) {
 		LOG("illegal compression %d\n",ibuf[28]);
-		up(&cam->param_lock);
+		mutex_unlock(&cam->param_lock);
 		return -1;
 	}
 	compressed = (ibuf[28] == COMPRESSED);
 	
 	if (ibuf[29] != NO_DECIMATION && ibuf[29] != DECIMATION_ENAB) {
 		LOG("illegal decimation %d\n",ibuf[29]);
-		up(&cam->param_lock);
+		mutex_unlock(&cam->param_lock);
 		return -1;
 	}
 	decimation = (ibuf[29] == DECIMATION_ENAB);	
@@ -2130,7 +2130,7 @@
 	cam->params.status.vpStatus = ibuf[38];
 	cam->params.status.errorCode = ibuf[39];
 	cam->fps = ibuf[41];
-	up(&cam->param_lock);
+	mutex_unlock(&cam->param_lock);
 	
 	linesize = skipcount(cols, out_fmt);
 	ibuf += FRAME_HEADER_SIZE;
@@ -2271,9 +2271,9 @@
 /* update various camera modes and settings */
 static void dispatch_commands(struct cam_data *cam)
 {
-	down(&cam->param_lock);
+	mutex_lock(&cam->param_lock);
 	if (cam->cmd_queue==COMMAND_NONE) {
-		up(&cam->param_lock);
+		mutex_unlock(&cam->param_lock);
 		return;
 	}
 	DEB_BYTE(cam->cmd_queue);
@@ -2415,7 +2415,7 @@
 	  }
 
 	cam->cmd_queue = COMMAND_NONE;
-	up(&cam->param_lock);
+	mutex_unlock(&cam->param_lock);
 	return;
 }
 
@@ -2562,7 +2562,7 @@
 	gain = data[2];
 	coarseL = data[3];
 
-	down(&cam->param_lock);
+	mutex_lock(&cam->param_lock);
 	light_exp = cam->params.colourParams.brightness +
 	            TC - 50 + EXP_ACC_LIGHT;
 	if(light_exp > 255)
@@ -2762,7 +2762,7 @@
 			LOG("Automatically increasing sensor_fps\n");
 		}
 	}
-	up(&cam->param_lock);
+	mutex_unlock(&cam->param_lock);
 }
 
 /*-----------------------------------------------------------------*/
@@ -2778,10 +2778,10 @@
 	int cam_exposure, old_exp;
 	if(!FIRMWARE_VERSION(1,2))
 		return;
-	down(&cam->param_lock);
+	mutex_lock(&cam->param_lock);
 	if(cam->params.flickerControl.flickerMode == 0 ||
 	   cam->raw_image[39] == 0) {
-		up(&cam->param_lock);
+		mutex_unlock(&cam->param_lock);
 		return;
 	}
 	cam_exposure = cam->raw_image[39]*2;
@@ -2810,7 +2810,7 @@
 			cam->exposure_status = EXPOSURE_NORMAL;
 
 	}
-	up(&cam->param_lock);
+	mutex_unlock(&cam->param_lock);
 }
 #undef FIRMWARE_VERSION
 
@@ -3186,7 +3186,7 @@
 	if (!try_module_get(cam->ops->owner))
 		return -ENODEV;
 
-	down(&cam->busy_lock);
+	mutex_lock(&cam->busy_lock);
 	err = -ENOMEM;
 	if (!cam->raw_image) {
 		cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE);
@@ -3227,7 +3227,7 @@
 	
 	++cam->open_count;
 	file->private_data = dev;
-	up(&cam->busy_lock);
+	mutex_unlock(&cam->busy_lock);
 	return 0;
 
  oops:
@@ -3239,7 +3239,7 @@
 		rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
 		cam->raw_image = NULL;
 	}
-	up(&cam->busy_lock);
+	mutex_unlock(&cam->busy_lock);
 	put_cam(cam->ops);
 	return err;
 }
@@ -3303,24 +3303,24 @@
 	int err;
 
 	/* make this _really_ smp and multithread-safe */
-	if (down_interruptible(&cam->busy_lock))
+	if (mutex_lock_interruptible(&cam->busy_lock))
 		return -EINTR;
 
 	if (!buf) {
 		DBG("buf NULL\n");
-		up(&cam->busy_lock);
+		mutex_unlock(&cam->busy_lock);
 		return -EINVAL;
 	}
 
 	if (!count) {
 		DBG("count 0\n");
-		up(&cam->busy_lock);
+		mutex_unlock(&cam->busy_lock);
 		return 0;
 	}
 
 	if (!cam->ops) {
 		DBG("ops NULL\n");
-		up(&cam->busy_lock);
+		mutex_unlock(&cam->busy_lock);
 		return -ENODEV;
 	}
 
@@ -3329,7 +3329,7 @@
 	cam->mmap_kludge=0;
 	if((err = fetch_frame(cam)) != 0) {
 		DBG("ERROR from fetch_frame: %d\n", err);
-		up(&cam->busy_lock);
+		mutex_unlock(&cam->busy_lock);
 		return err;
 	}
 	cam->decompressed_frame.state = FRAME_UNUSED;
@@ -3338,17 +3338,17 @@
 	if (cam->decompressed_frame.count > count) {
 		DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count,
 		    (unsigned long) count);
-		up(&cam->busy_lock);
+		mutex_unlock(&cam->busy_lock);
 		return -EFAULT;
 	}
 	if (copy_to_user(buf, cam->decompressed_frame.data,
 	                cam->decompressed_frame.count)) {
 		DBG("copy_to_user failed\n");
-		up(&cam->busy_lock);
+		mutex_unlock(&cam->busy_lock);
 		return -EFAULT;
 	}
 
-	up(&cam->busy_lock);
+	mutex_unlock(&cam->busy_lock);
 	return cam->decompressed_frame.count;
 }
 
@@ -3363,7 +3363,7 @@
 		return -ENODEV;
 	
 	/* make this _really_ smp-safe */
-	if (down_interruptible(&cam->busy_lock))
+	if (mutex_lock_interruptible(&cam->busy_lock))
 		return -EINTR;
 
 	//DBG("cpia_ioctl: %u\n", ioctlnr);
@@ -3439,7 +3439,7 @@
 			break;
 		}
 
-		down(&cam->param_lock);
+		mutex_lock(&cam->param_lock);
 		/* brightness, colour, contrast need no check 0-65535 */
 		cam->vp = *vp;
 		/* update cam->params.colourParams */
@@ -3466,7 +3466,7 @@
 
 		/* queue command to update camera */
 		cam->cmd_queue |= COMMAND_SETCOLOURPARAMS;
-		up(&cam->param_lock);
+		mutex_unlock(&cam->param_lock);
 		DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n",
 		    vp->depth, vp->palette, vp->brightness, vp->hue, vp->colour,
 		    vp->contrast);
@@ -3501,13 +3501,13 @@
 		/* we set the video window to something smaller or equal to what
 		* is requested by the user???
 		*/
-		down(&cam->param_lock);
+		mutex_lock(&cam->param_lock);
 		if (vw->width != cam->vw.width || vw->height != cam->vw.height) {
 			int video_size = match_videosize(vw->width, vw->height);
 
 			if (video_size < 0) {
 				retval = -EINVAL;
-				up(&cam->param_lock);
+				mutex_unlock(&cam->param_lock);
 				break;
 			}
 			cam->video_size = video_size;
@@ -3520,7 +3520,7 @@
 			cam->cmd_queue |= COMMAND_SETFORMAT;
 		}
 
-		up(&cam->param_lock);
+		mutex_unlock(&cam->param_lock);
 
 		/* setformat ignored by camera during streaming,
 		 * so stop/dispatch/start */
@@ -3682,7 +3682,7 @@
 
 		DBG("%d,%d/%dx%d\n", vc->x,vc->y,vc->width, vc->height);
 		
-		down(&cam->param_lock);
+		mutex_lock(&cam->param_lock);
 		
 		cam->vc.x      = vc->x;
 		cam->vc.y      = vc->y;
@@ -3692,7 +3692,7 @@
 		set_vw_size(cam);
 		cam->cmd_queue |= COMMAND_SETFORMAT;
 
-		up(&cam->param_lock);
+		mutex_unlock(&cam->param_lock);
 
 		/* setformat ignored by camera during streaming,
 		 * so stop/dispatch/start */
@@ -3736,7 +3736,7 @@
 		break;
 	}
 
-	up(&cam->busy_lock);
+	mutex_unlock(&cam->busy_lock);
 	return retval;
 } 
 
@@ -3769,12 +3769,12 @@
 		return -ENODEV;
 	
 	/* make this _really_ smp-safe */
-	if (down_interruptible(&cam->busy_lock))
+	if (mutex_lock_interruptible(&cam->busy_lock))
 		return -EINTR;
 
 	if (!cam->frame_buf) {	/* we do lazy allocation */
 		if ((retval = allocate_frame_buf(cam))) {
-			up(&cam->busy_lock);
+			mutex_unlock(&cam->busy_lock);
 			return retval;
 		}
 	}
@@ -3783,7 +3783,7 @@
 	while (size > 0) {
 		page = vmalloc_to_pfn((void *)pos);
 		if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-			up(&cam->busy_lock);
+			mutex_unlock(&cam->busy_lock);
 			return -EAGAIN;
 		}
 		start += PAGE_SIZE;
@@ -3795,7 +3795,7 @@
 	}
 
 	DBG("cpia_mmap: %ld\n", size);
-	up(&cam->busy_lock);
+	mutex_unlock(&cam->busy_lock);
 
 	return 0;
 }
@@ -3936,8 +3936,8 @@
 	memset(cam, 0, sizeof(struct cam_data));
 
 	cam->ops = ops;
-	init_MUTEX(&cam->param_lock);
-	init_MUTEX(&cam->busy_lock);
+	mutex_init(&cam->param_lock);
+	mutex_init(&cam->busy_lock);
 
 	reset_camera_struct(cam);
 
diff --git a/drivers/media/video/cpia.h b/drivers/media/video/cpia.h
index f629b69..de66782 100644
--- a/drivers/media/video/cpia.h
+++ b/drivers/media/video/cpia.h
@@ -47,6 +47,7 @@
 #include <linux/videodev.h>
 #include <linux/list.h>
 #include <linux/smp_lock.h>
+#include <linux/mutex.h>
 
 struct cpia_camera_ops
 {
@@ -246,7 +247,7 @@
 struct cam_data {
 	struct list_head cam_data_list;
 
-        struct semaphore busy_lock;     /* guard against SMP multithreading */
+        struct mutex busy_lock;     /* guard against SMP multithreading */
 	struct cpia_camera_ops *ops;	/* lowlevel driver operations */
 	void *lowlevel_data;		/* private data for lowlevel driver */
 	u8 *raw_image;			/* buffer for raw image data */
@@ -261,7 +262,7 @@
 	u8 mainsFreq;			/* for flicker control */
 
 				/* proc interface */
-	struct semaphore param_lock;	/* params lock for this camera */
+	struct mutex param_lock;	/* params lock for this camera */
 	struct cam_params params;	/* camera settings */
 	struct proc_dir_entry *proc_entry;	/* /proc/cpia/videoX */
 	
diff --git a/drivers/media/video/cpia2/Kconfig b/drivers/media/video/cpia2/Kconfig
new file mode 100644
index 0000000..513cc09
--- /dev/null
+++ b/drivers/media/video/cpia2/Kconfig
@@ -0,0 +1,9 @@
+config VIDEO_CPIA2
+	tristate "CPiA2 Video For Linux"
+	depends on VIDEO_DEV && USB
+	---help---
+	  This is the video4linux driver for cameras based on Vision's CPiA2
+	  (Colour Processor Interface ASIC), such as the Digital Blue QX5
+	  Microscope. If you have one of these cameras, say Y here
+
+	  This driver is also available as a module (cpia2).
diff --git a/drivers/media/video/cpia2/Makefile b/drivers/media/video/cpia2/Makefile
new file mode 100644
index 0000000..828cf1b
--- /dev/null
+++ b/drivers/media/video/cpia2/Makefile
@@ -0,0 +1,3 @@
+cpia2-objs	:= cpia2_v4l.o cpia2_usb.o cpia2_core.o
+
+obj-$(CONFIG_VIDEO_CPIA2) += cpia2.o
diff --git a/drivers/media/video/cpia2/cpia2.h b/drivers/media/video/cpia2/cpia2.h
new file mode 100644
index 0000000..95d3afa
--- /dev/null
+++ b/drivers/media/video/cpia2/cpia2.h
@@ -0,0 +1,497 @@
+/****************************************************************************
+ *
+ *  Filename: cpia2.h
+ *
+ *  Copyright 2001, STMicrolectronics, Inc.
+ *
+ *  Contact:  steve.miller@st.com
+ *
+ *  Description:
+ *     This is a USB driver for CPiA2 based video cameras.
+ *
+ *     This driver is modelled on the cpia usb driver by
+ *     Jochen Scharrlach and Johannes Erdfeldt.
+ *
+ *  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 __CPIA2_H__
+#define __CPIA2_H__
+
+#include <linux/version.h>
+#include <linux/videodev.h>
+#include <linux/usb.h>
+#include <linux/poll.h>
+
+#include "cpia2dev.h"
+#include "cpia2_registers.h"
+
+/* define for verbose debug output */
+//#define _CPIA2_DEBUG_
+
+#define CPIA2_MAJ_VER	2
+#define CPIA2_MIN_VER   0
+#define CPIA2_PATCH_VER	0
+
+/***
+ * Image defines
+ ***/
+#ifndef true
+#define true 1
+#define false 0
+#endif
+
+/*  Misc constants */
+#define ALLOW_CORRUPT 0		/* Causes collater to discard checksum */
+
+/* USB Transfer mode */
+#define XFER_ISOC 0
+#define XFER_BULK 1
+
+/* USB Alternates */
+#define USBIF_CMDONLY 0
+#define USBIF_BULK 1
+#define USBIF_ISO_1 2	/*  128 bytes/ms */
+#define USBIF_ISO_2 3	/*  384 bytes/ms */
+#define USBIF_ISO_3 4	/*  640 bytes/ms */
+#define USBIF_ISO_4 5	/*  768 bytes/ms */
+#define USBIF_ISO_5 6	/*  896 bytes/ms */
+#define USBIF_ISO_6 7	/* 1023 bytes/ms */
+
+/* Flicker Modes */
+#define NEVER_FLICKER   0
+#define ANTI_FLICKER_ON 1
+#define FLICKER_60      60
+#define FLICKER_50      50
+
+/* Debug flags */
+#define DEBUG_NONE          0
+#define DEBUG_REG           0x00000001
+#define DEBUG_DUMP_PATCH    0x00000002
+#define DEBUG_DUMP_REGS     0x00000004
+
+/***
+ * Video frame sizes
+ ***/
+enum {
+	VIDEOSIZE_VGA = 0,	/* 640x480 */
+	VIDEOSIZE_CIF,		/* 352x288 */
+	VIDEOSIZE_QVGA,		/* 320x240 */
+	VIDEOSIZE_QCIF,		/* 176x144 */
+	VIDEOSIZE_288_216,
+	VIDEOSIZE_256_192,
+	VIDEOSIZE_224_168,
+	VIDEOSIZE_192_144,
+};
+
+#define STV_IMAGE_CIF_ROWS    288
+#define STV_IMAGE_CIF_COLS    352
+
+#define STV_IMAGE_QCIF_ROWS   144
+#define STV_IMAGE_QCIF_COLS   176
+
+#define STV_IMAGE_VGA_ROWS    480
+#define STV_IMAGE_VGA_COLS    640
+
+#define STV_IMAGE_QVGA_ROWS   240
+#define STV_IMAGE_QVGA_COLS   320
+
+#define JPEG_MARKER_COM (1<<6)	/* Comment segment */
+
+/***
+ * Enums
+ ***/
+/* Sensor types available with cpia2 asics */
+enum sensors {
+	CPIA2_SENSOR_410,
+	CPIA2_SENSOR_500
+};
+
+/* Asic types available in the CPiA2 architecture */
+#define  CPIA2_ASIC_672 0x67
+
+/* Device types (stv672, stv676, etc) */
+#define  DEVICE_STV_672   0x0001
+#define  DEVICE_STV_676   0x0002
+
+enum frame_status {
+	FRAME_EMPTY,
+	FRAME_READING,		/* In the process of being grabbed into */
+	FRAME_READY,		/* Ready to be read */
+	FRAME_ERROR,
+};
+
+/***
+ * Register access (for USB request byte)
+ ***/
+enum {
+	CAMERAACCESS_SYSTEM = 0,
+	CAMERAACCESS_VC,
+	CAMERAACCESS_VP,
+	CAMERAACCESS_IDATA
+};
+
+#define CAMERAACCESS_TYPE_BLOCK    0x00
+#define CAMERAACCESS_TYPE_RANDOM   0x04
+#define CAMERAACCESS_TYPE_MASK     0x08
+#define CAMERAACCESS_TYPE_REPEAT   0x0C
+
+#define TRANSFER_READ 0
+#define TRANSFER_WRITE 1
+
+#define DEFAULT_ALT   USBIF_ISO_6
+#define DEFAULT_BRIGHTNESS 0x46
+#define DEFAULT_CONTRAST 0x93
+#define DEFAULT_SATURATION 0x7f
+#define DEFAULT_TARGET_KB 0x30
+
+/* Power state */
+#define HI_POWER_MODE CPIA2_SYSTEM_CONTROL_HIGH_POWER
+#define LO_POWER_MODE CPIA2_SYSTEM_CONTROL_LOW_POWER
+
+
+/********
+ * Commands
+ *******/
+enum {
+	CPIA2_CMD_NONE = 0,
+	CPIA2_CMD_GET_VERSION,
+	CPIA2_CMD_GET_PNP_ID,
+	CPIA2_CMD_GET_ASIC_TYPE,
+	CPIA2_CMD_GET_SENSOR,
+	CPIA2_CMD_GET_VP_DEVICE,
+	CPIA2_CMD_GET_VP_BRIGHTNESS,
+	CPIA2_CMD_SET_VP_BRIGHTNESS,
+	CPIA2_CMD_GET_CONTRAST,
+	CPIA2_CMD_SET_CONTRAST,
+	CPIA2_CMD_GET_VP_SATURATION,
+	CPIA2_CMD_SET_VP_SATURATION,
+	CPIA2_CMD_GET_VP_GPIO_DIRECTION,
+	CPIA2_CMD_SET_VP_GPIO_DIRECTION,
+	CPIA2_CMD_GET_VP_GPIO_DATA,
+	CPIA2_CMD_SET_VP_GPIO_DATA,
+	CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION,
+	CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION,
+	CPIA2_CMD_GET_VC_MP_GPIO_DATA,
+	CPIA2_CMD_SET_VC_MP_GPIO_DATA,
+	CPIA2_CMD_ENABLE_PACKET_CTRL,
+	CPIA2_CMD_GET_FLICKER_MODES,
+	CPIA2_CMD_SET_FLICKER_MODES,
+	CPIA2_CMD_RESET_FIFO,	/* clear fifo and enable stream block */
+	CPIA2_CMD_SET_HI_POWER,
+	CPIA2_CMD_SET_LOW_POWER,
+	CPIA2_CMD_CLEAR_V2W_ERR,
+	CPIA2_CMD_SET_USER_MODE,
+	CPIA2_CMD_GET_USER_MODE,
+	CPIA2_CMD_FRAMERATE_REQ,
+	CPIA2_CMD_SET_COMPRESSION_STATE,
+	CPIA2_CMD_GET_WAKEUP,
+	CPIA2_CMD_SET_WAKEUP,
+	CPIA2_CMD_GET_PW_CONTROL,
+	CPIA2_CMD_SET_PW_CONTROL,
+	CPIA2_CMD_GET_SYSTEM_CTRL,
+	CPIA2_CMD_SET_SYSTEM_CTRL,
+	CPIA2_CMD_GET_VP_SYSTEM_STATE,
+	CPIA2_CMD_GET_VP_SYSTEM_CTRL,
+	CPIA2_CMD_SET_VP_SYSTEM_CTRL,
+	CPIA2_CMD_GET_VP_EXP_MODES,
+	CPIA2_CMD_SET_VP_EXP_MODES,
+	CPIA2_CMD_GET_DEVICE_CONFIG,
+	CPIA2_CMD_SET_DEVICE_CONFIG,
+	CPIA2_CMD_SET_SERIAL_ADDR,
+	CPIA2_CMD_SET_SENSOR_CR1,
+	CPIA2_CMD_GET_VC_CONTROL,
+	CPIA2_CMD_SET_VC_CONTROL,
+	CPIA2_CMD_SET_TARGET_KB,
+	CPIA2_CMD_SET_DEF_JPEG_OPT,
+	CPIA2_CMD_REHASH_VP4,
+	CPIA2_CMD_GET_USER_EFFECTS,
+	CPIA2_CMD_SET_USER_EFFECTS
+};
+
+enum user_cmd {
+	COMMAND_NONE = 0x00000001,
+	COMMAND_SET_FPS = 0x00000002,
+	COMMAND_SET_COLOR_PARAMS = 0x00000004,
+	COMMAND_GET_COLOR_PARAMS = 0x00000008,
+	COMMAND_SET_FORMAT = 0x00000010,	/* size, etc */
+	COMMAND_SET_FLICKER = 0x00000020
+};
+
+/***
+ * Some defines specific to the 676 chip
+ ***/
+#define CAMACC_CIF      0x01
+#define CAMACC_VGA      0x02
+#define CAMACC_QCIF     0x04
+#define CAMACC_QVGA     0x08
+
+
+struct cpia2_register {
+	u8 index;
+	u8 value;
+};
+
+struct cpia2_reg_mask {
+	u8 index;
+	u8 and_mask;
+	u8 or_mask;
+	u8 fill;
+};
+
+struct cpia2_command {
+	u32 command;
+	u8 req_mode;		/* (Block or random) | registerBank */
+	u8 reg_count;
+	u8 direction;
+	u8 start;
+	union reg_types {
+		struct cpia2_register registers[32];
+		struct cpia2_reg_mask masks[16];
+		u8 block_data[64];
+		u8 *patch_data;	/* points to function defined block */
+	} buffer;
+};
+
+struct camera_params {
+	struct {
+		u8 firmware_revision_hi; /* For system register set (bank 0) */
+		u8 firmware_revision_lo;
+		u8 asic_id;	/* Video Compressor set (bank 1) */
+		u8 asic_rev;
+		u8 vp_device_hi;	/* Video Processor set (bank 2) */
+		u8 vp_device_lo;
+		u8 sensor_flags;
+		u8 sensor_rev;
+	} version;
+
+	struct {
+		u32 device_type;     /* enumerated from vendor/product ids.
+				      * Currently, either STV_672 or STV_676 */
+		u16 vendor;
+		u16 product;
+		u16 device_revision;
+	} pnp_id;
+
+	struct {
+		u8 brightness;	/* CPIA2_VP_EXPOSURE_TARGET */
+		u8 contrast;	/* Note: this is CPIA2_VP_YRANGE */
+		u8 saturation;	/*  CPIA2_VP_SATURATION */
+	} color_params;
+
+	struct {
+		u8 cam_register;
+		u8 flicker_mode_req;	/* 1 if flicker on, else never flicker */
+		int mains_frequency;
+	} flicker_control;
+
+	struct {
+		u8 jpeg_options;
+		u8 creep_period;
+		u8 user_squeeze;
+		u8 inhibit_htables;
+	} compression;
+
+	struct {
+		u8 ohsize;	/* output image size */
+		u8 ovsize;
+		u8 hcrop;	/* cropping start_pos/4 */
+		u8 vcrop;
+		u8 hphase;	/* scaling registers */
+		u8 vphase;
+		u8 hispan;
+		u8 vispan;
+		u8 hicrop;
+		u8 vicrop;
+		u8 hifraction;
+		u8 vifraction;
+	} image_size;
+
+	struct {
+		int width;	/* actual window width */
+		int height;	/* actual window height */
+	} roi;
+
+	struct {
+		u8 video_mode;
+		u8 frame_rate;
+		u8 video_size;	/* Not a register, just a convenience for cropped sizes */
+		u8 gpio_direction;
+		u8 gpio_data;
+		u8 system_ctrl;
+		u8 system_state;
+		u8 lowlight_boost;	/* Bool: 0 = off, 1 = on */
+		u8 device_config;
+		u8 exposure_modes;
+		u8 user_effects;
+	} vp_params;
+
+	struct {
+		u8 pw_control;
+		u8 wakeup;
+		u8 vc_control;
+		u8 vc_mp_direction;
+		u8 vc_mp_data;
+		u8 target_kb;
+	} vc_params;
+
+	struct {
+		u8 power_mode;
+		u8 system_ctrl;
+		u8 stream_mode;	/* This is the current alternate for usb drivers */
+		u8 allow_corrupt;
+	} camera_state;
+};
+
+#define NUM_SBUF    2
+
+struct cpia2_sbuf {
+	char *data;
+	struct urb *urb;
+};
+
+struct framebuf {
+	struct timeval timestamp;
+	unsigned long seq;
+	int num;
+	int length;
+	int max_length;
+	volatile enum frame_status status;
+	u8 *data;
+	struct framebuf *next;
+};
+
+struct cpia2_fh {
+	enum v4l2_priority prio;
+	u8 mmapped;
+};
+
+struct camera_data {
+	/* locks */
+	struct semaphore busy_lock;	/* guard against SMP multithreading */
+	struct v4l2_prio_state prio;
+
+	/* camera status */
+	volatile int present;	/* Is the camera still present? */
+	int open_count;		/* # of process that have camera open */
+	int first_image_seen;
+	u8 mains_freq;		/* for flicker control */
+	enum sensors sensor_type;
+	u8 flush;
+	u8 mmapped;
+	int streaming;		/* 0 = no, 1 = yes */
+	int xfer_mode;		/* XFER_BULK or XFER_ISOC */
+	struct camera_params params;	/* camera settings */
+
+	/* v4l */
+	int video_size;			/* VIDEO_SIZE_ */
+	struct video_device *vdev;	/* v4l videodev */
+	struct video_picture vp;	/* v4l camera settings */
+	struct video_window vw;		/* v4l capture area */
+	__u32 pixelformat;       /* Format fourcc      */
+
+	/* USB */
+	struct usb_device *dev;
+	unsigned char iface;
+	unsigned int cur_alt;
+	unsigned int old_alt;
+	struct cpia2_sbuf sbuf[NUM_SBUF];	/* Double buffering */
+
+	wait_queue_head_t wq_stream;
+
+	/* Buffering */
+	u32 frame_size;
+	int num_frames;
+	unsigned long frame_count;
+	u8 *frame_buffer;	/* frame buffer data */
+	struct framebuf *buffers;
+	struct framebuf * volatile curbuff;
+	struct framebuf *workbuff;
+
+	/* MJPEG Extension */
+	int APPn;		/* Number of APP segment to be written, must be 0..15 */
+	int APP_len;		/* Length of data in JPEG APPn segment */
+	char APP_data[60];	/* Data in the JPEG APPn segment. */
+
+	int COM_len;		/* Length of data in JPEG COM segment */
+	char COM_data[60];	/* Data in JPEG COM segment */
+};
+
+/* v4l */
+int cpia2_register_camera(struct camera_data *cam);
+void cpia2_unregister_camera(struct camera_data *cam);
+
+/* core */
+int cpia2_reset_camera(struct camera_data *cam);
+int cpia2_set_low_power(struct camera_data *cam);
+void cpia2_dbg_dump_registers(struct camera_data *cam);
+int cpia2_match_video_size(int width, int height);
+void cpia2_set_camera_state(struct camera_data *cam);
+void cpia2_save_camera_state(struct camera_data *cam);
+void cpia2_set_color_params(struct camera_data *cam);
+void cpia2_set_brightness(struct camera_data *cam, unsigned char value);
+void cpia2_set_contrast(struct camera_data *cam, unsigned char value);
+void cpia2_set_saturation(struct camera_data *cam, unsigned char value);
+int cpia2_set_flicker_mode(struct camera_data *cam, int mode);
+void cpia2_set_format(struct camera_data *cam);
+int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd);
+int cpia2_do_command(struct camera_data *cam,
+		     unsigned int command,
+		     unsigned char direction, unsigned char param);
+struct camera_data *cpia2_init_camera_struct(void);
+int cpia2_init_camera(struct camera_data *cam);
+int cpia2_allocate_buffers(struct camera_data *cam);
+void cpia2_free_buffers(struct camera_data *cam);
+long cpia2_read(struct camera_data *cam,
+		char *buf, unsigned long count, int noblock);
+unsigned int cpia2_poll(struct camera_data *cam,
+			struct file *filp, poll_table *wait);
+int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma);
+void cpia2_set_property_flip(struct camera_data *cam, int prop_val);
+void cpia2_set_property_mirror(struct camera_data *cam, int prop_val);
+int cpia2_set_target_kb(struct camera_data *cam, unsigned char value);
+int cpia2_set_gpio(struct camera_data *cam, unsigned char setting);
+int cpia2_set_fps(struct camera_data *cam, int framerate);
+
+/* usb */
+int cpia2_usb_init(void);
+void cpia2_usb_cleanup(void);
+int cpia2_usb_transfer_cmd(struct camera_data *cam, void *registers,
+			   u8 request, u8 start, u8 count, u8 direction);
+int cpia2_usb_stream_start(struct camera_data *cam, unsigned int alternate);
+int cpia2_usb_stream_stop(struct camera_data *cam);
+int cpia2_usb_stream_pause(struct camera_data *cam);
+int cpia2_usb_stream_resume(struct camera_data *cam);
+int cpia2_usb_change_streaming_alternate(struct camera_data *cam,
+					 unsigned int alt);
+
+
+/* ----------------------- debug functions ---------------------- */
+#ifdef _CPIA2_DEBUG_
+#define ALOG(lev, fmt, args...) printk(lev "%s:%d %s(): " fmt, __FILE__, __LINE__, __func__, ## args)
+#define LOG(fmt, args...) ALOG(KERN_INFO, fmt, ## args)
+#define ERR(fmt, args...) ALOG(KERN_ERR, fmt, ## args)
+#define DBG(fmt, args...) ALOG(KERN_DEBUG, fmt, ## args)
+#else
+#define ALOG(fmt,args...) printk(fmt,##args)
+#define LOG(fmt,args...) ALOG(KERN_INFO "cpia2: "fmt,##args)
+#define ERR(fmt,args...) ALOG(KERN_ERR "cpia2: "fmt,##args)
+#define DBG(fmn,args...) do {} while(0)
+#endif
+/* No function or lineno, for shorter lines */
+#define KINFO(fmt, args...) printk(KERN_INFO fmt,##args)
+
+#endif
diff --git a/drivers/media/video/cpia2/cpia2_core.c b/drivers/media/video/cpia2/cpia2_core.c
new file mode 100644
index 0000000..5dfb242
--- /dev/null
+++ b/drivers/media/video/cpia2/cpia2_core.c
@@ -0,0 +1,2525 @@
+/****************************************************************************
+ *
+ *  Filename: cpia2_core.c
+ *
+ *  Copyright 2001, STMicrolectronics, Inc.
+ *      Contact:  steve.miller@st.com
+ *
+ *  Description:
+ *     This is a USB driver for CPia2 based video cameras.
+ *     The infrastructure of this driver is based on the cpia usb driver by
+ *     Jochen Scharrlach and Johannes Erdfeldt.
+ *
+ *  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.
+ *
+ *  Stripped of 2.4 stuff ready for main kernel submit by
+ *		Alan Cox <alan@redhat.com>
+ *
+ ****************************************************************************/
+
+#include "cpia2.h"
+
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+//#define _CPIA2_DEBUG_
+
+#include "cpia2patch.h"
+
+#ifdef _CPIA2_DEBUG_
+
+static const char *block_name[] = {
+	"System",
+	"VC",
+	"VP",
+	"IDATA"
+};
+#endif
+
+static unsigned int debugs_on = 0;//DEBUG_REG;
+
+
+/******************************************************************************
+ *
+ *  Forward Declarations
+ *
+ *****************************************************************************/
+static int apply_vp_patch(struct camera_data *cam);
+static int set_default_user_mode(struct camera_data *cam);
+static int set_vw_size(struct camera_data *cam, int size);
+static int configure_sensor(struct camera_data *cam,
+			    int reqwidth, int reqheight);
+static int config_sensor_410(struct camera_data *cam,
+			    int reqwidth, int reqheight);
+static int config_sensor_500(struct camera_data *cam,
+			    int reqwidth, int reqheight);
+static int set_all_properties(struct camera_data *cam);
+static void get_color_params(struct camera_data *cam);
+static void wake_system(struct camera_data *cam);
+static void set_lowlight_boost(struct camera_data *cam);
+static void reset_camera_struct(struct camera_data *cam);
+static int cpia2_set_high_power(struct camera_data *cam);
+
+/* Here we want the physical address of the memory.
+ * This is used when initializing the contents of the
+ * area and marking the pages as reserved.
+ */
+static inline unsigned long kvirt_to_pa(unsigned long adr)
+{
+	unsigned long kva, ret;
+
+	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
+	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
+	ret = __pa(kva);
+	return ret;
+}
+
+static void *rvmalloc(unsigned long size)
+{
+	void *mem;
+	unsigned long adr;
+
+	/* Round it off to PAGE_SIZE */
+	size = PAGE_ALIGN(size);
+
+	mem = vmalloc_32(size);
+	if (!mem)
+		return NULL;
+
+	memset(mem, 0, size);	/* Clear the ram out, no junk to the user */
+	adr = (unsigned long) mem;
+
+	while ((long)size > 0) {
+		SetPageReserved(vmalloc_to_page((void *)adr));
+		adr += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+	return mem;
+}
+
+static void rvfree(void *mem, unsigned long size)
+{
+	unsigned long adr;
+
+	if (!mem)
+		return;
+
+	size = PAGE_ALIGN(size);
+
+	adr = (unsigned long) mem;
+	while ((long)size > 0) {
+		ClearPageReserved(vmalloc_to_page((void *)adr));
+		adr += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+	vfree(mem);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_do_command
+ *
+ *  Send an arbitrary command to the camera.  For commands that read from
+ *  the camera, copy the buffers into the proper param structures.
+ *****************************************************************************/
+int cpia2_do_command(struct camera_data *cam,
+		     u32 command, u8 direction, u8 param)
+{
+	int retval = 0;
+	struct cpia2_command cmd;
+	unsigned int device = cam->params.pnp_id.device_type;
+
+	cmd.command = command;
+	cmd.reg_count = 2;	/* default */
+	cmd.direction = direction;
+
+	/***
+	 * Set up the command.
+	 ***/
+	switch (command) {
+	case CPIA2_CMD_GET_VERSION:
+		cmd.req_mode =
+		    CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+		cmd.start = CPIA2_SYSTEM_DEVICE_HI;
+		break;
+	case CPIA2_CMD_GET_PNP_ID:
+		cmd.req_mode =
+		    CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+		cmd.reg_count = 8;
+		cmd.start = CPIA2_SYSTEM_DESCRIP_VID_HI;
+		break;
+	case CPIA2_CMD_GET_ASIC_TYPE:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+		cmd.start = CPIA2_VC_ASIC_ID;
+		break;
+	case CPIA2_CMD_GET_SENSOR:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.start = CPIA2_VP_SENSOR_FLAGS;
+		break;
+	case CPIA2_CMD_GET_VP_DEVICE:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.start = CPIA2_VP_DEVICEH;
+		break;
+	case CPIA2_CMD_SET_VP_BRIGHTNESS:
+		cmd.buffer.block_data[0] = param;	/* Then fall through */
+	case CPIA2_CMD_GET_VP_BRIGHTNESS:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.reg_count = 1;
+		if (device == DEVICE_STV_672)
+			cmd.start = CPIA2_VP4_EXPOSURE_TARGET;
+		else
+			cmd.start = CPIA2_VP5_EXPOSURE_TARGET;
+		break;
+	case CPIA2_CMD_SET_CONTRAST:
+		cmd.buffer.block_data[0] = param;	/* Then fall through */
+	case CPIA2_CMD_GET_CONTRAST:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_VP_YRANGE;
+		break;
+	case CPIA2_CMD_SET_VP_SATURATION:
+		cmd.buffer.block_data[0] = param;	/* Then fall through */
+	case CPIA2_CMD_GET_VP_SATURATION:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.reg_count = 1;
+		if (device == DEVICE_STV_672)
+			cmd.start = CPIA2_VP_SATURATION;
+		else
+			cmd.start = CPIA2_VP5_MCUVSATURATION;
+		break;
+	case CPIA2_CMD_SET_VP_GPIO_DATA:
+		cmd.buffer.block_data[0] = param;	/* Then fall through */
+	case CPIA2_CMD_GET_VP_GPIO_DATA:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_VP_GPIO_DATA;
+		break;
+	case CPIA2_CMD_SET_VP_GPIO_DIRECTION:
+		cmd.buffer.block_data[0] = param;	/* Then fall through */
+	case CPIA2_CMD_GET_VP_GPIO_DIRECTION:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_VP_GPIO_DIRECTION;
+		break;
+	case CPIA2_CMD_SET_VC_MP_GPIO_DATA:
+		cmd.buffer.block_data[0] = param;	/* Then fall through */
+	case CPIA2_CMD_GET_VC_MP_GPIO_DATA:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_VC_MP_DATA;
+		break;
+	case CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION:
+		cmd.buffer.block_data[0] = param;	/* Then fall through */
+	case CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_VC_MP_DIR;
+		break;
+	case CPIA2_CMD_ENABLE_PACKET_CTRL:
+		cmd.req_mode =
+		    CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+		cmd.start = CPIA2_SYSTEM_INT_PACKET_CTRL;
+		cmd.reg_count = 1;
+		cmd.buffer.block_data[0] = param;
+		break;
+	case CPIA2_CMD_SET_FLICKER_MODES:
+		cmd.buffer.block_data[0] = param;	/* Then fall through */
+	case CPIA2_CMD_GET_FLICKER_MODES:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_VP_FLICKER_MODES;
+		break;
+	case CPIA2_CMD_RESET_FIFO:	/* clear fifo and enable stream block */
+		cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
+		cmd.reg_count = 2;
+		cmd.start = 0;
+		cmd.buffer.registers[0].index = CPIA2_VC_ST_CTRL;
+		cmd.buffer.registers[0].value = CPIA2_VC_ST_CTRL_SRC_VC |
+		    CPIA2_VC_ST_CTRL_DST_USB | CPIA2_VC_ST_CTRL_EOF_DETECT;
+		cmd.buffer.registers[1].index = CPIA2_VC_ST_CTRL;
+		cmd.buffer.registers[1].value = CPIA2_VC_ST_CTRL_SRC_VC |
+		    CPIA2_VC_ST_CTRL_DST_USB |
+		    CPIA2_VC_ST_CTRL_EOF_DETECT |
+		    CPIA2_VC_ST_CTRL_FIFO_ENABLE;
+		break;
+	case CPIA2_CMD_SET_HI_POWER:
+		cmd.req_mode =
+		    CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_SYSTEM;
+		cmd.reg_count = 2;
+		cmd.buffer.registers[0].index =
+		    CPIA2_SYSTEM_SYSTEM_CONTROL;
+		cmd.buffer.registers[1].index =
+		    CPIA2_SYSTEM_SYSTEM_CONTROL;
+		cmd.buffer.registers[0].value = CPIA2_SYSTEM_CONTROL_CLEAR_ERR;
+		cmd.buffer.registers[1].value =
+		    CPIA2_SYSTEM_CONTROL_HIGH_POWER;
+		break;
+	case CPIA2_CMD_SET_LOW_POWER:
+		cmd.req_mode =
+		    CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL;
+		cmd.buffer.block_data[0] = 0;
+		break;
+	case CPIA2_CMD_CLEAR_V2W_ERR:
+		cmd.req_mode =
+		    CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL;
+		cmd.buffer.block_data[0] = CPIA2_SYSTEM_CONTROL_CLEAR_ERR;
+		break;
+	case CPIA2_CMD_SET_USER_MODE:   /* Then fall through */
+		cmd.buffer.block_data[0] = param;
+	case CPIA2_CMD_GET_USER_MODE:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.reg_count = 1;
+		if (device == DEVICE_STV_672)
+			cmd.start = CPIA2_VP4_USER_MODE;
+		else
+			cmd.start = CPIA2_VP5_USER_MODE;
+		break;
+	case CPIA2_CMD_FRAMERATE_REQ:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.reg_count = 1;
+		if (device == DEVICE_STV_672)
+			cmd.start = CPIA2_VP4_FRAMERATE_REQUEST;
+		else
+			cmd.start = CPIA2_VP5_FRAMERATE_REQUEST;
+		cmd.buffer.block_data[0] = param;
+		break;
+	case CPIA2_CMD_SET_WAKEUP:
+		cmd.buffer.block_data[0] = param;	/* Then fall through */
+	case CPIA2_CMD_GET_WAKEUP:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_VC_WAKEUP;
+		break;
+	case CPIA2_CMD_SET_PW_CONTROL:
+		cmd.buffer.block_data[0] = param;	/* Then fall through */
+	case CPIA2_CMD_GET_PW_CONTROL:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_VC_PW_CTRL;
+		break;
+	case CPIA2_CMD_GET_VP_SYSTEM_STATE:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_VP_SYSTEMSTATE;
+		break;
+	case CPIA2_CMD_SET_SYSTEM_CTRL:
+		cmd.buffer.block_data[0] = param;	/* Then fall through */
+	case CPIA2_CMD_GET_SYSTEM_CTRL:
+		cmd.req_mode =
+		    CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL;
+		break;
+	case CPIA2_CMD_SET_VP_SYSTEM_CTRL:
+		cmd.buffer.block_data[0] = param;	/* Then fall through */
+	case CPIA2_CMD_GET_VP_SYSTEM_CTRL:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_VP_SYSTEMCTRL;
+		break;
+	case CPIA2_CMD_SET_VP_EXP_MODES:
+		cmd.buffer.block_data[0] = param;	/* Then fall through */
+	case CPIA2_CMD_GET_VP_EXP_MODES:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_VP_EXPOSURE_MODES;
+		break;
+	case CPIA2_CMD_SET_DEVICE_CONFIG:
+		cmd.buffer.block_data[0] = param;	/* Then fall through */
+	case CPIA2_CMD_GET_DEVICE_CONFIG:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_VP_DEVICE_CONFIG;
+		break;
+	case CPIA2_CMD_SET_SERIAL_ADDR:
+		cmd.buffer.block_data[0] = param;
+		cmd.req_mode =
+		    CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_SYSTEM_VP_SERIAL_ADDR;
+		break;
+	case CPIA2_CMD_SET_SENSOR_CR1:
+		cmd.buffer.block_data[0] = param;
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_SENSOR_CR1;
+		break;
+	case CPIA2_CMD_SET_VC_CONTROL:
+		cmd.buffer.block_data[0] = param;	/* Then fall through */
+	case CPIA2_CMD_GET_VC_CONTROL:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_VC_VC_CTRL;
+		break;
+	case CPIA2_CMD_SET_TARGET_KB:
+		cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
+		cmd.reg_count = 1;
+		cmd.buffer.registers[0].index = CPIA2_VC_VC_TARGET_KB;
+		cmd.buffer.registers[0].value = param;
+		break;
+	case CPIA2_CMD_SET_DEF_JPEG_OPT:
+		cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
+		cmd.reg_count = 4;
+		cmd.buffer.registers[0].index = CPIA2_VC_VC_JPEG_OPT;
+		cmd.buffer.registers[0].value =
+		    CPIA2_VC_VC_JPEG_OPT_DOUBLE_SQUEEZE;
+		cmd.buffer.registers[1].index = CPIA2_VC_VC_USER_SQUEEZE;
+		cmd.buffer.registers[1].value = 20;
+		cmd.buffer.registers[2].index = CPIA2_VC_VC_CREEP_PERIOD;
+		cmd.buffer.registers[2].value = 2;
+		cmd.buffer.registers[3].index = CPIA2_VC_VC_JPEG_OPT;
+		cmd.buffer.registers[3].value = CPIA2_VC_VC_JPEG_OPT_DEFAULT;
+		break;
+	case CPIA2_CMD_REHASH_VP4:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_VP_REHASH_VALUES;
+		cmd.buffer.block_data[0] = param;
+		break;
+	case CPIA2_CMD_SET_USER_EFFECTS:  /* Note: Be careful with this as
+					     this register can also affect
+					     flicker modes */
+		cmd.buffer.block_data[0] = param;      /* Then fall through */
+	case CPIA2_CMD_GET_USER_EFFECTS:
+		cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+		cmd.reg_count = 1;
+		if (device == DEVICE_STV_672)
+			cmd.start = CPIA2_VP4_USER_EFFECTS;
+		else
+			cmd.start = CPIA2_VP5_USER_EFFECTS;
+		break;
+	default:
+		LOG("DoCommand received invalid command\n");
+		return -EINVAL;
+	}
+
+	retval = cpia2_send_command(cam, &cmd);
+	if (retval) {
+		return retval;
+	}
+
+	/***
+	 * Now copy any results from a read into the appropriate param struct.
+	 ***/
+	switch (command) {
+	case CPIA2_CMD_GET_VERSION:
+		cam->params.version.firmware_revision_hi =
+		    cmd.buffer.block_data[0];
+		cam->params.version.firmware_revision_lo =
+		    cmd.buffer.block_data[1];
+		break;
+	case CPIA2_CMD_GET_PNP_ID:
+		cam->params.pnp_id.vendor = (cmd.buffer.block_data[0] << 8) |
+					    cmd.buffer.block_data[1];
+		cam->params.pnp_id.product = (cmd.buffer.block_data[2] << 8) |
+					     cmd.buffer.block_data[3];
+		cam->params.pnp_id.device_revision =
+			(cmd.buffer.block_data[4] << 8) |
+			cmd.buffer.block_data[5];
+		if (cam->params.pnp_id.vendor == 0x553) {
+			if (cam->params.pnp_id.product == 0x100) {
+				cam->params.pnp_id.device_type = DEVICE_STV_672;
+			} else if (cam->params.pnp_id.product == 0x140 ||
+				   cam->params.pnp_id.product == 0x151) {
+				cam->params.pnp_id.device_type = DEVICE_STV_676;
+			}
+		}
+		break;
+	case CPIA2_CMD_GET_ASIC_TYPE:
+		cam->params.version.asic_id = cmd.buffer.block_data[0];
+		cam->params.version.asic_rev = cmd.buffer.block_data[1];
+		break;
+	case CPIA2_CMD_GET_SENSOR:
+		cam->params.version.sensor_flags = cmd.buffer.block_data[0];
+		cam->params.version.sensor_rev = cmd.buffer.block_data[1];
+		break;
+	case CPIA2_CMD_GET_VP_DEVICE:
+		cam->params.version.vp_device_hi = cmd.buffer.block_data[0];
+		cam->params.version.vp_device_lo = cmd.buffer.block_data[1];
+		break;
+	case CPIA2_CMD_GET_VP_BRIGHTNESS:
+		cam->params.color_params.brightness = cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_CONTRAST:
+		cam->params.color_params.contrast = cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_VP_SATURATION:
+		cam->params.color_params.saturation = cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_VP_GPIO_DATA:
+		cam->params.vp_params.gpio_data = cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_VP_GPIO_DIRECTION:
+		cam->params.vp_params.gpio_direction = cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION:
+		cam->params.vc_params.vc_mp_direction =cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_VC_MP_GPIO_DATA:
+		cam->params.vc_params.vc_mp_data = cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_FLICKER_MODES:
+		cam->params.flicker_control.cam_register =
+			cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_WAKEUP:
+		cam->params.vc_params.wakeup = cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_PW_CONTROL:
+		cam->params.vc_params.pw_control = cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_SYSTEM_CTRL:
+		cam->params.camera_state.system_ctrl = cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_VP_SYSTEM_STATE:
+		cam->params.vp_params.system_state = cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_VP_SYSTEM_CTRL:
+		cam->params.vp_params.system_ctrl = cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_VP_EXP_MODES:
+		cam->params.vp_params.exposure_modes = cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_DEVICE_CONFIG:
+		cam->params.vp_params.device_config = cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_VC_CONTROL:
+		cam->params.vc_params.vc_control = cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_USER_MODE:
+		cam->params.vp_params.video_mode = cmd.buffer.block_data[0];
+		break;
+	case CPIA2_CMD_GET_USER_EFFECTS:
+		cam->params.vp_params.user_effects = cmd.buffer.block_data[0];
+		break;
+	default:
+		break;
+	}
+	return retval;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_send_command
+ *
+ *****************************************************************************/
+int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd)
+{
+	u8 count;
+	u8 start;
+	u8 block_index;
+	u8 *buffer;
+	int retval;
+	const char* dir;
+
+	if (cmd->direction == TRANSFER_WRITE) {
+		dir = "Write";
+	} else {
+		dir = "Read";
+	}
+
+	block_index = cmd->req_mode & 0x03;
+
+	switch (cmd->req_mode & 0x0c) {
+	case CAMERAACCESS_TYPE_RANDOM:
+		count = cmd->reg_count * sizeof(struct cpia2_register);
+		start = 0;
+		buffer = (u8 *) & cmd->buffer;
+		if (debugs_on & DEBUG_REG)
+			DBG("%s Random: Register block %s\n", dir,
+			    block_name[block_index]);
+		break;
+	case CAMERAACCESS_TYPE_BLOCK:
+		count = cmd->reg_count;
+		start = cmd->start;
+		buffer = cmd->buffer.block_data;
+		if (debugs_on & DEBUG_REG)
+			DBG("%s Block: Register block %s\n", dir,
+			    block_name[block_index]);
+		break;
+	case CAMERAACCESS_TYPE_MASK:
+		count = cmd->reg_count * sizeof(struct cpia2_reg_mask);
+		start = 0;
+		buffer = (u8 *) & cmd->buffer;
+		if (debugs_on & DEBUG_REG)
+			DBG("%s Mask: Register block %s\n", dir,
+			    block_name[block_index]);
+		break;
+	case CAMERAACCESS_TYPE_REPEAT:	/* For patch blocks only */
+		count = cmd->reg_count;
+		start = cmd->start;
+		buffer = cmd->buffer.block_data;
+		if (debugs_on & DEBUG_REG)
+			DBG("%s Repeat: Register block %s\n", dir,
+			    block_name[block_index]);
+		break;
+	default:
+		LOG("%s: invalid request mode\n",__FUNCTION__);
+		return -EINVAL;
+	}
+
+	retval = cpia2_usb_transfer_cmd(cam,
+					buffer,
+					cmd->req_mode,
+					start, count, cmd->direction);
+#ifdef _CPIA2_DEBUG_
+	if (debugs_on & DEBUG_REG) {
+		int i;
+		for (i = 0; i < cmd->reg_count; i++) {
+			if((cmd->req_mode & 0x0c) == CAMERAACCESS_TYPE_BLOCK)
+				KINFO("%s Block: [0x%02X] = 0x%02X\n",
+				    dir, start + i, buffer[i]);
+			if((cmd->req_mode & 0x0c) == CAMERAACCESS_TYPE_RANDOM)
+				KINFO("%s Random: [0x%02X] = 0x%02X\n",
+				    dir, cmd->buffer.registers[i].index,
+				    cmd->buffer.registers[i].value);
+		}
+	}
+#endif
+
+	return retval;
+};
+
+/*************
+ * Functions to implement camera functionality
+ *************/
+/******************************************************************************
+ *
+ *  cpia2_get_version_info
+ *
+ *****************************************************************************/
+static void cpia2_get_version_info(struct camera_data *cam)
+{
+	cpia2_do_command(cam, CPIA2_CMD_GET_VERSION, TRANSFER_READ, 0);
+	cpia2_do_command(cam, CPIA2_CMD_GET_PNP_ID, TRANSFER_READ, 0);
+	cpia2_do_command(cam, CPIA2_CMD_GET_ASIC_TYPE, TRANSFER_READ, 0);
+	cpia2_do_command(cam, CPIA2_CMD_GET_SENSOR, TRANSFER_READ, 0);
+	cpia2_do_command(cam, CPIA2_CMD_GET_VP_DEVICE, TRANSFER_READ, 0);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_reset_camera
+ *
+ *  Called at least during the open process, sets up initial params.
+ *****************************************************************************/
+int cpia2_reset_camera(struct camera_data *cam)
+{
+	u8 tmp_reg;
+	int retval = 0;
+	int i;
+	struct cpia2_command cmd;
+
+	/***
+	 * VC setup
+	 ***/
+	retval = configure_sensor(cam,
+				  cam->params.roi.width,
+				  cam->params.roi.height);
+	if (retval < 0) {
+		ERR("Couldn't configure sensor, error=%d\n", retval);
+		return retval;
+	}
+
+	/* Clear FIFO and route/enable stream block */
+	cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
+	cmd.direction = TRANSFER_WRITE;
+	cmd.reg_count = 2;
+	cmd.buffer.registers[0].index = CPIA2_VC_ST_CTRL;
+	cmd.buffer.registers[0].value = CPIA2_VC_ST_CTRL_SRC_VC |
+		CPIA2_VC_ST_CTRL_DST_USB | CPIA2_VC_ST_CTRL_EOF_DETECT;
+	cmd.buffer.registers[1].index = CPIA2_VC_ST_CTRL;
+	cmd.buffer.registers[1].value = CPIA2_VC_ST_CTRL_SRC_VC |
+		CPIA2_VC_ST_CTRL_DST_USB |
+		CPIA2_VC_ST_CTRL_EOF_DETECT | CPIA2_VC_ST_CTRL_FIFO_ENABLE;
+
+	cpia2_send_command(cam, &cmd);
+
+	cpia2_set_high_power(cam);
+
+	if (cam->params.pnp_id.device_type == DEVICE_STV_672) {
+		/* Enable button notification */
+		cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_SYSTEM;
+		cmd.buffer.registers[0].index = CPIA2_SYSTEM_INT_PACKET_CTRL;
+		cmd.buffer.registers[0].value =
+			CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_SW_XX;
+		cmd.reg_count = 1;
+		cpia2_send_command(cam, &cmd);
+	}
+
+	current->state = TASK_INTERRUPTIBLE;
+	schedule_timeout(100 * HZ / 1000);	/* wait for 100 msecs */
+
+	if (cam->params.pnp_id.device_type == DEVICE_STV_672)
+		retval = apply_vp_patch(cam);
+
+	/* wait for vp to go to sleep */
+	current->state = TASK_INTERRUPTIBLE;
+	schedule_timeout(100 * HZ / 1000);	/* wait for 100 msecs */
+
+	/***
+	 * If this is a 676, apply VP5 fixes before we start streaming
+	 ***/
+	if (cam->params.pnp_id.device_type == DEVICE_STV_676) {
+		cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP;
+
+		/* The following writes improve the picture */
+		cmd.buffer.registers[0].index = CPIA2_VP5_MYBLACK_LEVEL;
+		cmd.buffer.registers[0].value = 0; /* reduce from the default
+						    * rec 601 pedestal of 16 */
+		cmd.buffer.registers[1].index = CPIA2_VP5_MCYRANGE;
+		cmd.buffer.registers[1].value = 0x92; /* increase from 100% to
+						       * (256/256 - 31) to fill
+						       * available range */
+		cmd.buffer.registers[2].index = CPIA2_VP5_MYCEILING;
+		cmd.buffer.registers[2].value = 0xFF; /* Increase from the
+						       * default rec 601 ceiling
+						       * of 240 */
+		cmd.buffer.registers[3].index = CPIA2_VP5_MCUVSATURATION;
+		cmd.buffer.registers[3].value = 0xFF; /* Increase from the rec
+						       * 601 100% level (128)
+						       * to 145-192 */
+		cmd.buffer.registers[4].index = CPIA2_VP5_ANTIFLKRSETUP;
+		cmd.buffer.registers[4].value = 0x80;  /* Inhibit the
+							* anti-flicker */
+
+		/* The following 4 writes are a fix to allow QVGA to work at 30 fps */
+		cmd.buffer.registers[5].index = CPIA2_VP_RAM_ADDR_H;
+		cmd.buffer.registers[5].value = 0x01;
+		cmd.buffer.registers[6].index = CPIA2_VP_RAM_ADDR_L;
+		cmd.buffer.registers[6].value = 0xE3;
+		cmd.buffer.registers[7].index = CPIA2_VP_RAM_DATA;
+		cmd.buffer.registers[7].value = 0x02;
+		cmd.buffer.registers[8].index = CPIA2_VP_RAM_DATA;
+		cmd.buffer.registers[8].value = 0xFC;
+
+		cmd.direction = TRANSFER_WRITE;
+		cmd.reg_count = 9;
+
+		cpia2_send_command(cam, &cmd);
+	}
+
+	/* Activate all settings and start the data stream */
+	/* Set user mode */
+	set_default_user_mode(cam);
+
+	/* Give VP time to wake up */
+	current->state = TASK_INTERRUPTIBLE;
+	schedule_timeout(100 * HZ / 1000);	/* wait for 100 msecs */
+
+	set_all_properties(cam);
+
+	cpia2_do_command(cam, CPIA2_CMD_GET_USER_MODE, TRANSFER_READ, 0);
+	DBG("After SetAllProperties(cam), user mode is 0x%0X\n",
+	    cam->params.vp_params.video_mode);
+
+	/***
+	 * Set audio regulator off.  This and the code to set the compresison
+	 * state are too complex to form a CPIA2_CMD_, and seem to be somewhat
+	 * intertwined.  This stuff came straight from the windows driver.
+	 ***/
+	/* Turn AutoExposure off in VP and enable the serial bridge to the sensor */
+	cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_CTRL, TRANSFER_READ, 0);
+	tmp_reg = cam->params.vp_params.system_ctrl;
+	cmd.buffer.registers[0].value = tmp_reg &
+		(tmp_reg & (CPIA2_VP_SYSTEMCTRL_HK_CONTROL ^ 0xFF));
+
+	cpia2_do_command(cam, CPIA2_CMD_GET_DEVICE_CONFIG, TRANSFER_READ, 0);
+	cmd.buffer.registers[1].value = cam->params.vp_params.device_config |
+					CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE;
+	cmd.buffer.registers[0].index = CPIA2_VP_SYSTEMCTRL;
+	cmd.buffer.registers[1].index = CPIA2_VP_DEVICE_CONFIG;
+	cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP;
+	cmd.reg_count = 2;
+	cmd.direction = TRANSFER_WRITE;
+	cmd.start = 0;
+	cpia2_send_command(cam, &cmd);
+
+	/* Set the correct I2C address in the CPiA-2 system register */
+	cpia2_do_command(cam,
+			 CPIA2_CMD_SET_SERIAL_ADDR,
+			 TRANSFER_WRITE,
+			 CPIA2_SYSTEM_VP_SERIAL_ADDR_SENSOR);
+
+	/* Now have sensor access - set bit to turn the audio regulator off */
+	cpia2_do_command(cam,
+			 CPIA2_CMD_SET_SENSOR_CR1,
+			 TRANSFER_WRITE, CPIA2_SENSOR_CR1_DOWN_AUDIO_REGULATOR);
+
+	/* Set the correct I2C address in the CPiA-2 system register */
+	if (cam->params.pnp_id.device_type == DEVICE_STV_672)
+		cpia2_do_command(cam,
+				 CPIA2_CMD_SET_SERIAL_ADDR,
+				 TRANSFER_WRITE,
+				 CPIA2_SYSTEM_VP_SERIAL_ADDR_VP); // 0x88
+	else
+		cpia2_do_command(cam,
+				 CPIA2_CMD_SET_SERIAL_ADDR,
+				 TRANSFER_WRITE,
+				 CPIA2_SYSTEM_VP_SERIAL_ADDR_676_VP); // 0x8a
+
+	/* increase signal drive strength */
+	if (cam->params.pnp_id.device_type == DEVICE_STV_676)
+		cpia2_do_command(cam,
+				 CPIA2_CMD_SET_VP_EXP_MODES,
+				 TRANSFER_WRITE,
+				 CPIA2_VP_EXPOSURE_MODES_COMPILE_EXP);
+
+	/* Start autoexposure */
+	cpia2_do_command(cam, CPIA2_CMD_GET_DEVICE_CONFIG, TRANSFER_READ, 0);
+	cmd.buffer.registers[0].value = cam->params.vp_params.device_config &
+				  (CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE ^ 0xFF);
+
+	cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_CTRL, TRANSFER_READ, 0);
+	cmd.buffer.registers[1].value =
+	    cam->params.vp_params.system_ctrl | CPIA2_VP_SYSTEMCTRL_HK_CONTROL;
+
+	cmd.buffer.registers[0].index = CPIA2_VP_DEVICE_CONFIG;
+	cmd.buffer.registers[1].index = CPIA2_VP_SYSTEMCTRL;
+	cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP;
+	cmd.reg_count = 2;
+	cmd.direction = TRANSFER_WRITE;
+
+	cpia2_send_command(cam, &cmd);
+
+	/* Set compression state */
+	cpia2_do_command(cam, CPIA2_CMD_GET_VC_CONTROL, TRANSFER_READ, 0);
+	if (cam->params.compression.inhibit_htables) {
+		tmp_reg = cam->params.vc_params.vc_control |
+			  CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES;
+	} else  {
+		tmp_reg = cam->params.vc_params.vc_control &
+			  ~CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES;
+	}
+	cpia2_do_command(cam, CPIA2_CMD_SET_VC_CONTROL, TRANSFER_WRITE,tmp_reg);
+
+	/* Set target size (kb) on vc */
+	cpia2_do_command(cam, CPIA2_CMD_SET_TARGET_KB,
+			 TRANSFER_WRITE, cam->params.vc_params.target_kb);
+
+	/* Wiggle VC Reset */
+	/***
+	 * First read and wait a bit.
+	 ***/
+	for (i = 0; i < 50; i++) {
+		cpia2_do_command(cam, CPIA2_CMD_GET_PW_CONTROL,
+				 TRANSFER_READ, 0);
+	}
+
+	tmp_reg = cam->params.vc_params.pw_control;
+	tmp_reg &= ~CPIA2_VC_PW_CTRL_VC_RESET_N;
+
+	cpia2_do_command(cam, CPIA2_CMD_SET_PW_CONTROL, TRANSFER_WRITE,tmp_reg);
+
+	tmp_reg |= CPIA2_VC_PW_CTRL_VC_RESET_N;
+	cpia2_do_command(cam, CPIA2_CMD_SET_PW_CONTROL, TRANSFER_WRITE,tmp_reg);
+
+	cpia2_do_command(cam, CPIA2_CMD_SET_DEF_JPEG_OPT, TRANSFER_WRITE, 0);
+
+	cpia2_do_command(cam, CPIA2_CMD_GET_USER_MODE, TRANSFER_READ, 0);
+	DBG("After VC RESET, user mode is 0x%0X\n",
+	    cam->params.vp_params.video_mode);
+
+	return retval;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_high_power
+ *
+ *****************************************************************************/
+static int cpia2_set_high_power(struct camera_data *cam)
+{
+	int i;
+	for (i = 0; i <= 50; i++) {
+		/* Read system status */
+		cpia2_do_command(cam,CPIA2_CMD_GET_SYSTEM_CTRL,TRANSFER_READ,0);
+
+		/* If there is an error, clear it */
+		if(cam->params.camera_state.system_ctrl &
+		   CPIA2_SYSTEM_CONTROL_V2W_ERR)
+			cpia2_do_command(cam, CPIA2_CMD_CLEAR_V2W_ERR,
+					 TRANSFER_WRITE, 0);
+
+		/* Try to set high power mode */
+		cpia2_do_command(cam, CPIA2_CMD_SET_SYSTEM_CTRL,
+				 TRANSFER_WRITE, 1);
+
+		/* Try to read something in VP to check if everything is awake */
+		cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_STATE,
+				 TRANSFER_READ, 0);
+		if (cam->params.vp_params.system_state &
+		    CPIA2_VP_SYSTEMSTATE_HK_ALIVE) {
+			break;
+		} else if (i == 50) {
+			cam->params.camera_state.power_mode = LO_POWER_MODE;
+			ERR("Camera did not wake up\n");
+			return -EIO;
+		}
+	}
+
+	DBG("System now in high power state\n");
+	cam->params.camera_state.power_mode = HI_POWER_MODE;
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_low_power
+ *
+ *****************************************************************************/
+int cpia2_set_low_power(struct camera_data *cam)
+{
+	cam->params.camera_state.power_mode = LO_POWER_MODE;
+	cpia2_do_command(cam, CPIA2_CMD_SET_SYSTEM_CTRL, TRANSFER_WRITE, 0);
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  apply_vp_patch
+ *
+ *****************************************************************************/
+static int apply_vp_patch(struct camera_data *cam)
+{
+	int i, j;
+	struct cpia2_command cmd;
+
+	cmd.req_mode = CAMERAACCESS_TYPE_REPEAT | CAMERAACCESS_VP;
+	cmd.direction = TRANSFER_WRITE;
+
+	for (i = 0; i < PATCH_DATA_SIZE; i++) {
+		for (j = 0; j < patch_data[i].count; j++) {
+			cmd.buffer.block_data[j] = patch_data[i].data[j];
+		}
+
+		cmd.start = patch_data[i].reg;
+		cmd.reg_count = patch_data[i].count;
+		cpia2_send_command(cam, &cmd);
+	}
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  set_default_user_mode
+ *
+ *****************************************************************************/
+static int set_default_user_mode(struct camera_data *cam)
+{
+	unsigned char user_mode;
+	unsigned char frame_rate;
+	int width = cam->params.roi.width;
+	int height = cam->params.roi.height;
+
+	switch (cam->params.version.sensor_flags) {
+	case CPIA2_VP_SENSOR_FLAGS_404:
+	case CPIA2_VP_SENSOR_FLAGS_407:
+	case CPIA2_VP_SENSOR_FLAGS_409:
+	case CPIA2_VP_SENSOR_FLAGS_410:
+		if ((width > STV_IMAGE_QCIF_COLS)
+		    || (height > STV_IMAGE_QCIF_ROWS)) {
+			user_mode = CPIA2_VP_USER_MODE_CIF;
+		} else {
+			user_mode = CPIA2_VP_USER_MODE_QCIFDS;
+		}
+		frame_rate = CPIA2_VP_FRAMERATE_30;
+		break;
+	case CPIA2_VP_SENSOR_FLAGS_500:
+		if ((width > STV_IMAGE_CIF_COLS)
+		    || (height > STV_IMAGE_CIF_ROWS)) {
+			user_mode = CPIA2_VP_USER_MODE_VGA;
+		} else {
+			user_mode = CPIA2_VP_USER_MODE_QVGADS;
+		}
+		if (cam->params.pnp_id.device_type == DEVICE_STV_672)
+			frame_rate = CPIA2_VP_FRAMERATE_15;
+		else
+			frame_rate = CPIA2_VP_FRAMERATE_30;
+		break;
+	default:
+		LOG("%s: Invalid sensor flag value 0x%0X\n",__FUNCTION__,
+		    cam->params.version.sensor_flags);
+		return -EINVAL;
+	}
+
+	DBG("Sensor flag = 0x%0x, user mode = 0x%0x, frame rate = 0x%X\n",
+	    cam->params.version.sensor_flags, user_mode, frame_rate);
+	cpia2_do_command(cam, CPIA2_CMD_SET_USER_MODE, TRANSFER_WRITE,
+			 user_mode);
+	if(cam->params.vp_params.frame_rate > 0 &&
+	   frame_rate > cam->params.vp_params.frame_rate)
+		frame_rate = cam->params.vp_params.frame_rate;
+
+	cpia2_set_fps(cam, frame_rate);
+
+//	if (cam->params.pnp_id.device_type == DEVICE_STV_676)
+//		cpia2_do_command(cam,
+//				 CPIA2_CMD_SET_VP_SYSTEM_CTRL,
+//				 TRANSFER_WRITE,
+//				 CPIA2_VP_SYSTEMCTRL_HK_CONTROL |
+//				 CPIA2_VP_SYSTEMCTRL_POWER_CONTROL);
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_match_video_size
+ *
+ *  return the best match, where 'best' is as always
+ *  the largest that is not bigger than what is requested.
+ *****************************************************************************/
+int cpia2_match_video_size(int width, int height)
+{
+	if (width >= STV_IMAGE_VGA_COLS && height >= STV_IMAGE_VGA_ROWS)
+		return VIDEOSIZE_VGA;
+
+	if (width >= STV_IMAGE_CIF_COLS && height >= STV_IMAGE_CIF_ROWS)
+		return VIDEOSIZE_CIF;
+
+	if (width >= STV_IMAGE_QVGA_COLS && height >= STV_IMAGE_QVGA_ROWS)
+		return VIDEOSIZE_QVGA;
+
+	if (width >= 288 && height >= 216)
+		return VIDEOSIZE_288_216;
+
+	if (width >= 256 && height >= 192)
+		return VIDEOSIZE_256_192;
+
+	if (width >= 224 && height >= 168)
+		return VIDEOSIZE_224_168;
+
+	if (width >= 192 && height >= 144)
+		return VIDEOSIZE_192_144;
+
+	if (width >= STV_IMAGE_QCIF_COLS && height >= STV_IMAGE_QCIF_ROWS)
+		return VIDEOSIZE_QCIF;
+
+	return -1;
+}
+
+/******************************************************************************
+ *
+ *  SetVideoSize
+ *
+ *****************************************************************************/
+static int set_vw_size(struct camera_data *cam, int size)
+{
+	int retval = 0;
+
+	cam->params.vp_params.video_size = size;
+
+	switch (size) {
+	case VIDEOSIZE_VGA:
+		DBG("Setting size to VGA\n");
+		cam->params.roi.width = STV_IMAGE_VGA_COLS;
+		cam->params.roi.height = STV_IMAGE_VGA_ROWS;
+		cam->vw.width = STV_IMAGE_VGA_COLS;
+		cam->vw.height = STV_IMAGE_VGA_ROWS;
+		break;
+	case VIDEOSIZE_CIF:
+		DBG("Setting size to CIF\n");
+		cam->params.roi.width = STV_IMAGE_CIF_COLS;
+		cam->params.roi.height = STV_IMAGE_CIF_ROWS;
+		cam->vw.width = STV_IMAGE_CIF_COLS;
+		cam->vw.height = STV_IMAGE_CIF_ROWS;
+		break;
+	case VIDEOSIZE_QVGA:
+		DBG("Setting size to QVGA\n");
+		cam->params.roi.width = STV_IMAGE_QVGA_COLS;
+		cam->params.roi.height = STV_IMAGE_QVGA_ROWS;
+		cam->vw.width = STV_IMAGE_QVGA_COLS;
+		cam->vw.height = STV_IMAGE_QVGA_ROWS;
+		break;
+	case VIDEOSIZE_288_216:
+		cam->params.roi.width = 288;
+		cam->params.roi.height = 216;
+		cam->vw.width = 288;
+		cam->vw.height = 216;
+		break;
+	case VIDEOSIZE_256_192:
+		cam->vw.width = 256;
+		cam->vw.height = 192;
+		cam->params.roi.width = 256;
+		cam->params.roi.height = 192;
+		break;
+	case VIDEOSIZE_224_168:
+		cam->vw.width = 224;
+		cam->vw.height = 168;
+		cam->params.roi.width = 224;
+		cam->params.roi.height = 168;
+		break;
+	case VIDEOSIZE_192_144:
+		cam->vw.width = 192;
+		cam->vw.height = 144;
+		cam->params.roi.width = 192;
+		cam->params.roi.height = 144;
+		break;
+	case VIDEOSIZE_QCIF:
+		DBG("Setting size to QCIF\n");
+		cam->params.roi.width = STV_IMAGE_QCIF_COLS;
+		cam->params.roi.height = STV_IMAGE_QCIF_ROWS;
+		cam->vw.width = STV_IMAGE_QCIF_COLS;
+		cam->vw.height = STV_IMAGE_QCIF_ROWS;
+		break;
+	default:
+		retval = -EINVAL;
+	}
+	return retval;
+}
+
+/******************************************************************************
+ *
+ *  configure_sensor
+ *
+ *****************************************************************************/
+static int configure_sensor(struct camera_data *cam,
+			    int req_width, int req_height)
+{
+	int retval;
+
+	switch (cam->params.version.sensor_flags) {
+	case CPIA2_VP_SENSOR_FLAGS_404:
+	case CPIA2_VP_SENSOR_FLAGS_407:
+	case CPIA2_VP_SENSOR_FLAGS_409:
+	case CPIA2_VP_SENSOR_FLAGS_410:
+		retval = config_sensor_410(cam, req_width, req_height);
+		break;
+	case CPIA2_VP_SENSOR_FLAGS_500:
+		retval = config_sensor_500(cam, req_width, req_height);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return retval;
+}
+
+/******************************************************************************
+ *
+ *  config_sensor_410
+ *
+ *****************************************************************************/
+static int config_sensor_410(struct camera_data *cam,
+			    int req_width, int req_height)
+{
+	struct cpia2_command cmd;
+	int i = 0;
+	int image_size;
+	int image_type;
+	int width = req_width;
+	int height = req_height;
+
+	/***
+	 *  Make sure size doesn't exceed CIF.
+	 ***/
+	if (width > STV_IMAGE_CIF_COLS)
+		width = STV_IMAGE_CIF_COLS;
+	if (height > STV_IMAGE_CIF_ROWS)
+		height = STV_IMAGE_CIF_ROWS;
+
+	image_size = cpia2_match_video_size(width, height);
+
+	DBG("Config 410: width = %d, height = %d\n", width, height);
+	DBG("Image size returned is %d\n", image_size);
+	if (image_size >= 0) {
+		set_vw_size(cam, image_size);
+		width = cam->params.roi.width;
+		height = cam->params.roi.height;
+
+		DBG("After set_vw_size(), width = %d, height = %d\n",
+		    width, height);
+		if (width <= 176 && height <= 144) {
+			DBG("image type = VIDEOSIZE_QCIF\n");
+			image_type = VIDEOSIZE_QCIF;
+		}
+		else if (width <= 320 && height <= 240) {
+			DBG("image type = VIDEOSIZE_QVGA\n");
+			image_type = VIDEOSIZE_QVGA;
+		}
+		else {
+			DBG("image type = VIDEOSIZE_CIF\n");
+			image_type = VIDEOSIZE_CIF;
+		}
+	} else {
+		ERR("ConfigSensor410 failed\n");
+		return -EINVAL;
+	}
+
+	cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
+	cmd.direction = TRANSFER_WRITE;
+
+	/* VC Format */
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_FORMAT;
+	if (image_type == VIDEOSIZE_CIF) {
+		cmd.buffer.registers[i++].value =
+		    (u8) (CPIA2_VC_VC_FORMAT_UFIRST |
+			  CPIA2_VC_VC_FORMAT_SHORTLINE);
+	} else {
+		cmd.buffer.registers[i++].value =
+		    (u8) CPIA2_VC_VC_FORMAT_UFIRST;
+	}
+
+	/* VC Clocks */
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_CLOCKS;
+	if (image_type == VIDEOSIZE_QCIF) {
+		if (cam->params.pnp_id.device_type == DEVICE_STV_672) {
+			cmd.buffer.registers[i++].value=
+				(u8)(CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3 |
+				     CPIA2_VC_VC_672_CLOCKS_SCALING |
+				     CPIA2_VC_VC_CLOCKS_LOGDIV2);
+			DBG("VC_Clocks (0xc4) should be B\n");
+		}
+		else {
+			cmd.buffer.registers[i++].value=
+				(u8)(CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3 |
+				     CPIA2_VC_VC_CLOCKS_LOGDIV2);
+		}
+	} else {
+		if (cam->params.pnp_id.device_type == DEVICE_STV_672) {
+			cmd.buffer.registers[i++].value =
+			   (u8) (CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3 |
+				 CPIA2_VC_VC_CLOCKS_LOGDIV0);
+		}
+		else {
+			cmd.buffer.registers[i++].value =
+			   (u8) (CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3 |
+				 CPIA2_VC_VC_676_CLOCKS_SCALING |
+				 CPIA2_VC_VC_CLOCKS_LOGDIV0);
+		}
+	}
+	DBG("VC_Clocks (0xc4) = 0x%0X\n", cmd.buffer.registers[i-1].value);
+
+	/* Input reqWidth from VC */
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_IHSIZE_LO;
+	if (image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i++].value =
+		    (u8) (STV_IMAGE_QCIF_COLS / 4);
+	else
+		cmd.buffer.registers[i++].value =
+		    (u8) (STV_IMAGE_CIF_COLS / 4);
+
+	/* Timings */
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_HI;
+	if (image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i++].value = (u8) 0;
+	else
+		cmd.buffer.registers[i++].value = (u8) 1;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_LO;
+	if (image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i++].value = (u8) 208;
+	else
+		cmd.buffer.registers[i++].value = (u8) 160;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_HI;
+	if (image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i++].value = (u8) 0;
+	else
+		cmd.buffer.registers[i++].value = (u8) 1;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_LO;
+	if (image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i++].value = (u8) 160;
+	else
+		cmd.buffer.registers[i++].value = (u8) 64;
+
+	/* Output Image Size */
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_OHSIZE;
+	cmd.buffer.registers[i++].value = cam->params.roi.width / 4;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_OVSIZE;
+	cmd.buffer.registers[i++].value = cam->params.roi.height / 4;
+
+	/* Cropping */
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_HCROP;
+	if (image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i++].value =
+		    (u8) (((STV_IMAGE_QCIF_COLS / 4) - (width / 4)) / 2);
+	else
+		cmd.buffer.registers[i++].value =
+		    (u8) (((STV_IMAGE_CIF_COLS / 4) - (width / 4)) / 2);
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_VCROP;
+	if (image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i++].value =
+		    (u8) (((STV_IMAGE_QCIF_ROWS / 4) - (height / 4)) / 2);
+	else
+		cmd.buffer.registers[i++].value =
+		    (u8) (((STV_IMAGE_CIF_ROWS / 4) - (height / 4)) / 2);
+
+	/* Scaling registers (defaults) */
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_HPHASE;
+	cmd.buffer.registers[i++].value = (u8) 0;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_VPHASE;
+	cmd.buffer.registers[i++].value = (u8) 0;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_HISPAN;
+	cmd.buffer.registers[i++].value = (u8) 31;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_VISPAN;
+	cmd.buffer.registers[i++].value = (u8) 31;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_HICROP;
+	cmd.buffer.registers[i++].value = (u8) 0;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_VICROP;
+	cmd.buffer.registers[i++].value = (u8) 0;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_HFRACT;
+	cmd.buffer.registers[i++].value = (u8) 0x81;	/* = 8/1 = 8 (HIBYTE/LOBYTE) */
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_VFRACT;
+	cmd.buffer.registers[i++].value = (u8) 0x81;	/* = 8/1 = 8 (HIBYTE/LOBYTE) */
+
+	cmd.reg_count = i;
+
+	cpia2_send_command(cam, &cmd);
+
+	return i;
+}
+
+
+/******************************************************************************
+ *
+ *  config_sensor_500(cam)
+ *
+ *****************************************************************************/
+static int config_sensor_500(struct camera_data *cam,
+			     int req_width, int req_height)
+{
+	struct cpia2_command cmd;
+	int i = 0;
+	int image_size = VIDEOSIZE_CIF;
+	int image_type = VIDEOSIZE_VGA;
+	int width = req_width;
+	int height = req_height;
+	unsigned int device = cam->params.pnp_id.device_type;
+
+	image_size = cpia2_match_video_size(width, height);
+
+	if (width > STV_IMAGE_CIF_COLS || height > STV_IMAGE_CIF_ROWS)
+		image_type = VIDEOSIZE_VGA;
+	else if (width > STV_IMAGE_QVGA_COLS || height > STV_IMAGE_QVGA_ROWS)
+		image_type = VIDEOSIZE_CIF;
+	else if (width > STV_IMAGE_QCIF_COLS || height > STV_IMAGE_QCIF_ROWS)
+		image_type = VIDEOSIZE_QVGA;
+	else
+		image_type = VIDEOSIZE_QCIF;
+
+	if (image_size >= 0) {
+		set_vw_size(cam, image_size);
+		width = cam->params.roi.width;
+		height = cam->params.roi.height;
+	} else {
+		ERR("ConfigSensor500 failed\n");
+		return -EINVAL;
+	}
+
+	DBG("image_size = %d, width = %d, height = %d, type = %d\n",
+	    image_size, width, height, image_type);
+
+	cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
+	cmd.direction = TRANSFER_WRITE;
+	i = 0;
+
+	/* VC Format */
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_FORMAT;
+	cmd.buffer.registers[i].value = (u8) CPIA2_VC_VC_FORMAT_UFIRST;
+	if (image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i].value |= (u8) CPIA2_VC_VC_FORMAT_DECIMATING;
+	i++;
+
+	/* VC Clocks */
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_CLOCKS;
+	if (device == DEVICE_STV_672) {
+		if (image_type == VIDEOSIZE_VGA)
+			cmd.buffer.registers[i].value =
+				(u8)CPIA2_VC_VC_CLOCKS_LOGDIV1;
+		else
+			cmd.buffer.registers[i].value =
+				(u8)(CPIA2_VC_VC_672_CLOCKS_SCALING |
+				     CPIA2_VC_VC_CLOCKS_LOGDIV3);
+	} else {
+		if (image_type == VIDEOSIZE_VGA)
+			cmd.buffer.registers[i].value =
+				(u8)CPIA2_VC_VC_CLOCKS_LOGDIV0;
+		else
+			cmd.buffer.registers[i].value =
+				(u8)(CPIA2_VC_VC_676_CLOCKS_SCALING |
+				     CPIA2_VC_VC_CLOCKS_LOGDIV2);
+	}
+	i++;
+
+	DBG("VC_CLOCKS = 0x%X\n", cmd.buffer.registers[i-1].value);
+
+	/* Input width from VP */
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_IHSIZE_LO;
+	if (image_type == VIDEOSIZE_VGA)
+		cmd.buffer.registers[i].value =
+		    (u8) (STV_IMAGE_VGA_COLS / 4);
+	else
+		cmd.buffer.registers[i].value =
+		    (u8) (STV_IMAGE_QVGA_COLS / 4);
+	i++;
+	DBG("Input width = %d\n", cmd.buffer.registers[i-1].value);
+
+	/* Timings */
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_HI;
+	if (image_type == VIDEOSIZE_VGA)
+		cmd.buffer.registers[i++].value = (u8) 2;
+	else
+		cmd.buffer.registers[i++].value = (u8) 1;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_LO;
+	if (image_type == VIDEOSIZE_VGA)
+		cmd.buffer.registers[i++].value = (u8) 250;
+	else if (image_type == VIDEOSIZE_QVGA)
+		cmd.buffer.registers[i++].value = (u8) 125;
+	else
+		cmd.buffer.registers[i++].value = (u8) 160;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_HI;
+	if (image_type == VIDEOSIZE_VGA)
+		cmd.buffer.registers[i++].value = (u8) 2;
+	else
+		cmd.buffer.registers[i++].value = (u8) 1;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_LO;
+	if (image_type == VIDEOSIZE_VGA)
+		cmd.buffer.registers[i++].value = (u8) 12;
+	else if (image_type == VIDEOSIZE_QVGA)
+		cmd.buffer.registers[i++].value = (u8) 64;
+	else
+		cmd.buffer.registers[i++].value = (u8) 6;
+
+	/* Output Image Size */
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_OHSIZE;
+	if (image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i++].value = STV_IMAGE_CIF_COLS  / 4;
+	else
+		cmd.buffer.registers[i++].value = width / 4;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_OVSIZE;
+	if (image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i++].value = STV_IMAGE_CIF_ROWS  / 4;
+	else
+		cmd.buffer.registers[i++].value = height / 4;
+
+	/* Cropping */
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_HCROP;
+	if (image_type == VIDEOSIZE_VGA)
+		cmd.buffer.registers[i++].value =
+		    (u8) (((STV_IMAGE_VGA_COLS / 4) - (width / 4)) / 2);
+	else if (image_type == VIDEOSIZE_QVGA)
+		cmd.buffer.registers[i++].value =
+		    (u8) (((STV_IMAGE_QVGA_COLS / 4) - (width / 4)) / 2);
+	else if (image_type == VIDEOSIZE_CIF)
+		cmd.buffer.registers[i++].value =
+		    (u8) (((STV_IMAGE_CIF_COLS / 4) - (width / 4)) / 2);
+	else /*if (image_type == VIDEOSIZE_QCIF)*/
+		cmd.buffer.registers[i++].value =
+			(u8) (((STV_IMAGE_QCIF_COLS / 4) - (width / 4)) / 2);
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_VCROP;
+	if (image_type == VIDEOSIZE_VGA)
+		cmd.buffer.registers[i++].value =
+		    (u8) (((STV_IMAGE_VGA_ROWS / 4) - (height / 4)) / 2);
+	else if (image_type == VIDEOSIZE_QVGA)
+		cmd.buffer.registers[i++].value =
+		    (u8) (((STV_IMAGE_QVGA_ROWS / 4) - (height / 4)) / 2);
+	else if (image_type == VIDEOSIZE_CIF)
+		cmd.buffer.registers[i++].value =
+		    (u8) (((STV_IMAGE_CIF_ROWS / 4) - (height / 4)) / 2);
+	else /*if (image_type == VIDEOSIZE_QCIF)*/
+		cmd.buffer.registers[i++].value =
+		    (u8) (((STV_IMAGE_QCIF_ROWS / 4) - (height / 4)) / 2);
+
+	/* Scaling registers (defaults) */
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_HPHASE;
+	if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i++].value = (u8) 36;
+	else
+		cmd.buffer.registers[i++].value = (u8) 0;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_VPHASE;
+	if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i++].value = (u8) 32;
+	else
+		cmd.buffer.registers[i++].value = (u8) 0;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_HISPAN;
+	if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i++].value = (u8) 26;
+	else
+		cmd.buffer.registers[i++].value = (u8) 31;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_VISPAN;
+	if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i++].value = (u8) 21;
+	else
+		cmd.buffer.registers[i++].value = (u8) 31;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_HICROP;
+	cmd.buffer.registers[i++].value = (u8) 0;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_VICROP;
+	cmd.buffer.registers[i++].value = (u8) 0;
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_HFRACT;
+	if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i++].value = (u8) 0x2B;	/* 2/11 */
+	else
+		cmd.buffer.registers[i++].value = (u8) 0x81;	/* 8/1 */
+
+	cmd.buffer.registers[i].index = CPIA2_VC_VC_VFRACT;
+	if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
+		cmd.buffer.registers[i++].value = (u8) 0x13;	/* 1/3 */
+	else
+		cmd.buffer.registers[i++].value = (u8) 0x81;	/* 8/1 */
+
+	cmd.reg_count = i;
+
+	cpia2_send_command(cam, &cmd);
+
+	return i;
+}
+
+
+/******************************************************************************
+ *
+ *  setallproperties
+ *
+ *  This sets all user changeable properties to the values in cam->params.
+ *****************************************************************************/
+int set_all_properties(struct camera_data *cam)
+{
+	/**
+	 * Don't set target_kb here, it will be set later.
+	 * framerate and user_mode were already set (set_default_user_mode).
+	 **/
+
+	cpia2_set_color_params(cam);
+
+	cpia2_usb_change_streaming_alternate(cam,
+					  cam->params.camera_state.stream_mode);
+
+	cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
+			 cam->params.vp_params.user_effects);
+
+	cpia2_set_flicker_mode(cam,
+			       cam->params.flicker_control.flicker_mode_req);
+
+	cpia2_do_command(cam,
+			 CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION,
+			 TRANSFER_WRITE, cam->params.vp_params.gpio_direction);
+	cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DATA, TRANSFER_WRITE,
+			 cam->params.vp_params.gpio_data);
+
+	wake_system(cam);
+
+	set_lowlight_boost(cam);
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_save_camera_state
+ *
+ *****************************************************************************/
+void cpia2_save_camera_state(struct camera_data *cam)
+{
+	get_color_params(cam);
+	cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0);
+	cpia2_do_command(cam, CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION, TRANSFER_READ,
+			 0);
+	cpia2_do_command(cam, CPIA2_CMD_GET_VC_MP_GPIO_DATA, TRANSFER_READ, 0);
+	/* Don't get framerate or target_kb. Trust the values we already have */
+}
+
+/******************************************************************************
+ *
+ *  get_color_params
+ *
+ *****************************************************************************/
+void get_color_params(struct camera_data *cam)
+{
+	cpia2_do_command(cam, CPIA2_CMD_GET_VP_BRIGHTNESS, TRANSFER_READ, 0);
+	cpia2_do_command(cam, CPIA2_CMD_GET_VP_SATURATION, TRANSFER_READ, 0);
+	cpia2_do_command(cam, CPIA2_CMD_GET_CONTRAST, TRANSFER_READ, 0);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_color_params
+ *
+ *****************************************************************************/
+void cpia2_set_color_params(struct camera_data *cam)
+{
+	DBG("Setting color params\n");
+	cpia2_set_brightness(cam, cam->params.color_params.brightness);
+	cpia2_set_contrast(cam, cam->params.color_params.contrast);
+	cpia2_set_saturation(cam, cam->params.color_params.saturation);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_flicker_mode
+ *
+ *****************************************************************************/
+int cpia2_set_flicker_mode(struct camera_data *cam, int mode)
+{
+	unsigned char cam_reg;
+	int err = 0;
+
+	if(cam->params.pnp_id.device_type != DEVICE_STV_672)
+		return -EINVAL;
+
+	/* Set the appropriate bits in FLICKER_MODES, preserving the rest */
+	if((err = cpia2_do_command(cam, CPIA2_CMD_GET_FLICKER_MODES,
+				   TRANSFER_READ, 0)))
+		return err;
+	cam_reg = cam->params.flicker_control.cam_register;
+
+	switch(mode) {
+	case NEVER_FLICKER:
+		cam_reg |= CPIA2_VP_FLICKER_MODES_NEVER_FLICKER;
+		cam_reg &= ~CPIA2_VP_FLICKER_MODES_50HZ;
+		break;
+	case FLICKER_60:
+		cam_reg &= ~CPIA2_VP_FLICKER_MODES_NEVER_FLICKER;
+		cam_reg &= ~CPIA2_VP_FLICKER_MODES_50HZ;
+		break;
+	case FLICKER_50:
+		cam_reg &= ~CPIA2_VP_FLICKER_MODES_NEVER_FLICKER;
+		cam_reg |= CPIA2_VP_FLICKER_MODES_50HZ;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if((err = cpia2_do_command(cam, CPIA2_CMD_SET_FLICKER_MODES,
+				   TRANSFER_WRITE, cam_reg)))
+		return err;
+
+	/* Set the appropriate bits in EXP_MODES, preserving the rest */
+	if((err = cpia2_do_command(cam, CPIA2_CMD_GET_VP_EXP_MODES,
+				   TRANSFER_READ, 0)))
+		return err;
+	cam_reg = cam->params.vp_params.exposure_modes;
+
+	if (mode == NEVER_FLICKER) {
+		cam_reg |= CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER;
+	} else {
+		cam_reg &= ~CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER;
+	}
+
+	if((err = cpia2_do_command(cam, CPIA2_CMD_SET_VP_EXP_MODES,
+				   TRANSFER_WRITE, cam_reg)))
+		return err;
+
+	if((err = cpia2_do_command(cam, CPIA2_CMD_REHASH_VP4,
+				   TRANSFER_WRITE, 1)))
+		return err;
+
+	switch(mode) {
+	case NEVER_FLICKER:
+		cam->params.flicker_control.flicker_mode_req = mode;
+		break;
+	case FLICKER_60:
+		cam->params.flicker_control.flicker_mode_req = mode;
+		cam->params.flicker_control.mains_frequency = 60;
+		break;
+	case FLICKER_50:
+		cam->params.flicker_control.flicker_mode_req = mode;
+		cam->params.flicker_control.mains_frequency = 50;
+		break;
+	default:
+		err = -EINVAL;
+	}
+
+	return err;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_property_flip
+ *
+ *****************************************************************************/
+void cpia2_set_property_flip(struct camera_data *cam, int prop_val)
+{
+	unsigned char cam_reg;
+
+	cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0);
+	cam_reg = cam->params.vp_params.user_effects;
+
+	if (prop_val)
+	{
+		cam_reg |= CPIA2_VP_USER_EFFECTS_FLIP;
+	}
+	else
+	{
+		cam_reg &= ~CPIA2_VP_USER_EFFECTS_FLIP;
+	}
+	cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
+			 cam_reg);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_property_mirror
+ *
+ *****************************************************************************/
+void cpia2_set_property_mirror(struct camera_data *cam, int prop_val)
+{
+	unsigned char cam_reg;
+
+	cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0);
+	cam_reg = cam->params.vp_params.user_effects;
+
+	if (prop_val)
+	{
+		cam_reg |= CPIA2_VP_USER_EFFECTS_MIRROR;
+	}
+	else
+	{
+		cam_reg &= ~CPIA2_VP_USER_EFFECTS_MIRROR;
+	}
+	cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
+			 cam_reg);
+}
+
+/******************************************************************************
+ *
+ *  set_target_kb
+ *
+ *  The new Target KB is set in cam->params.vc_params.target_kb and
+ *  activates on reset.
+ *****************************************************************************/
+
+int cpia2_set_target_kb(struct camera_data *cam, unsigned char value)
+{
+	DBG("Requested target_kb = %d\n", value);
+	if (value != cam->params.vc_params.target_kb) {
+
+		cpia2_usb_stream_pause(cam);
+
+		/* reset camera for new target_kb */
+		cam->params.vc_params.target_kb = value;
+		cpia2_reset_camera(cam);
+
+		cpia2_usb_stream_resume(cam);
+	}
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_gpio
+ *
+ *****************************************************************************/
+int cpia2_set_gpio(struct camera_data *cam, unsigned char setting)
+{
+	int ret;
+
+	/* Set the microport direction (register 0x90, should be defined
+	 * already) to 1 (user output), and set the microport data (0x91) to
+	 * the value in the ioctl argument.
+	 */
+
+	ret = cpia2_do_command(cam,
+			       CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION,
+			       CPIA2_VC_MP_DIR_OUTPUT,
+			       255);
+	if (ret < 0)
+		return ret;
+	cam->params.vp_params.gpio_direction = 255;
+
+	ret = cpia2_do_command(cam,
+			       CPIA2_CMD_SET_VC_MP_GPIO_DATA,
+			       CPIA2_VC_MP_DIR_OUTPUT,
+			       setting);
+	if (ret < 0)
+		return ret;
+	cam->params.vp_params.gpio_data = setting;
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_fps
+ *
+ *****************************************************************************/
+int cpia2_set_fps(struct camera_data *cam, int framerate)
+{
+	int retval;
+
+	switch(framerate) {
+		case CPIA2_VP_FRAMERATE_30:
+		case CPIA2_VP_FRAMERATE_25:
+			if(cam->params.pnp_id.device_type == DEVICE_STV_672 &&
+			   cam->params.version.sensor_flags ==
+						    CPIA2_VP_SENSOR_FLAGS_500) {
+				return -EINVAL;
+			}
+			/* Fall through */
+		case CPIA2_VP_FRAMERATE_15:
+		case CPIA2_VP_FRAMERATE_12_5:
+		case CPIA2_VP_FRAMERATE_7_5:
+		case CPIA2_VP_FRAMERATE_6_25:
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	if (cam->params.pnp_id.device_type == DEVICE_STV_672 &&
+	    framerate == CPIA2_VP_FRAMERATE_15)
+		framerate = 0; /* Work around bug in VP4 */
+
+	retval = cpia2_do_command(cam,
+				 CPIA2_CMD_FRAMERATE_REQ,
+				 TRANSFER_WRITE,
+				 framerate);
+
+	if(retval == 0)
+		cam->params.vp_params.frame_rate = framerate;
+
+	return retval;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_brightness
+ *
+ *****************************************************************************/
+void cpia2_set_brightness(struct camera_data *cam, unsigned char value)
+{
+	/***
+	 * Don't let the register be set to zero - bug in VP4 - flash of full
+	 * brightness
+	 ***/
+	if (cam->params.pnp_id.device_type == DEVICE_STV_672 && value == 0)
+		value++;
+	DBG("Setting brightness to %d (0x%0x)\n", value, value);
+	cpia2_do_command(cam,CPIA2_CMD_SET_VP_BRIGHTNESS, TRANSFER_WRITE,value);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_contrast
+ *
+ *****************************************************************************/
+void cpia2_set_contrast(struct camera_data *cam, unsigned char value)
+{
+	DBG("Setting contrast to %d (0x%0x)\n", value, value);
+	cam->params.color_params.contrast = value;
+	cpia2_do_command(cam, CPIA2_CMD_SET_CONTRAST, TRANSFER_WRITE, value);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_saturation
+ *
+ *****************************************************************************/
+void cpia2_set_saturation(struct camera_data *cam, unsigned char value)
+{
+	DBG("Setting saturation to %d (0x%0x)\n", value, value);
+	cam->params.color_params.saturation = value;
+	cpia2_do_command(cam,CPIA2_CMD_SET_VP_SATURATION, TRANSFER_WRITE,value);
+}
+
+/******************************************************************************
+ *
+ *  wake_system
+ *
+ *****************************************************************************/
+void wake_system(struct camera_data *cam)
+{
+	cpia2_do_command(cam, CPIA2_CMD_SET_WAKEUP, TRANSFER_WRITE, 0);
+}
+
+/******************************************************************************
+ *
+ *  set_lowlight_boost
+ *
+ *  Valid for STV500 sensor only
+ *****************************************************************************/
+void set_lowlight_boost(struct camera_data *cam)
+{
+	struct cpia2_command cmd;
+
+	if (cam->params.pnp_id.device_type != DEVICE_STV_672 ||
+	    cam->params.version.sensor_flags != CPIA2_VP_SENSOR_FLAGS_500)
+		return;
+
+	cmd.direction = TRANSFER_WRITE;
+	cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+	cmd.reg_count = 3;
+	cmd.start = CPIA2_VP_RAM_ADDR_H;
+
+	cmd.buffer.block_data[0] = 0;	/* High byte of address to write to */
+	cmd.buffer.block_data[1] = 0x59;	/* Low byte of address to write to */
+	cmd.buffer.block_data[2] = 0;	/* High byte of data to write */
+
+	cpia2_send_command(cam, &cmd);
+
+	if (cam->params.vp_params.lowlight_boost) {
+		cmd.buffer.block_data[0] = 0x02;	/* Low byte data to write */
+	} else {
+		cmd.buffer.block_data[0] = 0x06;
+	}
+	cmd.start = CPIA2_VP_RAM_DATA;
+	cmd.reg_count = 1;
+	cpia2_send_command(cam, &cmd);
+
+	/* Rehash the VP4 values */
+	cpia2_do_command(cam, CPIA2_CMD_REHASH_VP4, TRANSFER_WRITE, 1);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_format
+ *
+ *  Assumes that new size is already set in param struct.
+ *****************************************************************************/
+void cpia2_set_format(struct camera_data *cam)
+{
+	cam->flush = true;
+
+	cpia2_usb_stream_pause(cam);
+
+	/* reset camera to new size */
+	cpia2_set_low_power(cam);
+	cpia2_reset_camera(cam);
+	cam->flush = false;
+
+	cpia2_dbg_dump_registers(cam);
+
+	cpia2_usb_stream_resume(cam);
+}
+
+/******************************************************************************
+ *
+ * cpia2_dbg_dump_registers
+ *
+ *****************************************************************************/
+void cpia2_dbg_dump_registers(struct camera_data *cam)
+{
+#ifdef _CPIA2_DEBUG_
+	struct cpia2_command cmd;
+
+	if (!(debugs_on & DEBUG_DUMP_REGS))
+		return;
+
+	cmd.direction = TRANSFER_READ;
+
+	/* Start with bank 0 (SYSTEM) */
+	cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+	cmd.reg_count = 3;
+	cmd.start = 0;
+	cpia2_send_command(cam, &cmd);
+	printk(KERN_DEBUG "System Device Hi      = 0x%X\n",
+	       cmd.buffer.block_data[0]);
+	printk(KERN_DEBUG "System Device Lo      = 0x%X\n",
+	       cmd.buffer.block_data[1]);
+	printk(KERN_DEBUG "System_system control = 0x%X\n",
+	       cmd.buffer.block_data[2]);
+
+	/* Bank 1 (VC) */
+	cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+	cmd.reg_count = 4;
+	cmd.start = 0x80;
+	cpia2_send_command(cam, &cmd);
+	printk(KERN_DEBUG "ASIC_ID       = 0x%X\n",
+	       cmd.buffer.block_data[0]);
+	printk(KERN_DEBUG "ASIC_REV      = 0x%X\n",
+	       cmd.buffer.block_data[1]);
+	printk(KERN_DEBUG "PW_CONTRL     = 0x%X\n",
+	       cmd.buffer.block_data[2]);
+	printk(KERN_DEBUG "WAKEUP        = 0x%X\n",
+	       cmd.buffer.block_data[3]);
+
+	cmd.start = 0xA0;	/* ST_CTRL */
+	cmd.reg_count = 1;
+	cpia2_send_command(cam, &cmd);
+	printk(KERN_DEBUG "Stream ctrl   = 0x%X\n",
+	       cmd.buffer.block_data[0]);
+
+	cmd.start = 0xA4;	/* Stream status */
+	cpia2_send_command(cam, &cmd);
+	printk(KERN_DEBUG "Stream status = 0x%X\n",
+	       cmd.buffer.block_data[0]);
+
+	cmd.start = 0xA8;	/* USB status */
+	cmd.reg_count = 3;
+	cpia2_send_command(cam, &cmd);
+	printk(KERN_DEBUG "USB_CTRL      = 0x%X\n",
+	       cmd.buffer.block_data[0]);
+	printk(KERN_DEBUG "USB_STRM      = 0x%X\n",
+	       cmd.buffer.block_data[1]);
+	printk(KERN_DEBUG "USB_STATUS    = 0x%X\n",
+	       cmd.buffer.block_data[2]);
+
+	cmd.start = 0xAF;	/* USB settings */
+	cmd.reg_count = 1;
+	cpia2_send_command(cam, &cmd);
+	printk(KERN_DEBUG "USB settings  = 0x%X\n",
+	       cmd.buffer.block_data[0]);
+
+	cmd.start = 0xC0;	/* VC stuff */
+	cmd.reg_count = 26;
+	cpia2_send_command(cam, &cmd);
+	printk(KERN_DEBUG "VC Control    = 0x%0X\n",
+	       cmd.buffer.block_data[0]);
+	printk(KERN_DEBUG "VC Format     = 0x%0X\n",
+	       cmd.buffer.block_data[3]);
+	printk(KERN_DEBUG "VC Clocks     = 0x%0X\n",
+	       cmd.buffer.block_data[4]);
+	printk(KERN_DEBUG "VC IHSize     = 0x%0X\n",
+	       cmd.buffer.block_data[5]);
+	printk(KERN_DEBUG "VC Xlim Hi    = 0x%0X\n",
+	       cmd.buffer.block_data[6]);
+	printk(KERN_DEBUG "VC XLim Lo    = 0x%0X\n",
+	       cmd.buffer.block_data[7]);
+	printk(KERN_DEBUG "VC YLim Hi    = 0x%0X\n",
+	       cmd.buffer.block_data[8]);
+	printk(KERN_DEBUG "VC YLim Lo    = 0x%0X\n",
+	       cmd.buffer.block_data[9]);
+	printk(KERN_DEBUG "VC OHSize     = 0x%0X\n",
+	       cmd.buffer.block_data[10]);
+	printk(KERN_DEBUG "VC OVSize     = 0x%0X\n",
+	       cmd.buffer.block_data[11]);
+	printk(KERN_DEBUG "VC HCrop      = 0x%0X\n",
+	       cmd.buffer.block_data[12]);
+	printk(KERN_DEBUG "VC VCrop      = 0x%0X\n",
+	       cmd.buffer.block_data[13]);
+	printk(KERN_DEBUG "VC HPhase     = 0x%0X\n",
+	       cmd.buffer.block_data[14]);
+	printk(KERN_DEBUG "VC VPhase     = 0x%0X\n",
+	       cmd.buffer.block_data[15]);
+	printk(KERN_DEBUG "VC HIspan     = 0x%0X\n",
+	       cmd.buffer.block_data[16]);
+	printk(KERN_DEBUG "VC VIspan     = 0x%0X\n",
+	       cmd.buffer.block_data[17]);
+	printk(KERN_DEBUG "VC HiCrop     = 0x%0X\n",
+	       cmd.buffer.block_data[18]);
+	printk(KERN_DEBUG "VC ViCrop     = 0x%0X\n",
+	       cmd.buffer.block_data[19]);
+	printk(KERN_DEBUG "VC HiFract    = 0x%0X\n",
+	       cmd.buffer.block_data[20]);
+	printk(KERN_DEBUG "VC ViFract    = 0x%0X\n",
+	       cmd.buffer.block_data[21]);
+	printk(KERN_DEBUG "VC JPeg Opt   = 0x%0X\n",
+	       cmd.buffer.block_data[22]);
+	printk(KERN_DEBUG "VC Creep Per  = 0x%0X\n",
+	       cmd.buffer.block_data[23]);
+	printk(KERN_DEBUG "VC User Sq.   = 0x%0X\n",
+	       cmd.buffer.block_data[24]);
+	printk(KERN_DEBUG "VC Target KB  = 0x%0X\n",
+	       cmd.buffer.block_data[25]);
+
+	/*** VP ***/
+	cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+	cmd.reg_count = 14;
+	cmd.start = 0;
+	cpia2_send_command(cam, &cmd);
+
+	printk(KERN_DEBUG "VP Dev Hi     = 0x%0X\n",
+	       cmd.buffer.block_data[0]);
+	printk(KERN_DEBUG "VP Dev Lo     = 0x%0X\n",
+	       cmd.buffer.block_data[1]);
+	printk(KERN_DEBUG "VP Sys State  = 0x%0X\n",
+	       cmd.buffer.block_data[2]);
+	printk(KERN_DEBUG "VP Sys Ctrl   = 0x%0X\n",
+	       cmd.buffer.block_data[3]);
+	printk(KERN_DEBUG "VP Sensor flg = 0x%0X\n",
+	       cmd.buffer.block_data[5]);
+	printk(KERN_DEBUG "VP Sensor Rev = 0x%0X\n",
+	       cmd.buffer.block_data[6]);
+	printk(KERN_DEBUG "VP Dev Config = 0x%0X\n",
+	       cmd.buffer.block_data[7]);
+	printk(KERN_DEBUG "VP GPIO_DIR   = 0x%0X\n",
+	       cmd.buffer.block_data[8]);
+	printk(KERN_DEBUG "VP GPIO_DATA  = 0x%0X\n",
+	       cmd.buffer.block_data[9]);
+	printk(KERN_DEBUG "VP Ram ADDR H = 0x%0X\n",
+	       cmd.buffer.block_data[10]);
+	printk(KERN_DEBUG "VP Ram ADDR L = 0x%0X\n",
+	       cmd.buffer.block_data[11]);
+	printk(KERN_DEBUG "VP RAM Data   = 0x%0X\n",
+	       cmd.buffer.block_data[12]);
+	printk(KERN_DEBUG "Do Call       = 0x%0X\n",
+	       cmd.buffer.block_data[13]);
+
+	if (cam->params.pnp_id.device_type == DEVICE_STV_672) {
+		cmd.reg_count = 9;
+		cmd.start = 0x0E;
+		cpia2_send_command(cam, &cmd);
+		printk(KERN_DEBUG "VP Clock Ctrl = 0x%0X\n",
+		       cmd.buffer.block_data[0]);
+		printk(KERN_DEBUG "VP Patch Rev  = 0x%0X\n",
+		       cmd.buffer.block_data[1]);
+		printk(KERN_DEBUG "VP Vid Mode   = 0x%0X\n",
+		       cmd.buffer.block_data[2]);
+		printk(KERN_DEBUG "VP Framerate  = 0x%0X\n",
+		       cmd.buffer.block_data[3]);
+		printk(KERN_DEBUG "VP UserEffect = 0x%0X\n",
+		       cmd.buffer.block_data[4]);
+		printk(KERN_DEBUG "VP White Bal  = 0x%0X\n",
+		       cmd.buffer.block_data[5]);
+		printk(KERN_DEBUG "VP WB thresh  = 0x%0X\n",
+		       cmd.buffer.block_data[6]);
+		printk(KERN_DEBUG "VP Exp Modes  = 0x%0X\n",
+		       cmd.buffer.block_data[7]);
+		printk(KERN_DEBUG "VP Exp Target = 0x%0X\n",
+		       cmd.buffer.block_data[8]);
+
+		cmd.reg_count = 1;
+		cmd.start = 0x1B;
+		cpia2_send_command(cam, &cmd);
+		printk(KERN_DEBUG "VP FlickerMds = 0x%0X\n",
+		       cmd.buffer.block_data[0]);
+	} else {
+		cmd.reg_count = 8 ;
+		cmd.start = 0x0E;
+		cpia2_send_command(cam, &cmd);
+		printk(KERN_DEBUG "VP Clock Ctrl = 0x%0X\n",
+		       cmd.buffer.block_data[0]);
+		printk(KERN_DEBUG "VP Patch Rev  = 0x%0X\n",
+		       cmd.buffer.block_data[1]);
+		printk(KERN_DEBUG "VP Vid Mode   = 0x%0X\n",
+		       cmd.buffer.block_data[5]);
+		printk(KERN_DEBUG "VP Framerate  = 0x%0X\n",
+		       cmd.buffer.block_data[6]);
+		printk(KERN_DEBUG "VP UserEffect = 0x%0X\n",
+		       cmd.buffer.block_data[7]);
+
+		cmd.reg_count = 1;
+		cmd.start = CPIA2_VP5_EXPOSURE_TARGET;
+		cpia2_send_command(cam, &cmd);
+		printk(KERN_DEBUG "VP5 Exp Target= 0x%0X\n",
+		       cmd.buffer.block_data[0]);
+
+		cmd.reg_count = 4;
+		cmd.start = 0x3A;
+		cpia2_send_command(cam, &cmd);
+		printk(KERN_DEBUG "VP5 MY Black  = 0x%0X\n",
+		       cmd.buffer.block_data[0]);
+		printk(KERN_DEBUG "VP5 MCY Range = 0x%0X\n",
+		       cmd.buffer.block_data[1]);
+		printk(KERN_DEBUG "VP5 MYCEILING = 0x%0X\n",
+		       cmd.buffer.block_data[2]);
+		printk(KERN_DEBUG "VP5 MCUV Sat  = 0x%0X\n",
+		       cmd.buffer.block_data[3]);
+	}
+#endif
+}
+
+/******************************************************************************
+ *
+ *  reset_camera_struct
+ *
+ *  Sets all values to the defaults
+ *****************************************************************************/
+void reset_camera_struct(struct camera_data *cam)
+{
+	/***
+	 * The following parameter values are the defaults from the register map.
+	 ***/
+	cam->params.color_params.brightness = DEFAULT_BRIGHTNESS;
+	cam->params.color_params.contrast = DEFAULT_CONTRAST;
+	cam->params.color_params.saturation = DEFAULT_SATURATION;
+	cam->params.vp_params.lowlight_boost = 0;
+
+	/* FlickerModes */
+	cam->params.flicker_control.flicker_mode_req = NEVER_FLICKER;
+	cam->params.flicker_control.mains_frequency = 60;
+
+	/* jpeg params */
+	cam->params.compression.jpeg_options = CPIA2_VC_VC_JPEG_OPT_DEFAULT;
+	cam->params.compression.creep_period = 2;
+	cam->params.compression.user_squeeze = 20;
+	cam->params.compression.inhibit_htables = false;
+
+	/* gpio params */
+	cam->params.vp_params.gpio_direction = 0;	/* write, the default safe mode */
+	cam->params.vp_params.gpio_data = 0;
+
+	/* Target kb params */
+	cam->params.vc_params.target_kb = DEFAULT_TARGET_KB;
+
+	/***
+	 * Set Sensor FPS as fast as possible.
+	 ***/
+	if(cam->params.pnp_id.device_type == DEVICE_STV_672) {
+		if(cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500)
+			cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_15;
+		else
+			cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_30;
+	} else {
+		cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_30;
+	}
+
+	/***
+	 * Set default video mode as large as possible :
+	 * for vga sensor set to vga, for cif sensor set to CIF.
+	 ***/
+	if (cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500) {
+		cam->sensor_type = CPIA2_SENSOR_500;
+		cam->video_size = VIDEOSIZE_VGA;
+		cam->params.roi.width = STV_IMAGE_VGA_COLS;
+		cam->params.roi.height = STV_IMAGE_VGA_ROWS;
+	} else {
+		cam->sensor_type = CPIA2_SENSOR_410;
+		cam->video_size = VIDEOSIZE_CIF;
+		cam->params.roi.width = STV_IMAGE_CIF_COLS;
+		cam->params.roi.height = STV_IMAGE_CIF_ROWS;
+	}
+
+	/***
+	 * Fill in the v4l structures.  video_cap is filled in inside the VIDIOCCAP
+	 * Ioctl.  Here, just do the window and picture stucts.
+	 ***/
+	cam->vp.palette = (u16) VIDEO_PALETTE_RGB24;	/* Is this right? */
+	cam->vp.brightness = (u16) cam->params.color_params.brightness * 256;
+	cam->vp.colour = (u16) cam->params.color_params.saturation * 256;
+	cam->vp.contrast = (u16) cam->params.color_params.contrast * 256;
+
+	cam->vw.x = 0;
+	cam->vw.y = 0;
+	cam->vw.width = cam->params.roi.width;
+	cam->vw.height = cam->params.roi.height;
+	cam->vw.flags = 0;
+	cam->vw.clipcount = 0;
+
+	return;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_init_camera_struct
+ *
+ *  Initializes camera struct, does not call reset to fill in defaults.
+ *****************************************************************************/
+struct camera_data *cpia2_init_camera_struct(void)
+{
+	struct camera_data *cam;
+
+	cam = kmalloc(sizeof(*cam), GFP_KERNEL);
+
+	if (!cam) {
+		ERR("couldn't kmalloc cpia2 struct\n");
+		return NULL;
+	}
+
+	/* Default everything to 0 */
+	memset(cam, 0, sizeof(struct camera_data));
+
+	cam->present = 1;
+	init_MUTEX(&cam->busy_lock);
+	init_waitqueue_head(&cam->wq_stream);
+
+	return cam;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_init_camera
+ *
+ *  Initializes camera.
+ *****************************************************************************/
+int cpia2_init_camera(struct camera_data *cam)
+{
+	DBG("Start\n");
+
+	cam->mmapped = false;
+
+	/* Get sensor and asic types before reset. */
+	cpia2_set_high_power(cam);
+	cpia2_get_version_info(cam);
+	if (cam->params.version.asic_id != CPIA2_ASIC_672) {
+		ERR("Device IO error (asicID has incorrect value of 0x%X\n",
+		    cam->params.version.asic_id);
+		return -ENODEV;
+	}
+
+	/* Set GPIO direction and data to a safe state. */
+	cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION,
+			 TRANSFER_WRITE, 0);
+	cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DATA,
+			 TRANSFER_WRITE, 0);
+
+	/* resetting struct requires version info for sensor and asic types */
+	reset_camera_struct(cam);
+
+	cpia2_set_low_power(cam);
+
+	DBG("End\n");
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_allocate_buffers
+ *
+ *****************************************************************************/
+int cpia2_allocate_buffers(struct camera_data *cam)
+{
+	int i;
+
+	if(!cam->buffers) {
+		u32 size = cam->num_frames*sizeof(struct framebuf);
+		cam->buffers = kmalloc(size, GFP_KERNEL);
+		if(!cam->buffers) {
+			ERR("couldn't kmalloc frame buffer structures\n");
+			return -ENOMEM;
+		}
+	}
+
+	if(!cam->frame_buffer) {
+		cam->frame_buffer = rvmalloc(cam->frame_size*cam->num_frames);
+		if (!cam->frame_buffer) {
+			ERR("couldn't vmalloc frame buffer data area\n");
+			kfree(cam->buffers);
+			cam->buffers = NULL;
+			return -ENOMEM;
+		}
+	}
+
+	for(i=0; i<cam->num_frames-1; ++i) {
+		cam->buffers[i].next = &cam->buffers[i+1];
+		cam->buffers[i].data = cam->frame_buffer +i*cam->frame_size;
+		cam->buffers[i].status = FRAME_EMPTY;
+		cam->buffers[i].length = 0;
+		cam->buffers[i].max_length = 0;
+		cam->buffers[i].num = i;
+	}
+	cam->buffers[i].next = cam->buffers;
+	cam->buffers[i].data = cam->frame_buffer +i*cam->frame_size;
+	cam->buffers[i].status = FRAME_EMPTY;
+	cam->buffers[i].length = 0;
+	cam->buffers[i].max_length = 0;
+	cam->buffers[i].num = i;
+	cam->curbuff = cam->buffers;
+	cam->workbuff = cam->curbuff->next;
+	DBG("buffers=%p, curbuff=%p, workbuff=%p\n", cam->buffers, cam->curbuff,
+	    cam->workbuff);
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_free_buffers
+ *
+ *****************************************************************************/
+void cpia2_free_buffers(struct camera_data *cam)
+{
+	if(cam->buffers) {
+		kfree(cam->buffers);
+		cam->buffers = NULL;
+	}
+	if(cam->frame_buffer) {
+		rvfree(cam->frame_buffer, cam->frame_size*cam->num_frames);
+		cam->frame_buffer = NULL;
+	}
+}
+
+/******************************************************************************
+ *
+ *  cpia2_read
+ *
+ *****************************************************************************/
+long cpia2_read(struct camera_data *cam,
+		char __user *buf, unsigned long count, int noblock)
+{
+	struct framebuf *frame;
+	if (!count) {
+		return 0;
+	}
+
+	if (!buf) {
+		ERR("%s: buffer NULL\n",__FUNCTION__);
+		return -EINVAL;
+	}
+
+	if (!cam) {
+		ERR("%s: Internal error, camera_data NULL!\n",__FUNCTION__);
+		return -EINVAL;
+	}
+
+	/* make this _really_ smp and multithread-safe */
+	if (down_interruptible(&cam->busy_lock))
+		return -ERESTARTSYS;
+
+	if (!cam->present) {
+		LOG("%s: camera removed\n",__FUNCTION__);
+		up(&cam->busy_lock);
+		return 0;	/* EOF */
+	}
+
+	if(!cam->streaming) {
+		/* Start streaming */
+		cpia2_usb_stream_start(cam,
+				       cam->params.camera_state.stream_mode);
+	}
+
+	/* Copy cam->curbuff in case it changes while we're processing */
+	frame = cam->curbuff;
+	if (noblock && frame->status != FRAME_READY) {
+		up(&cam->busy_lock);
+		return -EAGAIN;
+	}
+
+	if(frame->status != FRAME_READY) {
+		up(&cam->busy_lock);
+		wait_event_interruptible(cam->wq_stream,
+			       !cam->present ||
+			       (frame = cam->curbuff)->status == FRAME_READY);
+		if (signal_pending(current))
+			return -ERESTARTSYS;
+		/* make this _really_ smp and multithread-safe */
+		if (down_interruptible(&cam->busy_lock)) {
+			return -ERESTARTSYS;
+		}
+		if(!cam->present) {
+			up(&cam->busy_lock);
+			return 0;
+		}
+	}
+
+	/* copy data to user space */
+	if (frame->length > count) {
+		up(&cam->busy_lock);
+		return -EFAULT;
+	}
+	if (copy_to_user(buf, frame->data, frame->length)) {
+		up(&cam->busy_lock);
+		return -EFAULT;
+	}
+
+	count = frame->length;
+
+	frame->status = FRAME_EMPTY;
+
+	up(&cam->busy_lock);
+	return count;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_poll
+ *
+ *****************************************************************************/
+unsigned int cpia2_poll(struct camera_data *cam, struct file *filp,
+			poll_table *wait)
+{
+	unsigned int status=0;
+
+	if(!cam) {
+		ERR("%s: Internal error, camera_data not found!\n",__FUNCTION__);
+		return POLLERR;
+	}
+
+	down(&cam->busy_lock);
+
+	if(!cam->present) {
+		up(&cam->busy_lock);
+		return POLLHUP;
+	}
+
+	if(!cam->streaming) {
+		/* Start streaming */
+		cpia2_usb_stream_start(cam,
+				       cam->params.camera_state.stream_mode);
+	}
+
+	up(&cam->busy_lock);
+	poll_wait(filp, &cam->wq_stream, wait);
+	down(&cam->busy_lock);
+
+	if(!cam->present)
+		status = POLLHUP;
+	else if(cam->curbuff->status == FRAME_READY)
+		status = POLLIN | POLLRDNORM;
+
+	up(&cam->busy_lock);
+	return status;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_remap_buffer
+ *
+ *****************************************************************************/
+int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma)
+{
+	const char *adr = (const char *)vma->vm_start;
+	unsigned long size = vma->vm_end-vma->vm_start;
+	unsigned long start_offset = vma->vm_pgoff << PAGE_SHIFT;
+	unsigned long start = (unsigned long) adr;
+	unsigned long page, pos;
+
+	if (!cam)
+		return -ENODEV;
+
+	DBG("mmap offset:%ld size:%ld\n", start_offset, size);
+
+	/* make this _really_ smp-safe */
+	if (down_interruptible(&cam->busy_lock))
+		return -ERESTARTSYS;
+
+	if (!cam->present) {
+		up(&cam->busy_lock);
+		return -ENODEV;
+	}
+
+	if (size > cam->frame_size*cam->num_frames  ||
+	    (start_offset % cam->frame_size) != 0 ||
+	    (start_offset+size > cam->frame_size*cam->num_frames)) {
+		up(&cam->busy_lock);
+		return -EINVAL;
+	}
+
+	pos = ((unsigned long) (cam->frame_buffer)) + start_offset;
+	while (size > 0) {
+		page = kvirt_to_pa(pos);
+		if (remap_pfn_range(vma, start, page >> PAGE_SHIFT, PAGE_SIZE, PAGE_SHARED)) {
+			up(&cam->busy_lock);
+			return -EAGAIN;
+		}
+		start += PAGE_SIZE;
+		pos += PAGE_SIZE;
+		if (size > PAGE_SIZE)
+			size -= PAGE_SIZE;
+		else
+			size = 0;
+	}
+
+	cam->mmapped = true;
+	up(&cam->busy_lock);
+	return 0;
+}
+
diff --git a/drivers/media/video/cpia2/cpia2_registers.h b/drivers/media/video/cpia2/cpia2_registers.h
new file mode 100644
index 0000000..3bbec51
--- /dev/null
+++ b/drivers/media/video/cpia2/cpia2_registers.h
@@ -0,0 +1,476 @@
+/****************************************************************************
+ *
+ *  Filename: cpia2registers.h
+ *
+ *  Copyright 2001, STMicrolectronics, Inc.
+ *
+ *  Description:
+ *     Definitions for the CPia2 register set
+ *
+ *  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 CPIA2_REGISTER_HEADER
+#define CPIA2_REGISTER_HEADER
+
+/***
+ * System register set (Bank 0)
+ ***/
+#define CPIA2_SYSTEM_DEVICE_HI                     0x00
+#define CPIA2_SYSTEM_DEVICE_LO                     0x01
+
+#define CPIA2_SYSTEM_SYSTEM_CONTROL                0x02
+#define CPIA2_SYSTEM_CONTROL_LOW_POWER       0x00
+#define CPIA2_SYSTEM_CONTROL_HIGH_POWER      0x01
+#define CPIA2_SYSTEM_CONTROL_SUSPEND         0x02
+#define CPIA2_SYSTEM_CONTROL_V2W_ERR         0x10
+#define CPIA2_SYSTEM_CONTROL_RB_ERR          0x10
+#define CPIA2_SYSTEM_CONTROL_CLEAR_ERR       0x80
+
+#define CPIA2_SYSTEM_INT_PACKET_CTRL                0x04
+#define CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_SW_XX 0x01
+#define CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_EOF   0x02
+#define CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_INT1  0x04
+
+#define CPIA2_SYSTEM_CACHE_CTRL                     0x05
+#define CPIA2_SYSTEM_CACHE_CTRL_CACHE_RESET      0x01
+#define CPIA2_SYSTEM_CACHE_CTRL_CACHE_FLUSH      0x02
+
+#define CPIA2_SYSTEM_SERIAL_CTRL                    0x06
+#define CPIA2_SYSTEM_SERIAL_CTRL_NULL_CMD        0x00
+#define CPIA2_SYSTEM_SERIAL_CTRL_START_CMD       0x01
+#define CPIA2_SYSTEM_SERIAL_CTRL_STOP_CMD        0x02
+#define CPIA2_SYSTEM_SERIAL_CTRL_WRITE_CMD       0x03
+#define CPIA2_SYSTEM_SERIAL_CTRL_READ_ACK_CMD    0x04
+#define CPIA2_SYSTEM_SERIAL_CTRL_READ_NACK_CMD   0x05
+
+#define CPIA2_SYSTEM_SERIAL_DATA                     0x07
+
+#define CPIA2_SYSTEM_VP_SERIAL_ADDR                  0x08
+
+/***
+ * I2C addresses for various devices in CPiA2
+ ***/
+#define CPIA2_SYSTEM_VP_SERIAL_ADDR_SENSOR           0x20
+#define CPIA2_SYSTEM_VP_SERIAL_ADDR_VP               0x88
+#define CPIA2_SYSTEM_VP_SERIAL_ADDR_676_VP           0x8A
+
+#define CPIA2_SYSTEM_SPARE_REG1                      0x09
+#define CPIA2_SYSTEM_SPARE_REG2                      0x0A
+#define CPIA2_SYSTEM_SPARE_REG3                      0x0B
+
+#define CPIA2_SYSTEM_MC_PORT_0                       0x0C
+#define CPIA2_SYSTEM_MC_PORT_1                       0x0D
+#define CPIA2_SYSTEM_MC_PORT_2                       0x0E
+#define CPIA2_SYSTEM_MC_PORT_3                       0x0F
+
+#define CPIA2_SYSTEM_STATUS_PKT                      0x20
+#define CPIA2_SYSTEM_STATUS_PKT_END                  0x27
+
+#define CPIA2_SYSTEM_DESCRIP_VID_HI                  0x30
+#define CPIA2_SYSTEM_DESCRIP_VID_LO                  0x31
+#define CPIA2_SYSTEM_DESCRIP_PID_HI                  0x32
+#define CPIA2_SYSTEM_DESCRIP_PID_LO                  0x33
+
+#define CPIA2_SYSTEM_FW_VERSION_HI                   0x34
+#define CPIA2_SYSTEM_FW_VERSION_LO                   0x35
+
+#define CPIA2_SYSTEM_CACHE_START_INDEX               0x80
+#define CPIA2_SYSTEM_CACHE_MAX_WRITES                0x10
+
+/***
+ * VC register set (Bank 1)
+ ***/
+#define CPIA2_VC_ASIC_ID                 0x80
+
+#define CPIA2_VC_ASIC_REV                0x81
+
+#define CPIA2_VC_PW_CTRL                 0x82
+#define CPIA2_VC_PW_CTRL_COLDSTART      0x01
+#define CPIA2_VC_PW_CTRL_CP_CLK_EN      0x02
+#define CPIA2_VC_PW_CTRL_VP_RESET_N     0x04
+#define CPIA2_VC_PW_CTRL_VC_CLK_EN      0x08
+#define CPIA2_VC_PW_CTRL_VC_RESET_N     0x10
+#define CPIA2_VC_PW_CTRL_GOTO_SUSPEND   0x20
+#define CPIA2_VC_PW_CTRL_UDC_SUSPEND    0x40
+#define CPIA2_VC_PW_CTRL_PWR_DOWN       0x80
+
+#define CPIA2_VC_WAKEUP                   0x83
+#define CPIA2_VC_WAKEUP_SW_ENABLE       0x01
+#define CPIA2_VC_WAKEUP_XX_ENABLE       0x02
+#define CPIA2_VC_WAKEUP_SW_ATWAKEUP     0x04
+#define CPIA2_VC_WAKEUP_XX_ATWAKEUP     0x08
+
+#define CPIA2_VC_CLOCK_CTRL               0x84
+#define CPIA2_VC_CLOCK_CTRL_TESTUP72    0x01
+
+#define CPIA2_VC_INT_ENABLE                0x88
+#define CPIA2_VC_INT_ENABLE_XX_IE       0x01
+#define CPIA2_VC_INT_ENABLE_SW_IE       0x02
+#define CPIA2_VC_INT_ENABLE_VC_IE       0x04
+#define CPIA2_VC_INT_ENABLE_USBDATA_IE  0x08
+#define CPIA2_VC_INT_ENABLE_USBSETUP_IE 0x10
+#define CPIA2_VC_INT_ENABLE_USBCFG_IE   0x20
+
+#define CPIA2_VC_INT_FLAG                  0x89
+#define CPIA2_VC_INT_ENABLE_XX_FLAG       0x01
+#define CPIA2_VC_INT_ENABLE_SW_FLAG       0x02
+#define CPIA2_VC_INT_ENABLE_VC_FLAG       0x04
+#define CPIA2_VC_INT_ENABLE_USBDATA_FLAG  0x08
+#define CPIA2_VC_INT_ENABLE_USBSETUP_FLAG 0x10
+#define CPIA2_VC_INT_ENABLE_USBCFG_FLAG   0x20
+#define CPIA2_VC_INT_ENABLE_SET_RESET_BIT 0x80
+
+#define CPIA2_VC_INT_STATE                 0x8A
+#define CPIA2_VC_INT_STATE_XX_STATE     0x01
+#define CPIA2_VC_INT_STATE_SW_STATE     0x02
+
+#define CPIA2_VC_MP_DIR                    0x90
+#define CPIA2_VC_MP_DIR_INPUT           0x00
+#define CPIA2_VC_MP_DIR_OUTPUT          0x01
+
+#define CPIA2_VC_MP_DATA                   0x91
+
+#define CPIA2_VC_DP_CTRL                   0x98
+#define CPIA2_VC_DP_CTRL_MODE_0         0x00
+#define CPIA2_VC_DP_CTRL_MODE_A         0x01
+#define CPIA2_VC_DP_CTRL_MODE_B         0x02
+#define CPIA2_VC_DP_CTRL_MODE_C         0x03
+#define CPIA2_VC_DP_CTRL_FAKE_FST       0x04
+
+#define CPIA2_VC_AD_CTRL                   0x99
+#define CPIA2_VC_AD_CTRL_SRC_0          0x00
+#define CPIA2_VC_AD_CTRL_SRC_DIGI_A     0x01
+#define CPIA2_VC_AD_CTRL_SRC_REG        0x02
+#define CPIA2_VC_AD_CTRL_DST_USB        0x00
+#define CPIA2_VC_AD_CTRL_DST_REG        0x04
+
+#define CPIA2_VC_AD_TEST_IN                0x9B
+
+#define CPIA2_VC_AD_TEST_OUT               0x9C
+
+#define CPIA2_VC_AD_STATUS                 0x9D
+#define CPIA2_VC_AD_STATUS_EMPTY        0x01
+#define CPIA2_VC_AD_STATUS_FULL         0x02
+
+#define CPIA2_VC_DP_DATA                   0x9E
+
+#define CPIA2_VC_ST_CTRL                   0xA0
+#define CPIA2_VC_ST_CTRL_SRC_VC         0x00
+#define CPIA2_VC_ST_CTRL_SRC_DP         0x01
+#define CPIA2_VC_ST_CTRL_SRC_REG        0x02
+
+#define CPIA2_VC_ST_CTRL_RAW_SELECT     0x04
+
+#define CPIA2_VC_ST_CTRL_DST_USB        0x00
+#define CPIA2_VC_ST_CTRL_DST_DP         0x08
+#define CPIA2_VC_ST_CTRL_DST_REG        0x10
+
+#define CPIA2_VC_ST_CTRL_FIFO_ENABLE    0x20
+#define CPIA2_VC_ST_CTRL_EOF_DETECT     0x40
+
+#define CPIA2_VC_ST_TEST                   0xA1
+#define CPIA2_VC_ST_TEST_MODE_MANUAL    0x00
+#define CPIA2_VC_ST_TEST_MODE_INCREMENT 0x02
+
+#define CPIA2_VC_ST_TEST_AUTO_FILL      0x08
+
+#define CPIA2_VC_ST_TEST_REPEAT_FIFO    0x10
+
+#define CPIA2_VC_ST_TEST_IN                0xA2
+
+#define CPIA2_VC_ST_TEST_OUT               0xA3
+
+#define CPIA2_VC_ST_STATUS                 0xA4
+#define CPIA2_VC_ST_STATUS_EMPTY        0x01
+#define CPIA2_VC_ST_STATUS_FULL         0x02
+
+#define CPIA2_VC_ST_FRAME_DETECT_1         0xA5
+
+#define CPIA2_VC_ST_FRAME_DETECT_2         0xA6
+
+#define CPIA2_VC_USB_CTRL                    0xA8
+#define CPIA2_VC_USB_CTRL_CMD_STALLED      0x01
+#define CPIA2_VC_USB_CTRL_CMD_READY        0x02
+#define CPIA2_VC_USB_CTRL_CMD_STATUS       0x04
+#define CPIA2_VC_USB_CTRL_CMD_STATUS_DIR   0x08
+#define CPIA2_VC_USB_CTRL_CMD_NO_CLASH     0x10
+#define CPIA2_VC_USB_CTRL_CMD_MICRO_ACCESS 0x80
+
+#define CPIA2_VC_USB_STRM                  0xA9
+#define CPIA2_VC_USB_STRM_ISO_ENABLE    0x01
+#define CPIA2_VC_USB_STRM_BLK_ENABLE    0x02
+#define CPIA2_VC_USB_STRM_INT_ENABLE    0x04
+#define CPIA2_VC_USB_STRM_AUD_ENABLE    0x08
+
+#define CPIA2_VC_USB_STATUS                   0xAA
+#define CPIA2_VC_USB_STATUS_CMD_IN_PROGRESS  0x01
+#define CPIA2_VC_USB_STATUS_CMD_STATUS_STALL 0x02
+#define CPIA2_VC_USB_STATUS_CMD_HANDSHAKE    0x04
+#define CPIA2_VC_USB_STATUS_CMD_OVERRIDE     0x08
+#define CPIA2_VC_USB_STATUS_CMD_FIFO_BUSY    0x10
+#define CPIA2_VC_USB_STATUS_BULK_REPEAT_TXN  0x20
+#define CPIA2_VC_USB_STATUS_CONFIG_DONE      0x40
+#define CPIA2_VC_USB_STATUS_USB_SUSPEND      0x80
+
+#define CPIA2_VC_USB_CMDW                   0xAB
+
+#define CPIA2_VC_USB_DATARW                 0xAC
+
+#define CPIA2_VC_USB_INFO                   0xAD
+
+#define CPIA2_VC_USB_CONFIG                 0xAE
+
+#define CPIA2_VC_USB_SETTINGS                  0xAF
+#define CPIA2_VC_USB_SETTINGS_CONFIG_MASK    0x03
+#define CPIA2_VC_USB_SETTINGS_INTERFACE_MASK 0x0C
+#define CPIA2_VC_USB_SETTINGS_ALTERNATE_MASK 0x70
+
+#define CPIA2_VC_USB_ISOLIM                  0xB0
+
+#define CPIA2_VC_USB_ISOFAILS                0xB1
+
+#define CPIA2_VC_USB_ISOMAXPKTHI             0xB2
+
+#define CPIA2_VC_USB_ISOMAXPKTLO             0xB3
+
+#define CPIA2_VC_V2W_CTRL                    0xB8
+#define CPIA2_VC_V2W_SELECT               0x01
+
+#define CPIA2_VC_V2W_SCL                     0xB9
+
+#define CPIA2_VC_V2W_SDA                     0xBA
+
+#define CPIA2_VC_VC_CTRL                     0xC0
+#define CPIA2_VC_VC_CTRL_RUN              0x01
+#define CPIA2_VC_VC_CTRL_SINGLESHOT       0x02
+#define CPIA2_VC_VC_CTRL_IDLING           0x04
+#define CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES 0x10
+#define CPIA2_VC_VC_CTRL_INHIBIT_Q_TABLES 0x20
+#define CPIA2_VC_VC_CTRL_INHIBIT_PRIVATE  0x40
+
+#define CPIA2_VC_VC_RESTART_IVAL_HI          0xC1
+
+#define CPIA2_VC_VC_RESTART_IVAL_LO          0xC2
+
+#define CPIA2_VC_VC_FORMAT                   0xC3
+#define CPIA2_VC_VC_FORMAT_UFIRST         0x01
+#define CPIA2_VC_VC_FORMAT_MONO           0x02
+#define CPIA2_VC_VC_FORMAT_DECIMATING     0x04
+#define CPIA2_VC_VC_FORMAT_SHORTLINE      0x08
+#define CPIA2_VC_VC_FORMAT_SELFTEST       0x10
+
+#define CPIA2_VC_VC_CLOCKS                         0xC4
+#define CPIA2_VC_VC_CLOCKS_CLKDIV_MASK        0x03
+#define CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3   0x04
+#define CPIA2_VC_VC_672_CLOCKS_SCALING        0x08
+#define CPIA2_VC_VC_CLOCKS_LOGDIV0        0x00
+#define CPIA2_VC_VC_CLOCKS_LOGDIV1        0x01
+#define CPIA2_VC_VC_CLOCKS_LOGDIV2        0x02
+#define CPIA2_VC_VC_CLOCKS_LOGDIV3        0x03
+#define CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3   0x08
+#define CPIA2_VC_VC_676_CLOCKS_SCALING	      0x10
+
+#define CPIA2_VC_VC_IHSIZE_LO                0xC5
+
+#define CPIA2_VC_VC_XLIM_HI                  0xC6
+
+#define CPIA2_VC_VC_XLIM_LO                  0xC7
+
+#define CPIA2_VC_VC_YLIM_HI                  0xC8
+
+#define CPIA2_VC_VC_YLIM_LO                  0xC9
+
+#define CPIA2_VC_VC_OHSIZE                   0xCA
+
+#define CPIA2_VC_VC_OVSIZE                   0xCB
+
+#define CPIA2_VC_VC_HCROP                    0xCC
+
+#define CPIA2_VC_VC_VCROP                    0xCD
+
+#define CPIA2_VC_VC_HPHASE                   0xCE
+
+#define CPIA2_VC_VC_VPHASE                   0xCF
+
+#define CPIA2_VC_VC_HISPAN                   0xD0
+
+#define CPIA2_VC_VC_VISPAN                   0xD1
+
+#define CPIA2_VC_VC_HICROP                   0xD2
+
+#define CPIA2_VC_VC_VICROP                   0xD3
+
+#define CPIA2_VC_VC_HFRACT                   0xD4
+#define CPIA2_VC_VC_HFRACT_DEN_MASK       0x0F
+#define CPIA2_VC_VC_HFRACT_NUM_MASK       0xF0
+
+#define CPIA2_VC_VC_VFRACT                   0xD5
+#define CPIA2_VC_VC_VFRACT_DEN_MASK       0x0F
+#define CPIA2_VC_VC_VFRACT_NUM_MASK       0xF0
+
+#define CPIA2_VC_VC_JPEG_OPT                      0xD6
+#define CPIA2_VC_VC_JPEG_OPT_DOUBLE_SQUEEZE     0x01
+#define CPIA2_VC_VC_JPEG_OPT_NO_DC_AUTO_SQUEEZE 0x02
+#define CPIA2_VC_VC_JPEG_OPT_AUTO_SQUEEZE       0x04
+#define CPIA2_VC_VC_JPEG_OPT_DEFAULT      (CPIA2_VC_VC_JPEG_OPT_DOUBLE_SQUEEZE|\
+					   CPIA2_VC_VC_JPEG_OPT_AUTO_SQUEEZE)
+
+
+#define CPIA2_VC_VC_CREEP_PERIOD             0xD7
+#define CPIA2_VC_VC_USER_SQUEEZE             0xD8
+#define CPIA2_VC_VC_TARGET_KB                0xD9
+
+#define CPIA2_VC_VC_AUTO_SQUEEZE             0xE6
+
+
+/***
+ * VP register set (Bank 2)
+ ***/
+#define CPIA2_VP_DEVICEH                             0
+#define CPIA2_VP_DEVICEL                             1
+
+#define CPIA2_VP_SYSTEMSTATE                         0x02
+#define CPIA2_VP_SYSTEMSTATE_HK_ALIVE             0x01
+
+#define CPIA2_VP_SYSTEMCTRL                          0x03
+#define CPIA2_VP_SYSTEMCTRL_REQ_CLEAR_ERROR       0x80
+#define CPIA2_VP_SYSTEMCTRL_POWER_DOWN_PLL        0x20
+#define CPIA2_VP_SYSTEMCTRL_REQ_SUSPEND_STATE     0x10
+#define CPIA2_VP_SYSTEMCTRL_REQ_SERIAL_WAKEUP     0x08
+#define CPIA2_VP_SYSTEMCTRL_REQ_AUTOLOAD          0x04
+#define CPIA2_VP_SYSTEMCTRL_HK_CONTROL            0x02
+#define CPIA2_VP_SYSTEMCTRL_POWER_CONTROL         0x01
+
+#define CPIA2_VP_SENSOR_FLAGS                        0x05
+#define CPIA2_VP_SENSOR_FLAGS_404                 0x01
+#define CPIA2_VP_SENSOR_FLAGS_407                 0x02
+#define CPIA2_VP_SENSOR_FLAGS_409                 0x04
+#define CPIA2_VP_SENSOR_FLAGS_410                 0x08
+#define CPIA2_VP_SENSOR_FLAGS_500                 0x10
+
+#define CPIA2_VP_SENSOR_REV                          0x06
+
+#define CPIA2_VP_DEVICE_CONFIG                       0x07
+#define CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE      0x01
+
+#define CPIA2_VP_GPIO_DIRECTION                      0x08
+#define CPIA2_VP_GPIO_READ                        0xFF
+#define CPIA2_VP_GPIO_WRITE                       0x00
+
+#define CPIA2_VP_GPIO_DATA                           0x09
+
+#define CPIA2_VP_RAM_ADDR_H                          0x0A
+#define CPIA2_VP_RAM_ADDR_L                          0x0B
+#define CPIA2_VP_RAM_DATA                            0x0C
+
+#define CPIA2_VP_PATCH_REV                           0x0F
+
+#define CPIA2_VP4_USER_MODE                           0x10
+#define CPIA2_VP5_USER_MODE                           0x13
+#define CPIA2_VP_USER_MODE_CIF                    0x01
+#define CPIA2_VP_USER_MODE_QCIFDS                 0x02
+#define CPIA2_VP_USER_MODE_QCIFPTC                0x04
+#define CPIA2_VP_USER_MODE_QVGADS                 0x08
+#define CPIA2_VP_USER_MODE_QVGAPTC                0x10
+#define CPIA2_VP_USER_MODE_VGA                    0x20
+
+#define CPIA2_VP4_FRAMERATE_REQUEST                    0x11
+#define CPIA2_VP5_FRAMERATE_REQUEST                    0x14
+#define CPIA2_VP_FRAMERATE_60                     0x80
+#define CPIA2_VP_FRAMERATE_50                     0x40
+#define CPIA2_VP_FRAMERATE_30                     0x20
+#define CPIA2_VP_FRAMERATE_25                     0x10
+#define CPIA2_VP_FRAMERATE_15                     0x08
+#define CPIA2_VP_FRAMERATE_12_5                   0x04
+#define CPIA2_VP_FRAMERATE_7_5                    0x02
+#define CPIA2_VP_FRAMERATE_6_25                   0x01
+
+#define CPIA2_VP4_USER_EFFECTS                         0x12
+#define CPIA2_VP5_USER_EFFECTS                         0x15
+#define CPIA2_VP_USER_EFFECTS_COLBARS             0x01
+#define CPIA2_VP_USER_EFFECTS_COLBARS_GRAD        0x02
+#define CPIA2_VP_USER_EFFECTS_MIRROR              0x04
+#define CPIA2_VP_USER_EFFECTS_FLIP                0x40  // VP5 only
+
+/* NOTE: CPIA2_VP_EXPOSURE_MODES shares the same register as VP5 User
+ * Effects */
+#define CPIA2_VP_EXPOSURE_MODES                       0x15
+#define CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER   0x20
+#define CPIA2_VP_EXPOSURE_MODES_COMPILE_EXP       0x10
+
+#define CPIA2_VP4_EXPOSURE_TARGET                     0x16    // VP4
+#define CPIA2_VP5_EXPOSURE_TARGET		      0x20    // VP5
+
+#define CPIA2_VP_FLICKER_MODES                        0x1B
+#define CPIA2_VP_FLICKER_MODES_50HZ               0x80
+#define CPIA2_VP_FLICKER_MODES_CUSTOM_FLT_FFREQ   0x40
+#define CPIA2_VP_FLICKER_MODES_NEVER_FLICKER      0x20
+#define CPIA2_VP_FLICKER_MODES_INHIBIT_RUB        0x10
+#define CPIA2_VP_FLICKER_MODES_ADJUST_LINE_FREQ   0x08
+#define CPIA2_VP_FLICKER_MODES_CUSTOM_INT_FFREQ   0x04
+
+#define CPIA2_VP_UMISC                                0x1D
+#define CPIA2_VP_UMISC_FORCE_MONO                 0x80
+#define CPIA2_VP_UMISC_FORCE_ID_MASK              0x40
+#define CPIA2_VP_UMISC_INHIBIT_AUTO_FGS           0x20
+#define CPIA2_VP_UMISC_INHIBIT_AUTO_DIMS          0x08
+#define CPIA2_VP_UMISC_OPT_FOR_SENSOR_DS          0x04
+#define CPIA2_VP_UMISC_INHIBIT_AUTO_MODE_INT      0x02
+
+#define CPIA2_VP5_ANTIFLKRSETUP                       0x22  //34
+
+#define CPIA2_VP_INTERPOLATION                        0x24
+#define CPIA2_VP_INTERPOLATION_EVEN_FIRST         0x40
+#define CPIA2_VP_INTERPOLATION_HJOG               0x20
+#define CPIA2_VP_INTERPOLATION_VJOG               0x10
+
+#define CPIA2_VP_GAMMA                                0x25
+#define CPIA2_VP_DEFAULT_GAMMA                    0x10
+
+#define CPIA2_VP_YRANGE                               0x26
+
+#define CPIA2_VP_SATURATION                           0x27
+
+#define CPIA2_VP5_MYBLACK_LEVEL                       0x3A   //58
+#define CPIA2_VP5_MCYRANGE                            0x3B   //59
+#define CPIA2_VP5_MYCEILING                           0x3C   //60
+#define CPIA2_VP5_MCUVSATURATION                      0x3D   //61
+
+
+#define CPIA2_VP_REHASH_VALUES                        0x60
+
+
+/***
+ * Common sensor registers
+ ***/
+#define CPIA2_SENSOR_DEVICE_H                         0x00
+#define CPIA2_SENSOR_DEVICE_L                         0x01
+
+#define CPIA2_SENSOR_DATA_FORMAT                      0x16
+#define CPIA2_SENSOR_DATA_FORMAT_HMIRROR      0x08
+#define CPIA2_SENSOR_DATA_FORMAT_VMIRROR      0x10
+
+#define CPIA2_SENSOR_CR1                              0x76
+#define CPIA2_SENSOR_CR1_STAND_BY             0x01
+#define CPIA2_SENSOR_CR1_DOWN_RAMP_GEN        0x02
+#define CPIA2_SENSOR_CR1_DOWN_COLUMN_ADC      0x04
+#define CPIA2_SENSOR_CR1_DOWN_CAB_REGULATOR   0x08
+#define CPIA2_SENSOR_CR1_DOWN_AUDIO_REGULATOR 0x10
+#define CPIA2_SENSOR_CR1_DOWN_VRT_AMP         0x20
+#define CPIA2_SENSOR_CR1_DOWN_BAND_GAP        0x40
+
+#endif
diff --git a/drivers/media/video/cpia2/cpia2_usb.c b/drivers/media/video/cpia2/cpia2_usb.c
new file mode 100644
index 0000000..f4da029
--- /dev/null
+++ b/drivers/media/video/cpia2/cpia2_usb.c
@@ -0,0 +1,907 @@
+/****************************************************************************
+ *
+ *  Filename: cpia2_usb.c
+ *
+ *  Copyright 2001, STMicrolectronics, Inc.
+ *      Contact:  steve.miller@st.com
+ *
+ *  Description:
+ *     This is a USB driver for CPia2 based video cameras.
+ *     The infrastructure of this driver is based on the cpia usb driver by
+ *     Jochen Scharrlach and Johannes Erdfeldt.
+ *
+ *  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.
+ *
+ *  Stripped of 2.4 stuff ready for main kernel submit by
+ *		Alan Cox <alan@redhat.com>
+ ****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include "cpia2.h"
+
+static int frame_sizes[] = {
+	0,	// USBIF_CMDONLY
+	0, 	// USBIF_BULK
+	128, 	// USBIF_ISO_1
+	384, 	// USBIF_ISO_2
+	640, 	// USBIF_ISO_3
+	768, 	// USBIF_ISO_4
+	896, 	// USBIF_ISO_5
+	1023, 	// USBIF_ISO_6
+};
+
+#define FRAMES_PER_DESC    10
+#define FRAME_SIZE_PER_DESC   frame_sizes[cam->cur_alt]
+
+static void process_frame(struct camera_data *cam);
+static void cpia2_usb_complete(struct urb *urb, struct pt_regs *);
+static int cpia2_usb_probe(struct usb_interface *intf,
+			   const struct usb_device_id *id);
+static void cpia2_usb_disconnect(struct usb_interface *intf);
+
+static void free_sbufs(struct camera_data *cam);
+static void add_APPn(struct camera_data *cam);
+static void add_COM(struct camera_data *cam);
+static int submit_urbs(struct camera_data *cam);
+static int set_alternate(struct camera_data *cam, unsigned int alt);
+static int configure_transfer_mode(struct camera_data *cam, unsigned int alt);
+
+static struct usb_device_id cpia2_id_table[] = {
+	{USB_DEVICE(0x0553, 0x0100)},
+	{USB_DEVICE(0x0553, 0x0140)},
+	{USB_DEVICE(0x0553, 0x0151)},  /* STV0676 */
+	{}			/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, cpia2_id_table);
+
+static struct usb_driver cpia2_driver = {
+	.name		= "cpia2",
+	.probe		= cpia2_usb_probe,
+	.disconnect	= cpia2_usb_disconnect,
+	.id_table	= cpia2_id_table
+};
+
+
+/******************************************************************************
+ *
+ *  process_frame
+ *
+ *****************************************************************************/
+static void process_frame(struct camera_data *cam)
+{
+	static int frame_count = 0;
+
+	unsigned char *inbuff = cam->workbuff->data;
+
+	DBG("Processing frame #%d, current:%d\n",
+	    cam->workbuff->num, cam->curbuff->num);
+
+	if(cam->workbuff->length > cam->workbuff->max_length)
+		cam->workbuff->max_length = cam->workbuff->length;
+
+	if ((inbuff[0] == 0xFF) && (inbuff[1] == 0xD8)) {
+		frame_count++;
+	} else {
+		cam->workbuff->status = FRAME_ERROR;
+		DBG("Start of frame not found\n");
+		return;
+	}
+
+	/***
+	 * Now the output buffer should have a JPEG image in it.
+	 ***/
+	if(!cam->first_image_seen) {
+		/* Always skip the first image after streaming
+		 * starts. It is almost certainly corrupt. */
+		cam->first_image_seen = 1;
+		cam->workbuff->status = FRAME_EMPTY;
+		return;
+	}
+	if (cam->workbuff->length > 3) {
+		if(cam->mmapped &&
+		   cam->workbuff->length < cam->workbuff->max_length) {
+			/* No junk in the buffers */
+			memset(cam->workbuff->data+cam->workbuff->length,
+			       0, cam->workbuff->max_length-
+				  cam->workbuff->length);
+		}
+		cam->workbuff->max_length = cam->workbuff->length;
+		cam->workbuff->status = FRAME_READY;
+
+		if(!cam->mmapped && cam->num_frames > 2) {
+			/* During normal reading, the most recent
+			 * frame will be read.  If the current frame
+			 * hasn't started reading yet, it will never
+			 * be read, so mark it empty.  If the buffer is
+			 * mmapped, or we have few buffers, we need to
+			 * wait for the user to free the buffer.
+			 *
+			 * NOTE: This is not entirely foolproof with 3
+			 * buffers, but it would take an EXTREMELY
+			 * overloaded system to cause problems (possible
+			 * image data corruption).  Basically, it would
+			 * need to take more time to execute cpia2_read
+			 * than it would for the camera to send
+			 * cam->num_frames-2 frames before problems
+			 * could occur.
+			 */
+			cam->curbuff->status = FRAME_EMPTY;
+		}
+		cam->curbuff = cam->workbuff;
+		cam->workbuff = cam->workbuff->next;
+		DBG("Changed buffers, work:%d, current:%d\n",
+		    cam->workbuff->num, cam->curbuff->num);
+		return;
+	} else {
+		DBG("Not enough data for an image.\n");
+	}
+
+	cam->workbuff->status = FRAME_ERROR;
+	return;
+}
+
+/******************************************************************************
+ *
+ *  add_APPn
+ *
+ *  Adds a user specified APPn record
+ *****************************************************************************/
+static void add_APPn(struct camera_data *cam)
+{
+	if(cam->APP_len > 0) {
+		cam->workbuff->data[cam->workbuff->length++] = 0xFF;
+		cam->workbuff->data[cam->workbuff->length++] = 0xE0+cam->APPn;
+		cam->workbuff->data[cam->workbuff->length++] = 0;
+		cam->workbuff->data[cam->workbuff->length++] = cam->APP_len+2;
+		memcpy(cam->workbuff->data+cam->workbuff->length,
+		       cam->APP_data, cam->APP_len);
+		cam->workbuff->length += cam->APP_len;
+	}
+}
+
+/******************************************************************************
+ *
+ *  add_COM
+ *
+ *  Adds a user specified COM record
+ *****************************************************************************/
+static void add_COM(struct camera_data *cam)
+{
+	if(cam->COM_len > 0) {
+		cam->workbuff->data[cam->workbuff->length++] = 0xFF;
+		cam->workbuff->data[cam->workbuff->length++] = 0xFE;
+		cam->workbuff->data[cam->workbuff->length++] = 0;
+		cam->workbuff->data[cam->workbuff->length++] = cam->COM_len+2;
+		memcpy(cam->workbuff->data+cam->workbuff->length,
+		       cam->COM_data, cam->COM_len);
+		cam->workbuff->length += cam->COM_len;
+	}
+}
+
+/******************************************************************************
+ *
+ *  cpia2_usb_complete
+ *
+ *  callback when incoming packet is received
+ *****************************************************************************/
+static void cpia2_usb_complete(struct urb *urb, struct pt_regs *regs)
+{
+	int i;
+	unsigned char *cdata;
+	static int frame_ready = false;
+	struct camera_data *cam = (struct camera_data *) urb->context;
+
+	if (urb->status!=0) {
+		if (!(urb->status == -ENOENT ||
+		      urb->status == -ECONNRESET ||
+		      urb->status == -ESHUTDOWN))
+		{
+			DBG("urb->status = %d!\n", urb->status);
+		}
+		DBG("Stopping streaming\n");
+		return;
+	}
+
+	if (!cam->streaming || !cam->present || cam->open_count == 0) {
+		LOG("Will now stop the streaming: streaming = %d, "
+		    "present=%d, open_count=%d\n",
+		    cam->streaming, cam->present, cam->open_count);
+		return;
+	}
+
+	/***
+	 * Packet collater
+	 ***/
+	//DBG("Collating %d packets\n", urb->number_of_packets);
+	for (i = 0; i < urb->number_of_packets; i++) {
+		u16 checksum, iso_checksum;
+		int j;
+		int n = urb->iso_frame_desc[i].actual_length;
+		int st = urb->iso_frame_desc[i].status;
+
+		if(cam->workbuff->status == FRAME_READY) {
+			struct framebuf *ptr;
+			/* Try to find an available buffer */
+			DBG("workbuff full, searching\n");
+			for (ptr = cam->workbuff->next;
+			     ptr != cam->workbuff;
+			     ptr = ptr->next)
+			{
+				if (ptr->status == FRAME_EMPTY) {
+					ptr->status = FRAME_READING;
+					ptr->length = 0;
+					break;
+				}
+			}
+			if (ptr == cam->workbuff)
+				break; /* No READING or EMPTY buffers left */
+
+			cam->workbuff = ptr;
+		}
+
+		if (cam->workbuff->status == FRAME_EMPTY ||
+		    cam->workbuff->status == FRAME_ERROR) {
+			cam->workbuff->status = FRAME_READING;
+			cam->workbuff->length = 0;
+		}
+
+		//DBG("   Packet %d length = %d, status = %d\n", i, n, st);
+		cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+
+		if (st) {
+			LOG("cpia2 data error: [%d] len=%d, status = %d\n",
+			    i, n, st);
+			if(!ALLOW_CORRUPT)
+				cam->workbuff->status = FRAME_ERROR;
+			continue;
+		}
+
+		if(n<=2)
+			continue;
+
+		checksum = 0;
+		for(j=0; j<n-2; ++j)
+			checksum += cdata[j];
+		iso_checksum = cdata[j] + cdata[j+1]*256;
+		if(checksum != iso_checksum) {
+			LOG("checksum mismatch: [%d] len=%d, calculated = %x, checksum = %x\n",
+			    i, n, (int)checksum, (int)iso_checksum);
+			if(!ALLOW_CORRUPT) {
+				cam->workbuff->status = FRAME_ERROR;
+				continue;
+			}
+		}
+		n -= 2;
+
+		if(cam->workbuff->status != FRAME_READING) {
+			if((0xFF == cdata[0] && 0xD8 == cdata[1]) ||
+			   (0xD8 == cdata[0] && 0xFF == cdata[1] &&
+			    0 != cdata[2])) {
+				/* frame is skipped, but increment total
+				 * frame count anyway */
+				cam->frame_count++;
+			}
+			DBG("workbuff not reading, status=%d\n",
+			    cam->workbuff->status);
+			continue;
+		}
+
+		if (cam->frame_size < cam->workbuff->length + n) {
+			ERR("buffer overflow! length: %d, n: %d\n",
+			    cam->workbuff->length, n);
+			cam->workbuff->status = FRAME_ERROR;
+			if(cam->workbuff->length > cam->workbuff->max_length)
+				cam->workbuff->max_length =
+					cam->workbuff->length;
+			continue;
+		}
+
+		if (cam->workbuff->length == 0) {
+			int data_offset;
+			if ((0xD8 == cdata[0]) && (0xFF == cdata[1])) {
+				data_offset = 1;
+			} else if((0xFF == cdata[0]) && (0xD8 == cdata[1])
+				  && (0xFF == cdata[2])) {
+				data_offset = 2;
+			} else {
+				DBG("Ignoring packet, not beginning!\n");
+				continue;
+			}
+			DBG("Start of frame pattern found\n");
+			do_gettimeofday(&cam->workbuff->timestamp);
+			cam->workbuff->seq = cam->frame_count++;
+			cam->workbuff->data[0] = 0xFF;
+			cam->workbuff->data[1] = 0xD8;
+			cam->workbuff->length = 2;
+			add_APPn(cam);
+			add_COM(cam);
+			memcpy(cam->workbuff->data+cam->workbuff->length,
+			       cdata+data_offset, n-data_offset);
+			cam->workbuff->length += n-data_offset;
+		} else if (cam->workbuff->length > 0) {
+			memcpy(cam->workbuff->data + cam->workbuff->length,
+			       cdata, n);
+			cam->workbuff->length += n;
+		}
+
+		if ((cam->workbuff->length >= 3) &&
+		    (cam->workbuff->data[cam->workbuff->length - 3] == 0xFF) &&
+		    (cam->workbuff->data[cam->workbuff->length - 2] == 0xD9) &&
+		    (cam->workbuff->data[cam->workbuff->length - 1] == 0xFF)) {
+			frame_ready = true;
+			cam->workbuff->data[cam->workbuff->length - 1] = 0;
+			cam->workbuff->length -= 1;
+		} else if ((cam->workbuff->length >= 2) &&
+		   (cam->workbuff->data[cam->workbuff->length - 2] == 0xFF) &&
+		   (cam->workbuff->data[cam->workbuff->length - 1] == 0xD9)) {
+			frame_ready = true;
+		}
+
+		if (frame_ready) {
+			DBG("Workbuff image size = %d\n",cam->workbuff->length);
+			process_frame(cam);
+
+			frame_ready = false;
+
+			if (waitqueue_active(&cam->wq_stream))
+				wake_up_interruptible(&cam->wq_stream);
+		}
+	}
+
+	if(cam->streaming) {
+		/* resubmit */
+		urb->dev = cam->dev;
+		if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0)
+			ERR("%s: usb_submit_urb ret %d!\n", __func__, i);
+	}
+}
+
+/******************************************************************************
+ *
+ * configure_transfer_mode
+ *
+ *****************************************************************************/
+static int configure_transfer_mode(struct camera_data *cam, unsigned int alt)
+{
+	static unsigned char iso_regs[8][4] = {
+		{0x00, 0x00, 0x00, 0x00},
+		{0x00, 0x00, 0x00, 0x00},
+		{0xB9, 0x00, 0x00, 0x7E},
+		{0xB9, 0x00, 0x01, 0x7E},
+		{0xB9, 0x00, 0x02, 0x7E},
+		{0xB9, 0x00, 0x02, 0xFE},
+		{0xB9, 0x00, 0x03, 0x7E},
+		{0xB9, 0x00, 0x03, 0xFD}
+	};
+	struct cpia2_command cmd;
+	unsigned char reg;
+
+	if(!cam->present)
+		return -ENODEV;
+
+	/***
+	 * Write the isoc registers according to the alternate selected
+	 ***/
+	cmd.direction = TRANSFER_WRITE;
+	cmd.buffer.block_data[0] = iso_regs[alt][0];
+	cmd.buffer.block_data[1] = iso_regs[alt][1];
+	cmd.buffer.block_data[2] = iso_regs[alt][2];
+	cmd.buffer.block_data[3] = iso_regs[alt][3];
+	cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+	cmd.start = CPIA2_VC_USB_ISOLIM;
+	cmd.reg_count = 4;
+	cpia2_send_command(cam, &cmd);
+
+	/***
+	 * Enable relevant streams before starting polling.
+	 * First read USB Stream Config Register.
+	 ***/
+	cmd.direction = TRANSFER_READ;
+	cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+	cmd.start = CPIA2_VC_USB_STRM;
+	cmd.reg_count = 1;
+	cpia2_send_command(cam, &cmd);
+	reg = cmd.buffer.block_data[0];
+
+	/* Clear iso, bulk, and int */
+	reg &= ~(CPIA2_VC_USB_STRM_BLK_ENABLE |
+		 CPIA2_VC_USB_STRM_ISO_ENABLE |
+		 CPIA2_VC_USB_STRM_INT_ENABLE);
+
+	if (alt == USBIF_BULK) {
+		DBG("Enabling bulk xfer\n");
+		reg |= CPIA2_VC_USB_STRM_BLK_ENABLE;	/* Enable Bulk */
+		cam->xfer_mode = XFER_BULK;
+	} else if (alt >= USBIF_ISO_1) {
+		DBG("Enabling ISOC xfer\n");
+		reg |= CPIA2_VC_USB_STRM_ISO_ENABLE;
+		cam->xfer_mode = XFER_ISOC;
+	}
+
+	cmd.buffer.block_data[0] = reg;
+	cmd.direction = TRANSFER_WRITE;
+	cmd.start = CPIA2_VC_USB_STRM;
+	cmd.reg_count = 1;
+	cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+	cpia2_send_command(cam, &cmd);
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ * cpia2_usb_change_streaming_alternate
+ *
+ *****************************************************************************/
+int cpia2_usb_change_streaming_alternate(struct camera_data *cam,
+					 unsigned int alt)
+{
+	int ret = 0;
+
+	if(alt < USBIF_ISO_1 || alt > USBIF_ISO_6)
+		return -EINVAL;
+
+	if(alt == cam->params.camera_state.stream_mode)
+		return 0;
+
+	cpia2_usb_stream_pause(cam);
+
+	configure_transfer_mode(cam, alt);
+
+	cam->params.camera_state.stream_mode = alt;
+
+	/* Reset the camera to prevent image quality degradation */
+	cpia2_reset_camera(cam);
+
+	cpia2_usb_stream_resume(cam);
+
+	return ret;
+}
+
+/******************************************************************************
+ *
+ * set_alternate
+ *
+ *****************************************************************************/
+int set_alternate(struct camera_data *cam, unsigned int alt)
+{
+	int ret = 0;
+
+	if(alt == cam->cur_alt)
+		return 0;
+
+	if (cam->cur_alt != USBIF_CMDONLY) {
+		DBG("Changing from alt %d to %d\n", cam->cur_alt, USBIF_CMDONLY);
+		ret = usb_set_interface(cam->dev, cam->iface, USBIF_CMDONLY);
+		if (ret != 0)
+			return ret;
+	}
+	if (alt != USBIF_CMDONLY) {
+		DBG("Changing from alt %d to %d\n", USBIF_CMDONLY, alt);
+		ret = usb_set_interface(cam->dev, cam->iface, alt);
+		if (ret != 0)
+			return ret;
+	}
+
+	cam->old_alt = cam->cur_alt;
+	cam->cur_alt = alt;
+
+	return ret;
+}
+
+/******************************************************************************
+ *
+ * free_sbufs
+ *
+ * Free all cam->sbuf[]. All non-NULL .data and .urb members that are non-NULL
+ * are assumed to be allocated. Non-NULL .urb members are also assumed to be
+ * submitted (and must therefore be killed before they are freed).
+ *****************************************************************************/
+static void free_sbufs(struct camera_data *cam)
+{
+	int i;
+
+	for (i = 0; i < NUM_SBUF; i++) {
+		if(cam->sbuf[i].urb) {
+			usb_kill_urb(cam->sbuf[i].urb);
+			usb_free_urb(cam->sbuf[i].urb);
+			cam->sbuf[i].urb = NULL;
+		}
+		if(cam->sbuf[i].data) {
+			kfree(cam->sbuf[i].data);
+			cam->sbuf[i].data = NULL;
+		}
+	}
+}
+
+/*******
+* Convenience functions
+*******/
+/****************************************************************************
+ *
+ *  write_packet
+ *
+ ***************************************************************************/
+static int write_packet(struct usb_device *udev,
+			u8 request, u8 * registers, u16 start, size_t size)
+{
+	if (!registers || size <= 0)
+		return -EINVAL;
+
+	return usb_control_msg(udev,
+			       usb_sndctrlpipe(udev, 0),
+			       request,
+			       USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			       start,	/* value */
+			       0,	/* index */
+			       registers,	/* buffer */
+			       size,
+			       HZ);
+}
+
+/****************************************************************************
+ *
+ *  read_packet
+ *
+ ***************************************************************************/
+static int read_packet(struct usb_device *udev,
+		       u8 request, u8 * registers, u16 start, size_t size)
+{
+	if (!registers || size <= 0)
+		return -EINVAL;
+
+	return usb_control_msg(udev,
+			       usb_rcvctrlpipe(udev, 0),
+			       request,
+			       USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_DEVICE,
+			       start,	/* value */
+			       0,	/* index */
+			       registers,	/* buffer */
+			       size,
+			       HZ);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_usb_transfer_cmd
+ *
+ *****************************************************************************/
+int cpia2_usb_transfer_cmd(struct camera_data *cam,
+			   void *registers,
+			   u8 request, u8 start, u8 count, u8 direction)
+{
+	int err = 0;
+	struct usb_device *udev = cam->dev;
+
+	if (!udev) {
+		ERR("%s: Internal driver error: udev is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!registers) {
+		ERR("%s: Internal driver error: register array is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	if (direction == TRANSFER_READ) {
+		err = read_packet(udev, request, (u8 *)registers, start, count);
+		if (err > 0)
+			err = 0;
+	} else if (direction == TRANSFER_WRITE) {
+		err =write_packet(udev, request, (u8 *)registers, start, count);
+		if (err < 0) {
+			LOG("Control message failed, err val = %d\n", err);
+			LOG("Message: request = 0x%0X, start = 0x%0X\n",
+			    request, start);
+			LOG("Message: count = %d, register[0] = 0x%0X\n",
+			    count, ((unsigned char *) registers)[0]);
+		} else
+			err=0;
+	} else {
+		LOG("Unexpected first byte of direction: %d\n",
+		       direction);
+		return -EINVAL;
+	}
+
+	if(err != 0)
+		LOG("Unexpected error: %d\n", err);
+	return err;
+}
+
+
+/******************************************************************************
+ *
+ *  submit_urbs
+ *
+ *****************************************************************************/
+static int submit_urbs(struct camera_data *cam)
+{
+	struct urb *urb;
+	int fx, err, i;
+
+	for(i=0; i<NUM_SBUF; ++i) {
+		if (cam->sbuf[i].data)
+			continue;
+		cam->sbuf[i].data =
+		    kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
+		if (!cam->sbuf[i].data) {
+			return -ENOMEM;
+		}
+	}
+
+	/* We double buffer the Isoc lists, and also know the polling
+	 * interval is every frame (1 == (1 << (bInterval -1))).
+	 */
+	for(i=0; i<NUM_SBUF; ++i) {
+		if(cam->sbuf[i].urb) {
+			continue;
+		}
+		urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
+		if (!urb) {
+			return -ENOMEM;
+		}
+
+		cam->sbuf[i].urb = urb;
+		urb->dev = cam->dev;
+		urb->context = cam;
+		urb->pipe = usb_rcvisocpipe(cam->dev, 1 /*ISOC endpoint*/);
+		urb->transfer_flags = URB_ISO_ASAP;
+		urb->transfer_buffer = cam->sbuf[i].data;
+		urb->complete = cpia2_usb_complete;
+		urb->number_of_packets = FRAMES_PER_DESC;
+		urb->interval = 1;
+		urb->transfer_buffer_length =
+			FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
+
+		for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
+			urb->iso_frame_desc[fx].offset =
+				FRAME_SIZE_PER_DESC * fx;
+			urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
+		}
+	}
+
+
+	/* Queue the ISO urbs, and resubmit in the completion handler */
+	for(i=0; i<NUM_SBUF; ++i) {
+		err = usb_submit_urb(cam->sbuf[i].urb, GFP_KERNEL);
+		if (err) {
+			ERR("usb_submit_urb[%d]() = %d\n", i, err);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_usb_stream_start
+ *
+ *****************************************************************************/
+int cpia2_usb_stream_start(struct camera_data *cam, unsigned int alternate)
+{
+	int ret;
+	int old_alt;
+
+	if(cam->streaming)
+		return 0;
+
+	if (cam->flush) {
+		int i;
+		DBG("Flushing buffers\n");
+		for(i=0; i<cam->num_frames; ++i) {
+			cam->buffers[i].status = FRAME_EMPTY;
+			cam->buffers[i].length = 0;
+		}
+		cam->curbuff = &cam->buffers[0];
+		cam->workbuff = cam->curbuff->next;
+		cam->flush = false;
+	}
+
+	old_alt = cam->params.camera_state.stream_mode;
+	cam->params.camera_state.stream_mode = 0;
+	ret = cpia2_usb_change_streaming_alternate(cam, alternate);
+	if (ret < 0) {
+		int ret2;
+		ERR("cpia2_usb_change_streaming_alternate() = %d!\n", ret);
+		cam->params.camera_state.stream_mode = old_alt;
+		ret2 = set_alternate(cam, USBIF_CMDONLY);
+		if (ret2 < 0) {
+			ERR("cpia2_usb_change_streaming_alternate(%d) =%d has already "
+			    "failed. Then tried to call "
+			    "set_alternate(USBIF_CMDONLY) = %d.\n",
+			    alternate, ret, ret2);
+		}
+	} else {
+		cam->frame_count = 0;
+		cam->streaming = 1;
+		ret = cpia2_usb_stream_resume(cam);
+	}
+	return ret;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_usb_stream_pause
+ *
+ *****************************************************************************/
+int cpia2_usb_stream_pause(struct camera_data *cam)
+{
+	int ret = 0;
+	if(cam->streaming) {
+		ret = set_alternate(cam, USBIF_CMDONLY);
+		free_sbufs(cam);
+	}
+	return ret;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_usb_stream_resume
+ *
+ *****************************************************************************/
+int cpia2_usb_stream_resume(struct camera_data *cam)
+{
+	int ret = 0;
+	if(cam->streaming) {
+		cam->first_image_seen = 0;
+		ret = set_alternate(cam, cam->params.camera_state.stream_mode);
+		if(ret == 0) {
+			ret = submit_urbs(cam);
+		}
+	}
+	return ret;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_usb_stream_stop
+ *
+ *****************************************************************************/
+int cpia2_usb_stream_stop(struct camera_data *cam)
+{
+	int ret;
+	ret = cpia2_usb_stream_pause(cam);
+	cam->streaming = 0;
+	configure_transfer_mode(cam, 0);
+	return ret;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_usb_probe
+ *
+ *  Probe and initialize.
+ *****************************************************************************/
+static int cpia2_usb_probe(struct usb_interface *intf,
+			   const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev(intf);
+	struct usb_interface_descriptor *interface;
+	struct camera_data *cam;
+	int ret;
+
+	/* A multi-config CPiA2 camera? */
+	if (udev->descriptor.bNumConfigurations != 1)
+		return -ENODEV;
+	interface = &intf->cur_altsetting->desc;
+
+	/* If we get to this point, we found a CPiA2 camera */
+	LOG("CPiA2 USB camera found\n");
+
+	if((cam = cpia2_init_camera_struct()) == NULL)
+		return -ENOMEM;
+
+	cam->dev = udev;
+	cam->iface = interface->bInterfaceNumber;
+
+	ret = set_alternate(cam, USBIF_CMDONLY);
+	if (ret < 0) {
+		ERR("%s: usb_set_interface error (ret = %d)\n", __func__, ret);
+		kfree(cam);
+		return ret;
+	}
+
+	if ((ret = cpia2_register_camera(cam)) < 0) {
+		ERR("%s: Failed to register cpia2 camera (ret = %d)\n", __func__, ret);
+		kfree(cam);
+		return ret;
+	}
+
+
+	if((ret = cpia2_init_camera(cam)) < 0) {
+		ERR("%s: failed to initialize cpia2 camera (ret = %d)\n", __func__, ret);
+		cpia2_unregister_camera(cam);
+		kfree(cam);
+		return ret;
+	}
+	LOG("  CPiA Version: %d.%02d (%d.%d)\n",
+	       cam->params.version.firmware_revision_hi,
+	       cam->params.version.firmware_revision_lo,
+	       cam->params.version.asic_id,
+	       cam->params.version.asic_rev);
+	LOG("  CPiA PnP-ID: %04x:%04x:%04x\n",
+	       cam->params.pnp_id.vendor,
+	       cam->params.pnp_id.product,
+	       cam->params.pnp_id.device_revision);
+	LOG("  SensorID: %d.(version %d)\n",
+	       cam->params.version.sensor_flags,
+	       cam->params.version.sensor_rev);
+
+	usb_set_intfdata(intf, cam);
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_disconnect
+ *
+ *****************************************************************************/
+static void cpia2_usb_disconnect(struct usb_interface *intf)
+{
+	struct camera_data *cam = usb_get_intfdata(intf);
+	usb_set_intfdata(intf, NULL);
+	cam->present = 0;
+
+	DBG("Stopping stream\n");
+	cpia2_usb_stream_stop(cam);
+
+	DBG("Unregistering camera\n");
+	cpia2_unregister_camera(cam);
+
+	if(cam->buffers) {
+		DBG("Wakeup waiting processes\n");
+		cam->curbuff->status = FRAME_READY;
+		cam->curbuff->length = 0;
+		if (waitqueue_active(&cam->wq_stream))
+			wake_up_interruptible(&cam->wq_stream);
+	}
+
+	DBG("Releasing interface\n");
+	usb_driver_release_interface(&cpia2_driver, intf);
+
+	if (cam->open_count == 0) {
+		DBG("Freeing camera structure\n");
+		kfree(cam);
+	}
+
+	LOG("CPiA2 camera disconnected.\n");
+}
+
+
+/******************************************************************************
+ *
+ *  usb_cpia2_init
+ *
+ *****************************************************************************/
+int cpia2_usb_init(void)
+{
+	return usb_register(&cpia2_driver);
+}
+
+/******************************************************************************
+ *
+ *  usb_cpia_cleanup
+ *
+ *****************************************************************************/
+void cpia2_usb_cleanup(void)
+{
+	schedule_timeout(2 * HZ);
+	usb_deregister(&cpia2_driver);
+}
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c
new file mode 100644
index 0000000..08f8be3
--- /dev/null
+++ b/drivers/media/video/cpia2/cpia2_v4l.c
@@ -0,0 +1,2079 @@
+/****************************************************************************
+ *
+ *  Filename: cpia2_v4l.c
+ *
+ *  Copyright 2001, STMicrolectronics, Inc.
+ *      Contact:  steve.miller@st.com
+ *  Copyright 2001,2005, Scott J. Bertin <scottbertin@yahoo.com>
+ *
+ *  Description:
+ *     This is a USB driver for CPia2 based video cameras.
+ *     The infrastructure of this driver is based on the cpia usb driver by
+ *     Jochen Scharrlach and Johannes Erdfeldt.
+ *
+ *  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.
+ *
+ *  Stripped of 2.4 stuff ready for main kernel submit by
+ *		Alan Cox <alan@redhat.com>
+ ****************************************************************************/
+
+#include <linux/version.h>
+
+#include <linux/config.h>
+
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+
+#include "cpia2.h"
+#include "cpia2dev.h"
+
+
+//#define _CPIA2_DEBUG_
+
+#define MAKE_STRING_1(x)	#x
+#define MAKE_STRING(x)	MAKE_STRING_1(x)
+
+static int video_nr = -1;
+module_param(video_nr, int, 0);
+MODULE_PARM_DESC(video_nr,"video device to register (0=/dev/video0, etc)");
+
+static int buffer_size = 68*1024;
+module_param(buffer_size, int, 0);
+MODULE_PARM_DESC(buffer_size, "Size for each frame buffer in bytes (default 68k)");
+
+static int num_buffers = 3;
+module_param(num_buffers, int, 0);
+MODULE_PARM_DESC(num_buffers, "Number of frame buffers (1-"
+		 MAKE_STRING(VIDEO_MAX_FRAME) ", default 3)");
+
+static int alternate = DEFAULT_ALT;
+module_param(alternate, int, 0);
+MODULE_PARM_DESC(alternate, "USB Alternate (" MAKE_STRING(USBIF_ISO_1) "-"
+		 MAKE_STRING(USBIF_ISO_6) ", default "
+		 MAKE_STRING(DEFAULT_ALT) ")");
+
+static int flicker_freq = 60;
+module_param(flicker_freq, int, 0);
+MODULE_PARM_DESC(flicker_freq, "Flicker frequency (" MAKE_STRING(50) "or"
+		 MAKE_STRING(60) ", default "
+		 MAKE_STRING(60) ")");
+
+static int flicker_mode = NEVER_FLICKER;
+module_param(flicker_mode, int, 0);
+MODULE_PARM_DESC(flicker_mode,
+		 "Flicker supression (" MAKE_STRING(NEVER_FLICKER) "or"
+		 MAKE_STRING(ANTI_FLICKER_ON) ", default "
+		 MAKE_STRING(NEVER_FLICKER) ")");
+
+MODULE_AUTHOR("Steve Miller (STMicroelectronics) <steve.miller@st.com>");
+MODULE_DESCRIPTION("V4L-driver for STMicroelectronics CPiA2 based cameras");
+MODULE_SUPPORTED_DEVICE("video");
+MODULE_LICENSE("GPL");
+
+#define ABOUT "V4L-Driver for Vision CPiA2 based cameras"
+
+#ifndef VID_HARDWARE_CPIA2
+#error "VID_HARDWARE_CPIA2 should have been defined in linux/videodev.h"
+#endif
+
+struct control_menu_info {
+	int value;
+	char name[32];
+};
+
+static struct control_menu_info framerate_controls[] =
+{
+	{ CPIA2_VP_FRAMERATE_6_25, "6.25 fps" },
+	{ CPIA2_VP_FRAMERATE_7_5,  "7.5 fps"  },
+	{ CPIA2_VP_FRAMERATE_12_5, "12.5 fps" },
+	{ CPIA2_VP_FRAMERATE_15,   "15 fps"   },
+	{ CPIA2_VP_FRAMERATE_25,   "25 fps"   },
+	{ CPIA2_VP_FRAMERATE_30,   "30 fps"   },
+};
+#define NUM_FRAMERATE_CONTROLS (sizeof(framerate_controls)/sizeof(framerate_controls[0]))
+
+static struct control_menu_info flicker_controls[] =
+{
+	{ NEVER_FLICKER, "Off" },
+	{ FLICKER_50,    "50 Hz" },
+	{ FLICKER_60,    "60 Hz"  },
+};
+#define NUM_FLICKER_CONTROLS (sizeof(flicker_controls)/sizeof(flicker_controls[0]))
+
+static struct control_menu_info lights_controls[] =
+{
+	{ 0,   "Off" },
+	{ 64,  "Top" },
+	{ 128, "Bottom"  },
+	{ 192, "Both"  },
+};
+#define NUM_LIGHTS_CONTROLS (sizeof(lights_controls)/sizeof(lights_controls[0]))
+#define GPIO_LIGHTS_MASK 192
+
+static struct v4l2_queryctrl controls[] = {
+	{
+		.id            = V4L2_CID_BRIGHTNESS,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Brightness",
+		.minimum       = 0,
+		.maximum       = 255,
+		.step          = 1,
+		.default_value = DEFAULT_BRIGHTNESS,
+	},
+	{
+		.id            = V4L2_CID_CONTRAST,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Contrast",
+		.minimum       = 0,
+		.maximum       = 255,
+		.step          = 1,
+		.default_value = DEFAULT_CONTRAST,
+	},
+	{
+		.id            = V4L2_CID_SATURATION,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Saturation",
+		.minimum       = 0,
+		.maximum       = 255,
+		.step          = 1,
+		.default_value = DEFAULT_SATURATION,
+	},
+	{
+		.id            = V4L2_CID_HFLIP,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+		.name          = "Mirror Horizontally",
+		.minimum       = 0,
+		.maximum       = 1,
+		.step          = 1,
+		.default_value = 0,
+	},
+	{
+		.id            = V4L2_CID_VFLIP,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+		.name          = "Flip Vertically",
+		.minimum       = 0,
+		.maximum       = 1,
+		.step          = 1,
+		.default_value = 0,
+	},
+	{
+		.id            = CPIA2_CID_TARGET_KB,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Target KB",
+		.minimum       = 0,
+		.maximum       = 255,
+		.step          = 1,
+		.default_value = DEFAULT_TARGET_KB,
+	},
+	{
+		.id            = CPIA2_CID_GPIO,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "GPIO",
+		.minimum       = 0,
+		.maximum       = 255,
+		.step          = 1,
+		.default_value = 0,
+	},
+	{
+		.id            = CPIA2_CID_FLICKER_MODE,
+		.type          = V4L2_CTRL_TYPE_MENU,
+		.name          = "Flicker Reduction",
+		.minimum       = 0,
+		.maximum       = NUM_FLICKER_CONTROLS-1,
+		.step          = 1,
+		.default_value = 0,
+	},
+	{
+		.id            = CPIA2_CID_FRAMERATE,
+		.type          = V4L2_CTRL_TYPE_MENU,
+		.name          = "Framerate",
+		.minimum       = 0,
+		.maximum       = NUM_FRAMERATE_CONTROLS-1,
+		.step          = 1,
+		.default_value = NUM_FRAMERATE_CONTROLS-1,
+	},
+	{
+		.id            = CPIA2_CID_USB_ALT,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "USB Alternate",
+		.minimum       = USBIF_ISO_1,
+		.maximum       = USBIF_ISO_6,
+		.step          = 1,
+		.default_value = DEFAULT_ALT,
+	},
+	{
+		.id            = CPIA2_CID_LIGHTS,
+		.type          = V4L2_CTRL_TYPE_MENU,
+		.name          = "Lights",
+		.minimum       = 0,
+		.maximum       = NUM_LIGHTS_CONTROLS-1,
+		.step          = 1,
+		.default_value = 0,
+	},
+	{
+		.id            = CPIA2_CID_RESET_CAMERA,
+		.type          = V4L2_CTRL_TYPE_BUTTON,
+		.name          = "Reset Camera",
+		.minimum       = 0,
+		.maximum       = 0,
+		.step          = 0,
+		.default_value = 0,
+	},
+};
+#define NUM_CONTROLS (sizeof(controls)/sizeof(controls[0]))
+
+
+/******************************************************************************
+ *
+ *  cpia2_open
+ *
+ *****************************************************************************/
+static int cpia2_open(struct inode *inode, struct file *file)
+{
+	struct video_device *dev = video_devdata(file);
+	struct camera_data *cam = video_get_drvdata(dev);
+	int retval = 0;
+
+	if (!cam) {
+		ERR("Internal error, camera_data not found!\n");
+		return -ENODEV;
+	}
+
+	if(down_interruptible(&cam->busy_lock))
+		return -ERESTARTSYS;
+
+	if(!cam->present) {
+		retval = -ENODEV;
+		goto err_return;
+	}
+
+	if (cam->open_count > 0) {
+		goto skip_init;
+	}
+
+	if (cpia2_allocate_buffers(cam)) {
+		retval = -ENOMEM;
+		goto err_return;
+	}
+
+	/* reset the camera */
+	if (cpia2_reset_camera(cam) < 0) {
+		retval = -EIO;
+		goto err_return;
+	}
+
+	cam->APP_len = 0;
+	cam->COM_len = 0;
+
+skip_init:
+	{
+		struct cpia2_fh *fh = kmalloc(sizeof(*fh),GFP_KERNEL);
+		if(!fh) {
+			retval = -ENOMEM;
+			goto err_return;
+		}
+		file->private_data = fh;
+		fh->prio = V4L2_PRIORITY_UNSET;
+		v4l2_prio_open(&cam->prio, &fh->prio);
+		fh->mmapped = 0;
+	}
+
+	++cam->open_count;
+
+	cpia2_dbg_dump_registers(cam);
+
+err_return:
+	up(&cam->busy_lock);
+	return retval;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_close
+ *
+ *****************************************************************************/
+static int cpia2_close(struct inode *inode, struct file *file)
+{
+	struct video_device *dev = video_devdata(file);
+	struct camera_data *cam = video_get_drvdata(dev);
+	struct cpia2_fh *fh = file->private_data;
+
+	down(&cam->busy_lock);
+
+	if (cam->present &&
+	    (cam->open_count == 1
+	     || fh->prio == V4L2_PRIORITY_RECORD
+	    )) {
+		cpia2_usb_stream_stop(cam);
+
+		if(cam->open_count == 1) {
+			/* save camera state for later open */
+			cpia2_save_camera_state(cam);
+
+			cpia2_set_low_power(cam);
+			cpia2_free_buffers(cam);
+		}
+	}
+
+	{
+		if(fh->mmapped)
+			cam->mmapped = 0;
+		v4l2_prio_close(&cam->prio,&fh->prio);
+		file->private_data = NULL;
+		kfree(fh);
+	}
+
+	if (--cam->open_count == 0) {
+		cpia2_free_buffers(cam);
+		if (!cam->present) {
+			video_unregister_device(dev);
+			kfree(cam);
+		}
+	}
+
+	up(&cam->busy_lock);
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_v4l_read
+ *
+ *****************************************************************************/
+static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count,
+			      loff_t *off)
+{
+	struct video_device *dev = video_devdata(file);
+	struct camera_data *cam = video_get_drvdata(dev);
+	int noblock = file->f_flags&O_NONBLOCK;
+
+	struct cpia2_fh *fh = file->private_data;
+
+	if(!cam)
+		return -EINVAL;
+
+	/* Priority check */
+	if(fh->prio != V4L2_PRIORITY_RECORD) {
+		return -EBUSY;
+	}
+
+	return cpia2_read(cam, buf, count, noblock);
+}
+
+
+/******************************************************************************
+ *
+ *  cpia2_v4l_poll
+ *
+ *****************************************************************************/
+static unsigned int cpia2_v4l_poll(struct file *filp, struct poll_table_struct *wait)
+{
+	struct video_device *dev = video_devdata(filp);
+	struct camera_data *cam = video_get_drvdata(dev);
+
+	struct cpia2_fh *fh = filp->private_data;
+
+	if(!cam)
+		return POLLERR;
+
+	/* Priority check */
+	if(fh->prio != V4L2_PRIORITY_RECORD) {
+		return POLLERR;
+	}
+
+	return cpia2_poll(cam, filp, wait);
+}
+
+
+/******************************************************************************
+ *
+ *  ioctl_cap_query
+ *
+ *****************************************************************************/
+static int ioctl_cap_query(void *arg, struct camera_data *cam)
+{
+	struct video_capability *vc;
+	int retval = 0;
+	vc = arg;
+
+	if (cam->params.pnp_id.product == 0x151)
+		strcpy(vc->name, "QX5 Microscope");
+	else
+		strcpy(vc->name, "CPiA2 Camera");
+
+	vc->type = VID_TYPE_CAPTURE | VID_TYPE_MJPEG_ENCODER;
+	vc->channels = 1;
+	vc->audios = 0;
+	vc->minwidth = 176;	/* VIDEOSIZE_QCIF */
+	vc->minheight = 144;
+	switch (cam->params.version.sensor_flags) {
+	case CPIA2_VP_SENSOR_FLAGS_500:
+		vc->maxwidth = STV_IMAGE_VGA_COLS;
+		vc->maxheight = STV_IMAGE_VGA_ROWS;
+		break;
+	case CPIA2_VP_SENSOR_FLAGS_410:
+		vc->maxwidth = STV_IMAGE_CIF_COLS;
+		vc->maxheight = STV_IMAGE_CIF_ROWS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return retval;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_get_channel
+ *
+ *****************************************************************************/
+static int ioctl_get_channel(void *arg)
+{
+	int retval = 0;
+	struct video_channel *v;
+	v = arg;
+
+	if (v->channel != 0)
+		return -EINVAL;
+
+	v->channel = 0;
+	strcpy(v->name, "Camera");
+	v->tuners = 0;
+	v->flags = 0;
+	v->type = VIDEO_TYPE_CAMERA;
+	v->norm = 0;
+
+	return retval;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_set_channel
+ *
+ *****************************************************************************/
+static int ioctl_set_channel(void *arg)
+{
+	struct video_channel *v;
+	int retval = 0;
+	v = arg;
+
+	if (retval == 0 && v->channel != 0)
+		retval = -EINVAL;
+
+	return retval;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_set_image_prop
+ *
+ *****************************************************************************/
+static int ioctl_set_image_prop(void *arg, struct camera_data *cam)
+{
+	struct video_picture *vp;
+	int retval = 0;
+	vp = arg;
+
+	/* brightness, color, contrast need no check 0-65535 */
+	memcpy(&cam->vp, vp, sizeof(*vp));
+
+	/* update cam->params.colorParams */
+	cam->params.color_params.brightness = vp->brightness / 256;
+	cam->params.color_params.saturation = vp->colour / 256;
+	cam->params.color_params.contrast = vp->contrast / 256;
+
+	DBG("Requested params: bright 0x%X, sat 0x%X, contrast 0x%X\n",
+	    cam->params.color_params.brightness,
+	    cam->params.color_params.saturation,
+	    cam->params.color_params.contrast);
+
+	cpia2_set_color_params(cam);
+
+	return retval;
+}
+
+static int sync(struct camera_data *cam, int frame_nr)
+{
+	struct framebuf *frame = &cam->buffers[frame_nr];
+
+	while (1) {
+		if (frame->status == FRAME_READY)
+			return 0;
+
+		if (!cam->streaming) {
+			frame->status = FRAME_READY;
+			frame->length = 0;
+			return 0;
+		}
+
+		up(&cam->busy_lock);
+		wait_event_interruptible(cam->wq_stream,
+					 !cam->streaming ||
+					 frame->status == FRAME_READY);
+		down(&cam->busy_lock);
+		if (signal_pending(current))
+			return -ERESTARTSYS;
+		if(!cam->present)
+			return -ENOTTY;
+	}
+}
+
+/******************************************************************************
+ *
+ *  ioctl_set_window_size
+ *
+ *****************************************************************************/
+static int ioctl_set_window_size(void *arg, struct camera_data *cam,
+				 struct cpia2_fh *fh)
+{
+	/* copy_from_user, check validity, copy to internal structure */
+	struct video_window *vw;
+	int frame, err;
+	vw = arg;
+
+	if (vw->clipcount != 0)	/* clipping not supported */
+		return -EINVAL;
+
+	if (vw->clips != NULL)	/* clipping not supported */
+		return -EINVAL;
+
+	/* Ensure that only this process can change the format. */
+	err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD);
+	if(err != 0)
+		return err;
+
+	cam->pixelformat = V4L2_PIX_FMT_JPEG;
+
+	/* Be sure to supply the Huffman tables, this isn't MJPEG */
+	cam->params.compression.inhibit_htables = 0;
+
+	/* we set the video window to something smaller or equal to what
+	 * is requested by the user???
+	 */
+	DBG("Requested width = %d, height = %d\n", vw->width, vw->height);
+	if (vw->width != cam->vw.width || vw->height != cam->vw.height) {
+		cam->vw.width = vw->width;
+		cam->vw.height = vw->height;
+		cam->params.roi.width = vw->width;
+		cam->params.roi.height = vw->height;
+		cpia2_set_format(cam);
+	}
+
+	for (frame = 0; frame < cam->num_frames; ++frame) {
+		if (cam->buffers[frame].status == FRAME_READING)
+			if ((err = sync(cam, frame)) < 0)
+				return err;
+
+		cam->buffers[frame].status = FRAME_EMPTY;
+	}
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_get_mbuf
+ *
+ *****************************************************************************/
+static int ioctl_get_mbuf(void *arg, struct camera_data *cam)
+{
+	struct video_mbuf *vm;
+	int i;
+	vm = arg;
+
+	memset(vm, 0, sizeof(*vm));
+	vm->size = cam->frame_size*cam->num_frames;
+	vm->frames = cam->num_frames;
+	for (i = 0; i < cam->num_frames; i++)
+		vm->offsets[i] = cam->frame_size * i;
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_mcapture
+ *
+ *****************************************************************************/
+static int ioctl_mcapture(void *arg, struct camera_data *cam,
+			  struct cpia2_fh *fh)
+{
+	struct video_mmap *vm;
+	int video_size, err;
+	vm = arg;
+
+	if (vm->frame < 0 || vm->frame >= cam->num_frames)
+		return -EINVAL;
+
+	/* set video size */
+	video_size = cpia2_match_video_size(vm->width, vm->height);
+	if (cam->video_size < 0) {
+		return -EINVAL;
+	}
+
+	/* Ensure that only this process can change the format. */
+	err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD);
+	if(err != 0)
+		return err;
+
+	if (video_size != cam->video_size) {
+		cam->video_size = video_size;
+		cam->params.roi.width = vm->width;
+		cam->params.roi.height = vm->height;
+		cpia2_set_format(cam);
+	}
+
+	if (cam->buffers[vm->frame].status == FRAME_READING)
+		if ((err=sync(cam, vm->frame)) < 0)
+			return err;
+
+	cam->buffers[vm->frame].status = FRAME_EMPTY;
+
+	return cpia2_usb_stream_start(cam,cam->params.camera_state.stream_mode);
+}
+
+/******************************************************************************
+ *
+ *  ioctl_sync
+ *
+ *****************************************************************************/
+static int ioctl_sync(void *arg, struct camera_data *cam)
+{
+	int frame;
+
+	frame = *(int*)arg;
+
+	if (frame < 0 || frame >= cam->num_frames)
+		return -EINVAL;
+
+	return sync(cam, frame);
+}
+
+
+/******************************************************************************
+ *
+ *  ioctl_set_gpio
+ *
+ *****************************************************************************/
+
+static int ioctl_set_gpio(void *arg, struct camera_data *cam)
+{
+	__u32 gpio_val;
+
+	gpio_val = *(__u32*) arg;
+
+	if (gpio_val &~ 0xFFU)
+		return -EINVAL;
+
+	return cpia2_set_gpio(cam, (unsigned char)gpio_val);
+}
+
+/******************************************************************************
+ *
+ *  ioctl_querycap
+ *
+ *  V4L2 device capabilities
+ *
+ *****************************************************************************/
+
+static int ioctl_querycap(void *arg, struct camera_data *cam)
+{
+	struct v4l2_capability *vc = arg;
+
+	memset(vc, 0, sizeof(*vc));
+	strcpy(vc->driver, "cpia2");
+
+	if (cam->params.pnp_id.product == 0x151)
+		strcpy(vc->card, "QX5 Microscope");
+	else
+		strcpy(vc->card, "CPiA2 Camera");
+	switch (cam->params.pnp_id.device_type) {
+	case DEVICE_STV_672:
+		strcat(vc->card, " (672/");
+		break;
+	case DEVICE_STV_676:
+		strcat(vc->card, " (676/");
+		break;
+	default:
+		strcat(vc->card, " (???/");
+		break;
+	}
+	switch (cam->params.version.sensor_flags) {
+	case CPIA2_VP_SENSOR_FLAGS_404:
+		strcat(vc->card, "404)");
+		break;
+	case CPIA2_VP_SENSOR_FLAGS_407:
+		strcat(vc->card, "407)");
+		break;
+	case CPIA2_VP_SENSOR_FLAGS_409:
+		strcat(vc->card, "409)");
+		break;
+	case CPIA2_VP_SENSOR_FLAGS_410:
+		strcat(vc->card, "410)");
+		break;
+	case CPIA2_VP_SENSOR_FLAGS_500:
+		strcat(vc->card, "500)");
+		break;
+	default:
+		strcat(vc->card, "???)");
+		break;
+	}
+
+	if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) <0)
+		memset(vc->bus_info,0, sizeof(vc->bus_info));
+
+	vc->version = KERNEL_VERSION(CPIA2_MAJ_VER, CPIA2_MIN_VER,
+				     CPIA2_PATCH_VER);
+
+	vc->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+			   V4L2_CAP_READWRITE |
+			   V4L2_CAP_STREAMING;
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_input
+ *
+ *  V4L2 input get/set/enumerate
+ *
+ *****************************************************************************/
+
+static int ioctl_input(unsigned int ioclt_nr,void *arg,struct camera_data *cam)
+{
+	struct v4l2_input *i = arg;
+
+	if(ioclt_nr  != VIDIOC_G_INPUT) {
+		if (i->index != 0)
+		       return -EINVAL;
+	}
+
+	memset(i, 0, sizeof(*i));
+	strcpy(i->name, "Camera");
+	i->type = V4L2_INPUT_TYPE_CAMERA;
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_enum_fmt
+ *
+ *  V4L2 format enumerate
+ *
+ *****************************************************************************/
+
+static int ioctl_enum_fmt(void *arg,struct camera_data *cam)
+{
+	struct v4l2_fmtdesc *f = arg;
+	int index = f->index;
+
+	if (index < 0 || index > 1)
+	       return -EINVAL;
+
+	memset(f, 0, sizeof(*f));
+	f->index = index;
+	f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	f->flags = V4L2_FMT_FLAG_COMPRESSED;
+	switch(index) {
+	case 0:
+		strcpy(f->description, "MJPEG");
+		f->pixelformat = V4L2_PIX_FMT_MJPEG;
+		break;
+	case 1:
+		strcpy(f->description, "JPEG");
+		f->pixelformat = V4L2_PIX_FMT_JPEG;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_try_fmt
+ *
+ *  V4L2 format try
+ *
+ *****************************************************************************/
+
+static int ioctl_try_fmt(void *arg,struct camera_data *cam)
+{
+	struct v4l2_format *f = arg;
+
+	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+	       return -EINVAL;
+
+	if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG &&
+	    f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
+	       return -EINVAL;
+
+	f->fmt.pix.field = V4L2_FIELD_NONE;
+	f->fmt.pix.bytesperline = 0;
+	f->fmt.pix.sizeimage = cam->frame_size;
+	f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
+	f->fmt.pix.priv = 0;
+
+	switch (cpia2_match_video_size(f->fmt.pix.width, f->fmt.pix.height)) {
+	case VIDEOSIZE_VGA:
+		f->fmt.pix.width = 640;
+		f->fmt.pix.height = 480;
+		break;
+	case VIDEOSIZE_CIF:
+		f->fmt.pix.width = 352;
+		f->fmt.pix.height = 288;
+		break;
+	case VIDEOSIZE_QVGA:
+		f->fmt.pix.width = 320;
+		f->fmt.pix.height = 240;
+		break;
+	case VIDEOSIZE_288_216:
+		f->fmt.pix.width = 288;
+		f->fmt.pix.height = 216;
+		break;
+	case VIDEOSIZE_256_192:
+		f->fmt.pix.width = 256;
+		f->fmt.pix.height = 192;
+		break;
+	case VIDEOSIZE_224_168:
+		f->fmt.pix.width = 224;
+		f->fmt.pix.height = 168;
+		break;
+	case VIDEOSIZE_192_144:
+		f->fmt.pix.width = 192;
+		f->fmt.pix.height = 144;
+		break;
+	case VIDEOSIZE_QCIF:
+	default:
+		f->fmt.pix.width = 176;
+		f->fmt.pix.height = 144;
+		break;
+	}
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_set_fmt
+ *
+ *  V4L2 format set
+ *
+ *****************************************************************************/
+
+static int ioctl_set_fmt(void *arg,struct camera_data *cam, struct cpia2_fh *fh)
+{
+	struct v4l2_format *f = arg;
+	int err, frame;
+
+	err = ioctl_try_fmt(arg, cam);
+	if(err != 0)
+		return err;
+
+	/* Ensure that only this process can change the format. */
+	err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD);
+	if(err != 0) {
+		return err;
+	}
+
+	cam->pixelformat = f->fmt.pix.pixelformat;
+
+	/* NOTE: This should be set to 1 for MJPEG, but some apps don't handle
+	 * the missing Huffman table properly. */
+	cam->params.compression.inhibit_htables = 0;
+		/*f->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG;*/
+
+	/* we set the video window to something smaller or equal to what
+	 * is requested by the user???
+	 */
+	DBG("Requested width = %d, height = %d\n",
+	    f->fmt.pix.width, f->fmt.pix.height);
+	if (f->fmt.pix.width != cam->vw.width ||
+	    f->fmt.pix.height != cam->vw.height) {
+		cam->vw.width = f->fmt.pix.width;
+		cam->vw.height = f->fmt.pix.height;
+		cam->params.roi.width = f->fmt.pix.width;
+		cam->params.roi.height = f->fmt.pix.height;
+		cpia2_set_format(cam);
+	}
+
+	for (frame = 0; frame < cam->num_frames; ++frame) {
+		if (cam->buffers[frame].status == FRAME_READING)
+			if ((err = sync(cam, frame)) < 0)
+				return err;
+
+		cam->buffers[frame].status = FRAME_EMPTY;
+	}
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_get_fmt
+ *
+ *  V4L2 format get
+ *
+ *****************************************************************************/
+
+static int ioctl_get_fmt(void *arg,struct camera_data *cam)
+{
+	struct v4l2_format *f = arg;
+
+	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+	       return -EINVAL;
+
+	f->fmt.pix.width = cam->vw.width;
+	f->fmt.pix.height = cam->vw.height;
+	f->fmt.pix.pixelformat = cam->pixelformat;
+	f->fmt.pix.field = V4L2_FIELD_NONE;
+	f->fmt.pix.bytesperline = 0;
+	f->fmt.pix.sizeimage = cam->frame_size;
+	f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
+	f->fmt.pix.priv = 0;
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_cropcap
+ *
+ *  V4L2 query cropping capabilities
+ *  NOTE: cropping is currently disabled
+ *
+ *****************************************************************************/
+
+static int ioctl_cropcap(void *arg,struct camera_data *cam)
+{
+	struct v4l2_cropcap *c = arg;
+
+	if (c->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+	       return -EINVAL;
+
+	c->bounds.left = 0;
+	c->bounds.top = 0;
+	c->bounds.width = cam->vw.width;
+	c->bounds.height = cam->vw.height;
+	c->defrect.left = 0;
+	c->defrect.top = 0;
+	c->defrect.width = cam->vw.width;
+	c->defrect.height = cam->vw.height;
+	c->pixelaspect.numerator = 1;
+	c->pixelaspect.denominator = 1;
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_queryctrl
+ *
+ *  V4L2 query possible control variables
+ *
+ *****************************************************************************/
+
+static int ioctl_queryctrl(void *arg,struct camera_data *cam)
+{
+	struct v4l2_queryctrl *c = arg;
+	int i;
+
+	for(i=0; i<NUM_CONTROLS; ++i) {
+		if(c->id == controls[i].id) {
+			memcpy(c, controls+i, sizeof(*c));
+			break;
+		}
+	}
+
+	if(i == NUM_CONTROLS)
+		return -EINVAL;
+
+	/* Some devices have additional limitations */
+	switch(c->id) {
+	case V4L2_CID_BRIGHTNESS:
+		/***
+		 * Don't let the register be set to zero - bug in VP4
+		 * flash of full brightness
+		 ***/
+		if (cam->params.pnp_id.device_type == DEVICE_STV_672)
+			c->minimum = 1;
+		break;
+	case V4L2_CID_VFLIP:
+		// VP5 Only
+		if(cam->params.pnp_id.device_type == DEVICE_STV_672)
+			c->flags |= V4L2_CTRL_FLAG_DISABLED;
+		break;
+	case CPIA2_CID_FRAMERATE:
+		if(cam->params.pnp_id.device_type == DEVICE_STV_672 &&
+		   cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){
+			// Maximum 15fps
+			int i;
+			for(i=0; i<c->maximum; ++i) {
+				if(framerate_controls[i].value ==
+				   CPIA2_VP_FRAMERATE_15) {
+					c->maximum = i;
+					c->default_value = i;
+				}
+			}
+		}
+		break;
+	case CPIA2_CID_FLICKER_MODE:
+		// Flicker control only valid for 672.
+		if(cam->params.pnp_id.device_type != DEVICE_STV_672)
+			c->flags |= V4L2_CTRL_FLAG_DISABLED;
+		break;
+	case CPIA2_CID_LIGHTS:
+		// Light control only valid for the QX5 Microscope.
+		if(cam->params.pnp_id.product != 0x151)
+			c->flags |= V4L2_CTRL_FLAG_DISABLED;
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_querymenu
+ *
+ *  V4L2 query possible control variables
+ *
+ *****************************************************************************/
+
+static int ioctl_querymenu(void *arg,struct camera_data *cam)
+{
+	struct v4l2_querymenu *m = arg;
+
+	memset(m->name, 0, sizeof(m->name));
+	m->reserved = 0;
+
+	switch(m->id) {
+	case CPIA2_CID_FLICKER_MODE:
+		if(m->index < 0 || m->index >= NUM_FLICKER_CONTROLS)
+			return -EINVAL;
+
+		strcpy(m->name, flicker_controls[m->index].name);
+		break;
+	case CPIA2_CID_FRAMERATE:
+	    {
+		int maximum = NUM_FRAMERATE_CONTROLS - 1;
+		if(cam->params.pnp_id.device_type == DEVICE_STV_672 &&
+		   cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){
+			// Maximum 15fps
+			int i;
+			for(i=0; i<maximum; ++i) {
+				if(framerate_controls[i].value ==
+				   CPIA2_VP_FRAMERATE_15)
+					maximum = i;
+			}
+		}
+		if(m->index < 0 || m->index > maximum)
+			return -EINVAL;
+
+		strcpy(m->name, framerate_controls[m->index].name);
+		break;
+	    }
+	case CPIA2_CID_LIGHTS:
+		if(m->index < 0 || m->index >= NUM_LIGHTS_CONTROLS)
+			return -EINVAL;
+
+		strcpy(m->name, lights_controls[m->index].name);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_g_ctrl
+ *
+ *  V4L2 get the value of a control variable
+ *
+ *****************************************************************************/
+
+static int ioctl_g_ctrl(void *arg,struct camera_data *cam)
+{
+	struct v4l2_control *c = arg;
+
+	switch(c->id) {
+	case V4L2_CID_BRIGHTNESS:
+		cpia2_do_command(cam, CPIA2_CMD_GET_VP_BRIGHTNESS,
+				 TRANSFER_READ, 0);
+		c->value = cam->params.color_params.brightness;
+		break;
+	case V4L2_CID_CONTRAST:
+		cpia2_do_command(cam, CPIA2_CMD_GET_CONTRAST,
+				 TRANSFER_READ, 0);
+		c->value = cam->params.color_params.contrast;
+		break;
+	case V4L2_CID_SATURATION:
+		cpia2_do_command(cam, CPIA2_CMD_GET_VP_SATURATION,
+				 TRANSFER_READ, 0);
+		c->value = cam->params.color_params.saturation;
+		break;
+	case V4L2_CID_HFLIP:
+		cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS,
+				 TRANSFER_READ, 0);
+		c->value = (cam->params.vp_params.user_effects &
+			    CPIA2_VP_USER_EFFECTS_MIRROR) != 0;
+		break;
+	case V4L2_CID_VFLIP:
+		cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS,
+				 TRANSFER_READ, 0);
+		c->value = (cam->params.vp_params.user_effects &
+			    CPIA2_VP_USER_EFFECTS_FLIP) != 0;
+		break;
+	case CPIA2_CID_TARGET_KB:
+		c->value = cam->params.vc_params.target_kb;
+		break;
+	case CPIA2_CID_GPIO:
+		cpia2_do_command(cam, CPIA2_CMD_GET_VP_GPIO_DATA,
+				 TRANSFER_READ, 0);
+		c->value = cam->params.vp_params.gpio_data;
+		break;
+	case CPIA2_CID_FLICKER_MODE:
+	{
+		int i, mode;
+		cpia2_do_command(cam, CPIA2_CMD_GET_FLICKER_MODES,
+				 TRANSFER_READ, 0);
+		if(cam->params.flicker_control.cam_register &
+		   CPIA2_VP_FLICKER_MODES_NEVER_FLICKER) {
+			mode = NEVER_FLICKER;
+		} else {
+		    if(cam->params.flicker_control.cam_register &
+		       CPIA2_VP_FLICKER_MODES_50HZ) {
+		    	mode = FLICKER_50;
+		    } else {
+		    	mode = FLICKER_60;
+		    }
+		}
+		for(i=0; i<NUM_FLICKER_CONTROLS; i++) {
+			if(flicker_controls[i].value == mode) {
+				c->value = i;
+				break;
+			}
+		}
+		if(i == NUM_FLICKER_CONTROLS)
+			return -EINVAL;
+		break;
+	}
+	case CPIA2_CID_FRAMERATE:
+	{
+		int maximum = NUM_FRAMERATE_CONTROLS - 1;
+		int i;
+		for(i=0; i<= maximum; i++) {
+			if(cam->params.vp_params.frame_rate ==
+			   framerate_controls[i].value)
+				break;
+		}
+		if(i > maximum)
+			return -EINVAL;
+		c->value = i;
+		break;
+	}
+	case CPIA2_CID_USB_ALT:
+		c->value = cam->params.camera_state.stream_mode;
+		break;
+	case CPIA2_CID_LIGHTS:
+	{
+		int i;
+		cpia2_do_command(cam, CPIA2_CMD_GET_VP_GPIO_DATA,
+				 TRANSFER_READ, 0);
+		for(i=0; i<NUM_LIGHTS_CONTROLS; i++) {
+			if((cam->params.vp_params.gpio_data&GPIO_LIGHTS_MASK) ==
+			   lights_controls[i].value) {
+				break;
+			}
+		}
+		if(i == NUM_LIGHTS_CONTROLS)
+			return -EINVAL;
+		c->value = i;
+		break;
+	}
+	case CPIA2_CID_RESET_CAMERA:
+		return -EINVAL;
+	default:
+		return -EINVAL;
+	}
+
+	DBG("Get control id:%d, value:%d\n", c->id, c->value);
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_s_ctrl
+ *
+ *  V4L2 set the value of a control variable
+ *
+ *****************************************************************************/
+
+static int ioctl_s_ctrl(void *arg,struct camera_data *cam)
+{
+	struct v4l2_control *c = arg;
+	int i;
+	int retval = 0;
+
+	DBG("Set control id:%d, value:%d\n", c->id, c->value);
+
+	/* Check that the value is in range */
+	for(i=0; i<NUM_CONTROLS; i++) {
+		if(c->id == controls[i].id) {
+			if(c->value < controls[i].minimum ||
+			   c->value > controls[i].maximum) {
+				return -EINVAL;
+			}
+			break;
+		}
+	}
+	if(i == NUM_CONTROLS)
+		return -EINVAL;
+
+	switch(c->id) {
+	case V4L2_CID_BRIGHTNESS:
+		cpia2_set_brightness(cam, c->value);
+		break;
+	case V4L2_CID_CONTRAST:
+		cpia2_set_contrast(cam, c->value);
+		break;
+	case V4L2_CID_SATURATION:
+		cpia2_set_saturation(cam, c->value);
+		break;
+	case V4L2_CID_HFLIP:
+		cpia2_set_property_mirror(cam, c->value);
+		break;
+	case V4L2_CID_VFLIP:
+		cpia2_set_property_flip(cam, c->value);
+		break;
+	case CPIA2_CID_TARGET_KB:
+		retval = cpia2_set_target_kb(cam, c->value);
+		break;
+	case CPIA2_CID_GPIO:
+		retval = cpia2_set_gpio(cam, c->value);
+		break;
+	case CPIA2_CID_FLICKER_MODE:
+		retval = cpia2_set_flicker_mode(cam,
+					      flicker_controls[c->value].value);
+		break;
+	case CPIA2_CID_FRAMERATE:
+		retval = cpia2_set_fps(cam, framerate_controls[c->value].value);
+		break;
+	case CPIA2_CID_USB_ALT:
+		retval = cpia2_usb_change_streaming_alternate(cam, c->value);
+		break;
+	case CPIA2_CID_LIGHTS:
+		retval = cpia2_set_gpio(cam, lights_controls[c->value].value);
+		break;
+	case CPIA2_CID_RESET_CAMERA:
+		cpia2_usb_stream_pause(cam);
+		cpia2_reset_camera(cam);
+		cpia2_usb_stream_resume(cam);
+		break;
+	default:
+		retval = -EINVAL;
+	}
+
+	return retval;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_g_jpegcomp
+ *
+ *  V4L2 get the JPEG compression parameters
+ *
+ *****************************************************************************/
+
+static int ioctl_g_jpegcomp(void *arg,struct camera_data *cam)
+{
+	struct v4l2_jpegcompression *parms = arg;
+
+	memset(parms, 0, sizeof(*parms));
+
+	parms->quality = 80; // TODO: Can this be made meaningful?
+
+	parms->jpeg_markers = V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI;
+	if(!cam->params.compression.inhibit_htables) {
+		parms->jpeg_markers |= V4L2_JPEG_MARKER_DHT;
+	}
+
+	parms->APPn = cam->APPn;
+	parms->APP_len = cam->APP_len;
+	if(cam->APP_len > 0) {
+		memcpy(parms->APP_data, cam->APP_data, cam->APP_len);
+		parms->jpeg_markers |= V4L2_JPEG_MARKER_APP;
+	}
+
+	parms->COM_len = cam->COM_len;
+	if(cam->COM_len > 0) {
+		memcpy(parms->COM_data, cam->COM_data, cam->COM_len);
+		parms->jpeg_markers |= JPEG_MARKER_COM;
+	}
+
+	DBG("G_JPEGCOMP APP_len:%d COM_len:%d\n",
+	    parms->APP_len, parms->COM_len);
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_s_jpegcomp
+ *
+ *  V4L2 set the JPEG compression parameters
+ *  NOTE: quality and some jpeg_markers are ignored.
+ *
+ *****************************************************************************/
+
+static int ioctl_s_jpegcomp(void *arg,struct camera_data *cam)
+{
+	struct v4l2_jpegcompression *parms = arg;
+
+	DBG("S_JPEGCOMP APP_len:%d COM_len:%d\n",
+	    parms->APP_len, parms->COM_len);
+
+	cam->params.compression.inhibit_htables =
+		!(parms->jpeg_markers & V4L2_JPEG_MARKER_DHT);
+
+	if(parms->APP_len != 0) {
+		if(parms->APP_len > 0 &&
+		   parms->APP_len <= sizeof(cam->APP_data) &&
+		   parms->APPn >= 0 && parms->APPn <= 15) {
+			cam->APPn = parms->APPn;
+			cam->APP_len = parms->APP_len;
+			memcpy(cam->APP_data, parms->APP_data, parms->APP_len);
+		} else {
+			LOG("Bad APPn Params n=%d len=%d\n",
+			    parms->APPn, parms->APP_len);
+			return -EINVAL;
+		}
+	} else {
+		cam->APP_len = 0;
+	}
+
+	if(parms->COM_len != 0) {
+		if(parms->COM_len > 0 &&
+		   parms->COM_len <= sizeof(cam->COM_data)) {
+			cam->COM_len = parms->COM_len;
+			memcpy(cam->COM_data, parms->COM_data, parms->COM_len);
+		} else {
+			LOG("Bad COM_len=%d\n", parms->COM_len);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_reqbufs
+ *
+ *  V4L2 Initiate memory mapping.
+ *  NOTE: The user's request is ignored. For now the buffers are fixed.
+ *
+ *****************************************************************************/
+
+static int ioctl_reqbufs(void *arg,struct camera_data *cam)
+{
+	struct v4l2_requestbuffers *req = arg;
+
+	if(req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+	   req->memory != V4L2_MEMORY_MMAP)
+		return -EINVAL;
+
+	DBG("REQBUFS requested:%d returning:%d\n", req->count, cam->num_frames);
+	req->count = cam->num_frames;
+	memset(&req->reserved, 0, sizeof(req->reserved));
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_querybuf
+ *
+ *  V4L2 Query memory buffer status.
+ *
+ *****************************************************************************/
+
+static int ioctl_querybuf(void *arg,struct camera_data *cam)
+{
+	struct v4l2_buffer *buf = arg;
+
+	if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+	   buf->index > cam->num_frames)
+		return -EINVAL;
+
+	buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer;
+	buf->length = cam->frame_size;
+
+	buf->memory = V4L2_MEMORY_MMAP;
+
+	if(cam->mmapped)
+		buf->flags = V4L2_BUF_FLAG_MAPPED;
+	else
+		buf->flags = 0;
+
+	switch (cam->buffers[buf->index].status) {
+	case FRAME_EMPTY:
+	case FRAME_ERROR:
+	case FRAME_READING:
+		buf->bytesused = 0;
+		buf->flags = V4L2_BUF_FLAG_QUEUED;
+		break;
+	case FRAME_READY:
+		buf->bytesused = cam->buffers[buf->index].length;
+		buf->timestamp = cam->buffers[buf->index].timestamp;
+		buf->sequence = cam->buffers[buf->index].seq;
+		buf->flags = V4L2_BUF_FLAG_DONE;
+		break;
+	}
+
+	DBG("QUERYBUF index:%d offset:%d flags:%d seq:%d bytesused:%d\n",
+	     buf->index, buf->m.offset, buf->flags, buf->sequence,
+	     buf->bytesused);
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_qbuf
+ *
+ *  V4L2 User is freeing buffer
+ *
+ *****************************************************************************/
+
+static int ioctl_qbuf(void *arg,struct camera_data *cam)
+{
+	struct v4l2_buffer *buf = arg;
+
+	if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+	   buf->memory != V4L2_MEMORY_MMAP ||
+	   buf->index > cam->num_frames)
+		return -EINVAL;
+
+	DBG("QBUF #%d\n", buf->index);
+
+	if(cam->buffers[buf->index].status == FRAME_READY)
+		cam->buffers[buf->index].status = FRAME_EMPTY;
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  find_earliest_filled_buffer
+ *
+ *  Helper for ioctl_dqbuf. Find the next ready buffer.
+ *
+ *****************************************************************************/
+
+static int find_earliest_filled_buffer(struct camera_data *cam)
+{
+	int i;
+	int found = -1;
+	for (i=0; i<cam->num_frames; i++) {
+		if(cam->buffers[i].status == FRAME_READY) {
+			if(found < 0) {
+				found = i;
+			} else {
+				/* find which buffer is earlier */
+				struct timeval *tv1, *tv2;
+				tv1 = &cam->buffers[i].timestamp;
+				tv2 = &cam->buffers[found].timestamp;
+				if(tv1->tv_sec < tv2->tv_sec ||
+				   (tv1->tv_sec == tv2->tv_sec &&
+				    tv1->tv_usec < tv2->tv_usec))
+					found = i;
+			}
+		}
+	}
+	return found;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_dqbuf
+ *
+ *  V4L2 User is asking for a filled buffer.
+ *
+ *****************************************************************************/
+
+static int ioctl_dqbuf(void *arg,struct camera_data *cam, struct file *file)
+{
+	struct v4l2_buffer *buf = arg;
+	int frame;
+
+	if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+	   buf->memory != V4L2_MEMORY_MMAP)
+		return -EINVAL;
+
+	frame = find_earliest_filled_buffer(cam);
+
+	if(frame < 0 && file->f_flags&O_NONBLOCK)
+		return -EAGAIN;
+
+	if(frame < 0) {
+		/* Wait for a frame to become available */
+		struct framebuf *cb=cam->curbuff;
+		up(&cam->busy_lock);
+		wait_event_interruptible(cam->wq_stream,
+					 !cam->present ||
+					 (cb=cam->curbuff)->status == FRAME_READY);
+		down(&cam->busy_lock);
+		if (signal_pending(current))
+			return -ERESTARTSYS;
+		if(!cam->present)
+			return -ENOTTY;
+		frame = cb->num;
+	}
+
+
+	buf->index = frame;
+	buf->bytesused = cam->buffers[buf->index].length;
+	buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE;
+	buf->field = V4L2_FIELD_NONE;
+	buf->timestamp = cam->buffers[buf->index].timestamp;
+	buf->sequence = cam->buffers[buf->index].seq;
+	buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer;
+	buf->length = cam->frame_size;
+	buf->input = 0;
+	buf->reserved = 0;
+	memset(&buf->timecode, 0, sizeof(buf->timecode));
+
+	DBG("DQBUF #%d status:%d seq:%d length:%d\n", buf->index,
+	    cam->buffers[buf->index].status, buf->sequence, buf->bytesused);
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_ioctl
+ *
+ *****************************************************************************/
+static int cpia2_do_ioctl(struct inode *inode, struct file *file,
+			  unsigned int ioctl_nr, void *arg)
+{
+	struct video_device *dev = video_devdata(file);
+	struct camera_data *cam = video_get_drvdata(dev);
+	int retval = 0;
+
+	if (!cam)
+		return -ENOTTY;
+
+	/* make this _really_ smp-safe */
+	if (down_interruptible(&cam->busy_lock))
+		return -ERESTARTSYS;
+
+	if (!cam->present) {
+		up(&cam->busy_lock);
+		return -ENODEV;
+	}
+
+	/* Priority check */
+	switch (ioctl_nr) {
+	case VIDIOCSWIN:
+	case VIDIOCMCAPTURE:
+	case VIDIOC_S_FMT:
+	{
+		struct cpia2_fh *fh = file->private_data;
+		retval = v4l2_prio_check(&cam->prio, &fh->prio);
+		if(retval) {
+			up(&cam->busy_lock);
+			return retval;
+		}
+		break;
+	}
+	case VIDIOCGMBUF:
+	case VIDIOCSYNC:
+	{
+		struct cpia2_fh *fh = file->private_data;
+		if(fh->prio != V4L2_PRIORITY_RECORD) {
+			up(&cam->busy_lock);
+			return -EBUSY;
+		}
+		break;
+	}
+	default:
+		break;
+	}
+
+	switch (ioctl_nr) {
+	case VIDIOCGCAP:	/* query capabilities */
+		retval = ioctl_cap_query(arg, cam);
+		break;
+
+	case VIDIOCGCHAN:	/* get video source - we are a camera, nothing else */
+		retval = ioctl_get_channel(arg);
+		break;
+	case VIDIOCSCHAN:	/* set video source - we are a camera, nothing else */
+		retval = ioctl_set_channel(arg);
+		break;
+	case VIDIOCGPICT:	/* image properties */
+		memcpy(arg, &cam->vp, sizeof(struct video_picture));
+		break;
+	case VIDIOCSPICT:
+		retval = ioctl_set_image_prop(arg, cam);
+		break;
+	case VIDIOCGWIN:	/* get/set capture window */
+		memcpy(arg, &cam->vw, sizeof(struct video_window));
+		break;
+	case VIDIOCSWIN:
+		retval = ioctl_set_window_size(arg, cam, file->private_data);
+		break;
+	case VIDIOCGMBUF:	/* mmap interface */
+		retval = ioctl_get_mbuf(arg, cam);
+		break;
+	case VIDIOCMCAPTURE:
+		retval = ioctl_mcapture(arg, cam, file->private_data);
+		break;
+	case VIDIOCSYNC:
+		retval = ioctl_sync(arg, cam);
+		break;
+		/* pointless to implement overlay with this camera */
+	case VIDIOCCAPTURE:
+	case VIDIOCGFBUF:
+	case VIDIOCSFBUF:
+	case VIDIOCKEY:
+		retval = -EINVAL;
+		break;
+
+		/* tuner interface - we have none */
+	case VIDIOCGTUNER:
+	case VIDIOCSTUNER:
+	case VIDIOCGFREQ:
+	case VIDIOCSFREQ:
+		retval = -EINVAL;
+		break;
+
+		/* audio interface - we have none */
+	case VIDIOCGAUDIO:
+	case VIDIOCSAUDIO:
+		retval = -EINVAL;
+		break;
+
+	/* CPIA2 extension to Video4Linux API */
+	case CPIA2_IOC_SET_GPIO:
+		retval = ioctl_set_gpio(arg, cam);
+		break;
+	case VIDIOC_QUERYCAP:
+		retval = ioctl_querycap(arg,cam);
+		break;
+
+	case VIDIOC_ENUMINPUT:
+	case VIDIOC_G_INPUT:
+	case VIDIOC_S_INPUT:
+		retval = ioctl_input(ioctl_nr, arg,cam);
+		break;
+
+	case VIDIOC_ENUM_FMT:
+		retval = ioctl_enum_fmt(arg,cam);
+		break;
+	case VIDIOC_TRY_FMT:
+		retval = ioctl_try_fmt(arg,cam);
+		break;
+	case VIDIOC_G_FMT:
+		retval = ioctl_get_fmt(arg,cam);
+		break;
+	case VIDIOC_S_FMT:
+		retval = ioctl_set_fmt(arg,cam,file->private_data);
+		break;
+
+	case VIDIOC_CROPCAP:
+		retval = ioctl_cropcap(arg,cam);
+		break;
+	case VIDIOC_G_CROP:
+	case VIDIOC_S_CROP:
+		// TODO: I think cropping can be implemented - SJB
+		retval = -EINVAL;
+		break;
+
+	case VIDIOC_QUERYCTRL:
+		retval = ioctl_queryctrl(arg,cam);
+		break;
+	case VIDIOC_QUERYMENU:
+		retval = ioctl_querymenu(arg,cam);
+		break;
+	case VIDIOC_G_CTRL:
+		retval = ioctl_g_ctrl(arg,cam);
+		break;
+	case VIDIOC_S_CTRL:
+		retval = ioctl_s_ctrl(arg,cam);
+		break;
+
+	case VIDIOC_G_JPEGCOMP:
+		retval = ioctl_g_jpegcomp(arg,cam);
+		break;
+	case VIDIOC_S_JPEGCOMP:
+		retval = ioctl_s_jpegcomp(arg,cam);
+		break;
+
+	case VIDIOC_G_PRIORITY:
+	{
+		struct cpia2_fh *fh = file->private_data;
+		*(enum v4l2_priority*)arg = fh->prio;
+		break;
+	}
+	case VIDIOC_S_PRIORITY:
+	{
+		struct cpia2_fh *fh = file->private_data;
+		enum v4l2_priority prio;
+		prio = *(enum v4l2_priority*)arg;
+		if(cam->streaming &&
+		   prio != fh->prio &&
+		   fh->prio == V4L2_PRIORITY_RECORD) {
+			/* Can't drop record priority while streaming */
+			retval = -EBUSY;
+		} else if(prio == V4L2_PRIORITY_RECORD &&
+		   prio != fh->prio &&
+		   v4l2_prio_max(&cam->prio) == V4L2_PRIORITY_RECORD) {
+			/* Only one program can record at a time */
+			retval = -EBUSY;
+		} else {
+			retval = v4l2_prio_change(&cam->prio, &fh->prio, prio);
+		}
+		break;
+	}
+
+	case VIDIOC_REQBUFS:
+		retval = ioctl_reqbufs(arg,cam);
+		break;
+	case VIDIOC_QUERYBUF:
+		retval = ioctl_querybuf(arg,cam);
+		break;
+	case VIDIOC_QBUF:
+		retval = ioctl_qbuf(arg,cam);
+		break;
+	case VIDIOC_DQBUF:
+		retval = ioctl_dqbuf(arg,cam,file);
+		break;
+	case VIDIOC_STREAMON:
+	{
+		int type;
+		DBG("VIDIOC_STREAMON, streaming=%d\n", cam->streaming);
+		type = *(int*)arg;
+		if(!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			retval = -EINVAL;
+
+		if(!cam->streaming) {
+			retval = cpia2_usb_stream_start(cam,
+					  cam->params.camera_state.stream_mode);
+		} else {
+			retval = -EINVAL;
+		}
+
+		break;
+	}
+	case VIDIOC_STREAMOFF:
+	{
+		int type;
+		DBG("VIDIOC_STREAMOFF, streaming=%d\n", cam->streaming);
+		type = *(int*)arg;
+		if(!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			retval = -EINVAL;
+
+		if(cam->streaming) {
+			retval = cpia2_usb_stream_stop(cam);
+		} else {
+			retval = -EINVAL;
+		}
+
+		break;
+	}
+
+	case VIDIOC_ENUMOUTPUT:
+	case VIDIOC_G_OUTPUT:
+	case VIDIOC_S_OUTPUT:
+	case VIDIOC_G_MODULATOR:
+	case VIDIOC_S_MODULATOR:
+
+	case VIDIOC_ENUMAUDIO:
+	case VIDIOC_G_AUDIO:
+	case VIDIOC_S_AUDIO:
+
+	case VIDIOC_ENUMAUDOUT:
+	case VIDIOC_G_AUDOUT:
+	case VIDIOC_S_AUDOUT:
+
+	case VIDIOC_ENUMSTD:
+	case VIDIOC_QUERYSTD:
+	case VIDIOC_G_STD:
+	case VIDIOC_S_STD:
+
+	case VIDIOC_G_TUNER:
+	case VIDIOC_S_TUNER:
+	case VIDIOC_G_FREQUENCY:
+	case VIDIOC_S_FREQUENCY:
+
+	case VIDIOC_OVERLAY:
+	case VIDIOC_G_FBUF:
+	case VIDIOC_S_FBUF:
+
+	case VIDIOC_G_PARM:
+	case VIDIOC_S_PARM:
+		retval = -EINVAL;
+		break;
+	default:
+		retval = -ENOIOCTLCMD;
+		break;
+	}
+
+	up(&cam->busy_lock);
+	return retval;
+}
+
+static int cpia2_ioctl(struct inode *inode, struct file *file,
+		       unsigned int ioctl_nr, unsigned long iarg)
+{
+	return video_usercopy(inode, file, ioctl_nr, iarg, cpia2_do_ioctl);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_mmap
+ *
+ *****************************************************************************/
+static int cpia2_mmap(struct file *file, struct vm_area_struct *area)
+{
+	int retval;
+	struct video_device *dev = video_devdata(file);
+	struct camera_data *cam = video_get_drvdata(dev);
+
+	/* Priority check */
+	struct cpia2_fh *fh = file->private_data;
+	if(fh->prio != V4L2_PRIORITY_RECORD) {
+		return -EBUSY;
+	}
+
+	retval = cpia2_remap_buffer(cam, area);
+
+	if(!retval)
+		fh->mmapped = 1;
+	return retval;
+}
+
+/******************************************************************************
+ *
+ *  reset_camera_struct_v4l
+ *
+ *  Sets all values to the defaults
+ *****************************************************************************/
+static void reset_camera_struct_v4l(struct camera_data *cam)
+{
+	/***
+	 * Fill in the v4l structures.  video_cap is filled in inside the VIDIOCCAP
+	 * Ioctl.  Here, just do the window and picture stucts.
+	 ***/
+	cam->vp.palette = (u16) VIDEO_PALETTE_RGB24;	/* Is this right? */
+	cam->vp.brightness = (u16) cam->params.color_params.brightness * 256;
+	cam->vp.colour = (u16) cam->params.color_params.saturation * 256;
+	cam->vp.contrast = (u16) cam->params.color_params.contrast * 256;
+
+	cam->vw.x = 0;
+	cam->vw.y = 0;
+	cam->vw.width = cam->params.roi.width;
+	cam->vw.height = cam->params.roi.height;
+	cam->vw.flags = 0;
+	cam->vw.clipcount = 0;
+
+	cam->frame_size = buffer_size;
+	cam->num_frames = num_buffers;
+
+	/* FlickerModes */
+	cam->params.flicker_control.flicker_mode_req = flicker_mode;
+	cam->params.flicker_control.mains_frequency = flicker_freq;
+
+	/* streamMode */
+	cam->params.camera_state.stream_mode = alternate;
+
+	cam->pixelformat = V4L2_PIX_FMT_JPEG;
+	v4l2_prio_init(&cam->prio);
+	return;
+}
+
+/***
+ * The v4l video device structure initialized for this device
+ ***/
+static struct file_operations fops_template = {
+	.owner=      THIS_MODULE,
+	.open=       cpia2_open,
+	.release=    cpia2_close,
+	.read=       cpia2_v4l_read,
+	.poll=       cpia2_v4l_poll,
+	.ioctl=      cpia2_ioctl,
+	.llseek=     no_llseek,
+	.mmap=       cpia2_mmap,
+};
+
+static struct video_device cpia2_template = {
+	/* I could not find any place for the old .initialize initializer?? */
+	.owner=		THIS_MODULE,
+	.name=		"CPiA2 Camera",
+	.type=		VID_TYPE_CAPTURE,
+	.type2 = 	V4L2_CAP_VIDEO_CAPTURE |
+			V4L2_CAP_STREAMING,
+	.hardware=	VID_HARDWARE_CPIA2,
+	.minor=		-1,
+	.fops=		&fops_template,
+	.release=	video_device_release,
+};
+
+/******************************************************************************
+ *
+ *  cpia2_register_camera
+ *
+ *****************************************************************************/
+int cpia2_register_camera(struct camera_data *cam)
+{
+	cam->vdev = video_device_alloc();
+	if(!cam->vdev)
+		return -ENOMEM;
+
+	memcpy(cam->vdev, &cpia2_template, sizeof(cpia2_template));
+	video_set_drvdata(cam->vdev, cam);
+
+	reset_camera_struct_v4l(cam);
+
+	/* register v4l device */
+	if (video_register_device
+	    (cam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+		ERR("video_register_device failed\n");
+		video_device_release(cam->vdev);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_unregister_camera
+ *
+ *****************************************************************************/
+void cpia2_unregister_camera(struct camera_data *cam)
+{
+	if (!cam->open_count) {
+		video_unregister_device(cam->vdev);
+	} else {
+		LOG("/dev/video%d removed while open, "
+		    "deferring video_unregister_device\n",
+		    cam->vdev->minor);
+	}
+}
+
+/******************************************************************************
+ *
+ *  check_parameters
+ *
+ *  Make sure that all user-supplied parameters are sensible
+ *****************************************************************************/
+static void __init check_parameters(void)
+{
+	if(buffer_size < PAGE_SIZE) {
+		buffer_size = PAGE_SIZE;
+		LOG("buffer_size too small, setting to %d\n", buffer_size);
+	} else if(buffer_size > 1024*1024) {
+		/* arbitrary upper limiit */
+		buffer_size = 1024*1024;
+		LOG("buffer_size ridiculously large, setting to %d\n",
+		    buffer_size);
+	} else {
+		buffer_size += PAGE_SIZE-1;
+		buffer_size &= ~(PAGE_SIZE-1);
+	}
+
+	if(num_buffers < 1) {
+		num_buffers = 1;
+		LOG("num_buffers too small, setting to %d\n", num_buffers);
+	} else if(num_buffers > VIDEO_MAX_FRAME) {
+		num_buffers = VIDEO_MAX_FRAME;
+		LOG("num_buffers too large, setting to %d\n", num_buffers);
+	}
+
+	if(alternate < USBIF_ISO_1 || alternate > USBIF_ISO_6) {
+		alternate = DEFAULT_ALT;
+		LOG("alternate specified is invalid, using %d\n", alternate);
+	}
+
+	if (flicker_mode != NEVER_FLICKER && flicker_mode != ANTI_FLICKER_ON) {
+		flicker_mode = NEVER_FLICKER;
+		LOG("Flicker mode specified is invalid, using %d\n",
+		    flicker_mode);
+	}
+
+	if (flicker_freq != FLICKER_50 && flicker_freq != FLICKER_60) {
+		flicker_freq = FLICKER_60;
+		LOG("Flicker mode specified is invalid, using %d\n",
+		    flicker_freq);
+	}
+
+	if(video_nr < -1 || video_nr > 64) {
+		video_nr = -1;
+		LOG("invalid video_nr specified, must be -1 to 64\n");
+	}
+
+	DBG("Using %d buffers, each %d bytes, alternate=%d\n",
+	    num_buffers, buffer_size, alternate);
+}
+
+/************   Module Stuff ***************/
+
+
+/******************************************************************************
+ *
+ * cpia2_init/module_init
+ *
+ *****************************************************************************/
+static int __init cpia2_init(void)
+{
+	LOG("%s v%d.%d.%d\n",
+	    ABOUT, CPIA2_MAJ_VER, CPIA2_MIN_VER, CPIA2_PATCH_VER);
+	check_parameters();
+	cpia2_usb_init();
+	return 0;
+}
+
+
+/******************************************************************************
+ *
+ * cpia2_exit/module_exit
+ *
+ *****************************************************************************/
+static void __exit cpia2_exit(void)
+{
+	cpia2_usb_cleanup();
+	schedule_timeout(2 * HZ);
+}
+
+module_init(cpia2_init);
+module_exit(cpia2_exit);
+
diff --git a/drivers/media/video/cpia2/cpia2dev.h b/drivers/media/video/cpia2/cpia2dev.h
new file mode 100644
index 0000000..d58097c
--- /dev/null
+++ b/drivers/media/video/cpia2/cpia2dev.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+ *
+ *  Filename: cpia2dev.h
+ *
+ *  Copyright 2001, STMicrolectronics, Inc.
+ *
+ *  Contact:  steve.miller@st.com
+ *
+ *  Description:
+ *     This file provides definitions for applications wanting to use the
+ *     cpia2 driver beyond the generic v4l capabilities.
+ *
+ *  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 CPIA2_DEV_HEADER
+#define CPIA2_DEV_HEADER
+
+#include <linux/videodev.h>
+
+/***
+ * The following defines are ioctl numbers based on video4linux private ioctls,
+ * which can range from 192 (BASE_VIDIOCPRIVATE) to 255. All of these take int
+ * args
+ */
+#define CPIA2_IOC_SET_GPIO         _IOW('v', BASE_VIDIOCPRIVATE + 17, __u32)
+
+/* V4L2 driver specific controls */
+#define CPIA2_CID_TARGET_KB     (V4L2_CID_PRIVATE_BASE+0)
+#define CPIA2_CID_GPIO          (V4L2_CID_PRIVATE_BASE+1)
+#define CPIA2_CID_FLICKER_MODE  (V4L2_CID_PRIVATE_BASE+2)
+#define CPIA2_CID_FRAMERATE     (V4L2_CID_PRIVATE_BASE+3)
+#define CPIA2_CID_USB_ALT       (V4L2_CID_PRIVATE_BASE+4)
+#define CPIA2_CID_LIGHTS        (V4L2_CID_PRIVATE_BASE+5)
+#define CPIA2_CID_RESET_CAMERA  (V4L2_CID_PRIVATE_BASE+6)
+
+#endif
diff --git a/drivers/media/video/cpia2/cpia2patch.h b/drivers/media/video/cpia2/cpia2patch.h
new file mode 100644
index 0000000..7f085fb
--- /dev/null
+++ b/drivers/media/video/cpia2/cpia2patch.h
@@ -0,0 +1,233 @@
+/****************************************************************************
+ *
+ *  Filename: cpia2patch.h
+ *
+ *  Copyright 2001, STMicrolectronics, Inc.
+ *
+ *  Contact:  steve.miller@st.com
+ *
+ *  Description:
+ *     This file contains patch data for the CPiA2 (stv0672) VP4.
+ *
+ *  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 CPIA2_PATCH_HEADER
+#define CPIA2_PATCH_HEADER
+
+typedef struct {
+	unsigned char reg;
+	unsigned char count;
+	const unsigned char *data;
+} cpia2_patch;
+
+static const unsigned char start_address_hi[1] = {
+	0x01
+};
+
+static const unsigned char start_address_lo[1] = {
+	0xBC
+};
+
+static const unsigned char patch_block0[64] = {
+	0xE3, 0x02, 0xE3, 0x03, 0xE3, 0x04, 0xE3, 0x05,
+	0xE3, 0x06, 0xE3, 0x07, 0x93, 0x44, 0x56, 0xD4,
+	0x93, 0x4E, 0x56, 0x51, 0x93, 0x4E, 0x51, 0xD6,
+	0x93, 0x4E, 0x4F, 0x54, 0x93, 0x4E, 0x92, 0x4F,
+	0x92, 0xA4, 0x93, 0x05, 0x92, 0xF4, 0x93, 0x1B,
+	0x92, 0x92, 0x91, 0xE6, 0x92, 0x36, 0x92, 0x74,
+	0x92, 0x4A, 0x92, 0x8C, 0x92, 0x8E, 0xC8, 0xD0,
+	0x0B, 0x42, 0x02, 0xA0, 0xCA, 0x92, 0x09, 0x02
+};
+
+static const unsigned char patch_block1[64] = {
+	0xC9, 0x10, 0x0A, 0x0A, 0x0A, 0x81, 0xE3, 0xB8,
+	0xE3, 0xB0, 0xE3, 0xA8, 0xE3, 0xA0, 0xE3, 0x98,
+	0xE3, 0x90, 0xE1, 0x00, 0xCF, 0xD7, 0x0A, 0x12,
+	0xCC, 0x95, 0x08, 0xB2, 0x0A, 0x18, 0xE1, 0x00,
+	0x01, 0xEE, 0x0C, 0x08, 0x4A, 0x12, 0xC8, 0x18,
+	0xF0, 0x9A, 0xC0, 0x22, 0xF3, 0x1C, 0x4A, 0x13,
+	0xF3, 0x14, 0xC8, 0xA0, 0xF2, 0x14, 0xF2, 0x1C,
+	0xEB, 0x13, 0xD3, 0xA2, 0x63, 0x16, 0x48, 0x9E
+};
+
+static const unsigned char patch_block2[64] = {
+	0xF0, 0x18, 0xA4, 0x03, 0xF3, 0x93, 0xC0, 0x58,
+	0xF7, 0x13, 0x51, 0x9C, 0xE9, 0x20, 0xCF, 0xEF,
+	0x63, 0xF9, 0x92, 0x2E, 0xD3, 0x5F, 0x63, 0xFA,
+	0x92, 0x2E, 0xD3, 0x67, 0x63, 0xFB, 0x92, 0x2E,
+	0xD3, 0x6F, 0xE9, 0x1A, 0x63, 0x16, 0x48, 0xA7,
+	0xF0, 0x20, 0xA4, 0x06, 0xF3, 0x94, 0xC0, 0x27,
+	0xF7, 0x14, 0xF5, 0x13, 0x51, 0x9D, 0xF6, 0x13,
+	0x63, 0x18, 0xC4, 0x20, 0xCB, 0xEF, 0x63, 0xFC
+};
+
+static const unsigned char patch_block3[64] = {
+	0x92, 0x2E, 0xD3, 0x77, 0x63, 0xFD, 0x92, 0x2E,
+	0xD3, 0x7F, 0x63, 0xFE, 0x92, 0x2E, 0xD3, 0x87,
+	0x63, 0xFF, 0x92, 0x2E, 0xD3, 0x8F, 0x64, 0x38,
+	0x92, 0x2E, 0xD3, 0x97, 0x64, 0x39, 0x92, 0x2E,
+	0xD3, 0x9F, 0xE1, 0x00, 0xF5, 0x3A, 0xF4, 0x3B,
+	0xF7, 0xBF, 0xF2, 0xBC, 0xF2, 0x3D, 0xE1, 0x00,
+	0x80, 0x87, 0x90, 0x80, 0x51, 0xD5, 0x02, 0x22,
+	0x02, 0x32, 0x4B, 0xD3, 0xF7, 0x11, 0x0B, 0xDA
+};
+
+static const unsigned char patch_block4[64] = {
+	0xE1, 0x00, 0x0E, 0x02, 0x02, 0x40, 0x0D, 0xB5,
+	0xE3, 0x02, 0x48, 0x55, 0xE5, 0x12, 0xA4, 0x01,
+	0xE8, 0x1B, 0xE3, 0x90, 0xF0, 0x18, 0xA4, 0x01,
+	0xE8, 0xBF, 0x8D, 0xB8, 0x4B, 0xD1, 0x4B, 0xD8,
+	0x0B, 0xCB, 0x0B, 0xC2, 0xE1, 0x00, 0xE3, 0x02,
+	0xE3, 0x03, 0x52, 0xD3, 0x60, 0x59, 0xE6, 0x93,
+	0x0D, 0x22, 0x52, 0xD4, 0xE6, 0x93, 0x0D, 0x2A,
+	0xE3, 0x98, 0xE3, 0x90, 0xE1, 0x00, 0x02, 0x5D
+};
+
+static const unsigned char patch_block5[64] = {
+	0x02, 0x63, 0xE3, 0x02, 0xC8, 0x12, 0x02, 0xCA,
+	0xC8, 0x52, 0x02, 0xC2, 0x82, 0x68, 0xE3, 0x02,
+	0xC8, 0x14, 0x02, 0xCA, 0xC8, 0x90, 0x02, 0xC2,
+	0x0A, 0xD0, 0xC9, 0x93, 0x0A, 0xDA, 0xCC, 0xD2,
+	0x0A, 0xE2, 0x63, 0x12, 0x02, 0xDA, 0x0A, 0x98,
+	0x0A, 0xA0, 0x0A, 0xA8, 0xE3, 0x90, 0xE1, 0x00,
+	0xE3, 0x02, 0x0A, 0xD0, 0xC9, 0x93, 0x0A, 0xDA,
+	0xCC, 0xD2, 0x0A, 0xE2, 0x63, 0x12, 0x02, 0xDA
+};
+
+static const unsigned char patch_block6[64] = {
+	0x0A, 0x98, 0x0A, 0xA0, 0x0A, 0xA8, 0x49, 0x91,
+	0xE5, 0x6A, 0xA4, 0x04, 0xC8, 0x12, 0x02, 0xCA,
+	0xC8, 0x52, 0x82, 0x89, 0xC8, 0x14, 0x02, 0xCA,
+	0xC8, 0x90, 0x02, 0xC2, 0xE3, 0x90, 0xE1, 0x00,
+	0x08, 0x60, 0xE1, 0x00, 0x48, 0x53, 0xE8, 0x97,
+	0x08, 0x5A, 0xE1, 0x00, 0xE3, 0x02, 0xE3, 0x03,
+	0x54, 0xD3, 0x60, 0x59, 0xE6, 0x93, 0x0D, 0x52,
+	0xE3, 0x98, 0xE3, 0x90, 0xE1, 0x00, 0x02, 0x9C
+};
+
+static const unsigned char patch_block7[64] = {
+	0xE3, 0x02, 0x55, 0x13, 0x93, 0x17, 0x55, 0x13,
+	0x93, 0x17, 0xE3, 0x90, 0xE1, 0x00, 0x75, 0x30,
+	0xE3, 0x02, 0xE3, 0x03, 0x55, 0x55, 0x60, 0x59,
+	0xE6, 0x93, 0x0D, 0xB2, 0xE3, 0x98, 0xE3, 0x90,
+	0xE1, 0x00, 0x02, 0xAE, 0xE7, 0x92, 0xE9, 0x18,
+	0xEA, 0x9A, 0xE8, 0x98, 0xE8, 0x10, 0xE8, 0x11,
+	0xE8, 0x51, 0xD2, 0xDA, 0xD2, 0xF3, 0xE8, 0x13,
+	0xD2, 0xFA, 0xE8, 0x50, 0xD2, 0xEA, 0xE8, 0xD0
+};
+
+static const unsigned char patch_block8[64] = {
+	0xE8, 0xD1, 0xD3, 0x0A, 0x03, 0x09, 0x48, 0x23,
+	0xE5, 0x2C, 0xA0, 0x03, 0x48, 0x24, 0xEA, 0x1C,
+	0x03, 0x08, 0xD2, 0xE3, 0xD3, 0x03, 0xD3, 0x13,
+	0xE1, 0x00, 0x02, 0xCB, 0x05, 0x93, 0x57, 0x93,
+	0xF0, 0x9A, 0xAC, 0x0B, 0xE3, 0x07, 0x92, 0xEA,
+	0xE2, 0x9F, 0xE5, 0x06, 0xE3, 0xB0, 0xA0, 0x02,
+	0xEB, 0x1E, 0x82, 0xD7, 0xEA, 0x1E, 0xE2, 0x3B,
+	0x85, 0x9B, 0xE9, 0x1E, 0xC8, 0x90, 0x85, 0x94
+};
+
+static const unsigned char patch_block9[64] = {
+	0x02, 0xDE, 0x05, 0x80, 0x57, 0x93, 0xF0, 0xBA,
+	0xAC, 0x06, 0x92, 0xEA, 0xE2, 0xBF, 0xE5, 0x06,
+	0xA0, 0x01, 0xEB, 0xBF, 0x85, 0x88, 0xE9, 0x3E,
+	0xC8, 0x90, 0x85, 0x81, 0xE9, 0x3E, 0xF0, 0xBA,
+	0xF3, 0x39, 0xF0, 0x3A, 0x60, 0x17, 0xF0, 0x3A,
+	0xC0, 0x90, 0xF0, 0xBA, 0xE1, 0x00, 0x00, 0x3F,
+	0xE3, 0x02, 0xE3, 0x03, 0x58, 0x10, 0x60, 0x59,
+	0xE6, 0x93, 0x0D, 0xA2, 0x58, 0x12, 0xE6, 0x93
+};
+
+static const unsigned char patch_block10[64] = {
+	0x0D, 0xAA, 0xE3, 0x98, 0xE3, 0x90, 0xE1, 0x00,
+	0x03, 0x01, 0xE1, 0x00, 0x03, 0x03, 0x9B, 0x7D,
+	0x8B, 0x8B, 0xE3, 0x02, 0xE3, 0x03, 0x58, 0x56,
+	0x60, 0x59, 0xE6, 0x93, 0x0D, 0xBA, 0xE3, 0x98,
+	0xE3, 0x90, 0xE1, 0x00, 0x03, 0x0F, 0x93, 0x11,
+	0xE1, 0x00, 0xE3, 0x02, 0x4A, 0x11, 0x0B, 0x42,
+	0x91, 0xAF, 0xE3, 0x90, 0xE1, 0x00, 0xF2, 0x91,
+	0xF0, 0x91, 0xA3, 0xFE, 0xE1, 0x00, 0x60, 0x92
+};
+
+static const unsigned char patch_block11[64] = {
+	0xC0, 0x5F, 0xF0, 0x13, 0xF0, 0x13, 0x59, 0x5B,
+	0xE2, 0x13, 0xF0, 0x11, 0x5A, 0x19, 0xE2, 0x13,
+	0xE1, 0x00, 0x00, 0x00, 0x03, 0x27, 0x68, 0x61,
+	0x76, 0x61, 0x6E, 0x61, 0x00, 0x06, 0x03, 0x2C,
+	0xE3, 0x02, 0xE3, 0x03, 0xE9, 0x38, 0x59, 0x15,
+	0x59, 0x5A, 0xF2, 0x9A, 0xBC, 0x0B, 0xA4, 0x0A,
+	0x59, 0x1E, 0xF3, 0x11, 0xF0, 0x1A, 0xE2, 0xBB,
+	0x59, 0x15, 0xF0, 0x11, 0x19, 0x2A, 0xE5, 0x02
+};
+
+static const unsigned char patch_block12[54] = {
+	0xA4, 0x01, 0xEB, 0xBF, 0xE3, 0x98, 0xE3, 0x90,
+	0xE1, 0x00, 0x03, 0x42, 0x19, 0x28, 0xE1, 0x00,
+	0xE9, 0x30, 0x60, 0x79, 0xE1, 0x00, 0xE3, 0x03,
+	0xE3, 0x07, 0x60, 0x79, 0x93, 0x4E, 0xE3, 0xB8,
+	0xE3, 0x98, 0xE1, 0x00, 0xE9, 0x1A, 0xF0, 0x1F,
+	0xE2, 0x33, 0xF0, 0x91, 0xE2, 0x92, 0xE0, 0x32,
+	0xF0, 0x31, 0xE1, 0x00, 0x00, 0x00
+};
+
+static const unsigned char do_call[1] = {
+	0x01
+};
+
+
+#define PATCH_DATA_SIZE 18
+
+static const cpia2_patch patch_data[PATCH_DATA_SIZE] = {
+	{0x0A, sizeof(start_address_hi), start_address_hi}
+	,			// 0
+	{0x0B, sizeof(start_address_lo), start_address_lo}
+	,			// 1
+	{0x0C, sizeof(patch_block0), patch_block0}
+	,			// 2
+	{0x0C, sizeof(patch_block1), patch_block1}
+	,			// 3
+	{0x0C, sizeof(patch_block2), patch_block2}
+	,			// 4
+	{0x0C, sizeof(patch_block3), patch_block3}
+	,			// 5
+	{0x0C, sizeof(patch_block4), patch_block4}
+	,			// 6
+	{0x0C, sizeof(patch_block5), patch_block5}
+	,			// 7
+	{0x0C, sizeof(patch_block6), patch_block6}
+	,			// 8
+	{0x0C, sizeof(patch_block7), patch_block7}
+	,			// 9
+	{0x0C, sizeof(patch_block8), patch_block8}
+	,			// 10
+	{0x0C, sizeof(patch_block9), patch_block9}
+	,			//11
+	{0x0C, sizeof(patch_block10), patch_block10}
+	,			// 12
+	{0x0C, sizeof(patch_block11), patch_block11}
+	,			// 13
+	{0x0C, sizeof(patch_block12), patch_block12}
+	,			// 14
+	{0x0A, sizeof(start_address_hi), start_address_hi}
+	,			// 15
+	{0x0B, sizeof(start_address_lo), start_address_lo}
+	,			// 16
+	{0x0D, sizeof(do_call), do_call}	//17
+};
+
+
+#endif
diff --git a/drivers/media/video/cx25840/Kconfig b/drivers/media/video/cx25840/Kconfig
new file mode 100644
index 0000000..854264e
--- /dev/null
+++ b/drivers/media/video/cx25840/Kconfig
@@ -0,0 +1,9 @@
+config VIDEO_CX25840
+	tristate "Conexant CX2584x audio/video decoders"
+	depends on VIDEO_DEV && I2C && EXPERIMENTAL
+	select FW_LOADER
+	---help---
+	  Support for the Conexant CX2584x audio/video decoders.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cx25840
diff --git a/drivers/media/video/cx25840/Makefile b/drivers/media/video/cx25840/Makefile
index 543ebac..32a896c 100644
--- a/drivers/media/video/cx25840/Makefile
+++ b/drivers/media/video/cx25840/Makefile
@@ -1,6 +1,6 @@
 cx25840-objs    := cx25840-core.o cx25840-audio.o cx25840-firmware.o \
 		   cx25840-vbi.o
 
-obj-$(CONFIG_VIDEO_DECODER) += cx25840.o
+obj-$(CONFIG_VIDEO_CX25840) += cx25840.o
 
 EXTRA_CFLAGS += -I$(src)/..
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 5588b9a..8a25797 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -743,6 +743,7 @@
 
 		memset(input, 0, sizeof(*input));
 		input->index = state->aud_input;
+		input->capability = V4L2_AUDCAP_STEREO;
 		break;
 	}
 
@@ -753,7 +754,6 @@
 	case VIDIOC_G_TUNER:
 	{
 		u8 mode = cx25840_read(client, 0x804);
-		u8 pref = cx25840_read(client, 0x809) & 0xf;
 		u8 vpres = cx25840_read(client, 0x80a) & 0x10;
 		int val = 0;
 
@@ -773,44 +773,49 @@
 			val |= V4L2_TUNER_SUB_MONO;
 
 		if (mode == 2 || mode == 4)
-			val |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+			val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
 
 		if (mode & 0x10)
 			val |= V4L2_TUNER_SUB_SAP;
 
 		vt->rxsubchans = val;
-
-		switch (pref) {
-		case 0:
-			vt->audmode = V4L2_TUNER_MODE_MONO;
-			break;
-		case 1:
-		case 2:
-			vt->audmode = V4L2_TUNER_MODE_LANG2;
-			break;
-		case 4:
-		default:
-			vt->audmode = V4L2_TUNER_MODE_STEREO;
-		}
+		vt->audmode = state->audmode;
 		break;
 	}
 
 	case VIDIOC_S_TUNER:
+		if (state->radio)
+			break;
+
 		switch (vt->audmode) {
 		case V4L2_TUNER_MODE_MONO:
-		case V4L2_TUNER_MODE_LANG1:
-			/* Force PREF_MODE to MONO */
+			/* mono      -> mono
+			   stereo    -> mono
+			   bilingual -> lang1 */
 			cx25840_and_or(client, 0x809, ~0xf, 0x00);
 			break;
-		case V4L2_TUNER_MODE_STEREO:
-			/* Force PREF_MODE to STEREO */
+		case V4L2_TUNER_MODE_LANG1:
+			/* mono      -> mono
+			   stereo    -> stereo
+			   bilingual -> lang1 */
 			cx25840_and_or(client, 0x809, ~0xf, 0x04);
 			break;
+		case V4L2_TUNER_MODE_STEREO:
+			/* mono      -> mono
+			   stereo    -> stereo
+			   bilingual -> lang1/lang2 */
+			cx25840_and_or(client, 0x809, ~0xf, 0x07);
+			break;
 		case V4L2_TUNER_MODE_LANG2:
-			/* Force PREF_MODE to LANG2 */
+			/* mono      -> mono
+			   stereo    ->stereo
+			   bilingual -> lang2 */
 			cx25840_and_or(client, 0x809, ~0xf, 0x01);
 			break;
+		default:
+			return -EINVAL;
 		}
+		state->audmode = vt->audmode;
 		break;
 
 	case VIDIOC_G_FMT:
@@ -891,6 +896,7 @@
 	state->aud_input = CX25840_AUDIO8;
 	state->audclk_freq = 48000;
 	state->pvr150_workaround = 0;
+	state->audmode = V4L2_TUNER_MODE_LANG1;
 
 	cx25840_initialize(client, 1);
 
diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c
index 04d879d..e96fd1f 100644
--- a/drivers/media/video/cx25840/cx25840-vbi.c
+++ b/drivers/media/video/cx25840/cx25840-vbi.c
@@ -151,7 +151,7 @@
 	case VIDIOC_G_FMT:
 	{
 		static u16 lcr2vbi[] = {
-			0, V4L2_SLICED_TELETEXT_B, 0,	/* 1 */
+			0, V4L2_SLICED_TELETEXT_PAL_B, 0,	/* 1 */
 			0, V4L2_SLICED_WSS_625, 0,	/* 4 */
 			V4L2_SLICED_CAPTION_525,	/* 6 */
 			0, 0, V4L2_SLICED_VPS, 0, 0,	/* 9 */
@@ -231,7 +231,7 @@
 		for (i = 7; i <= 23; i++) {
 			for (x = 0; x <= 1; x++) {
 				switch (svbi->service_lines[1-x][i]) {
-				case V4L2_SLICED_TELETEXT_B:
+				case V4L2_SLICED_TELETEXT_PAL_B:
 					lcr[i] |= 1 << (4 * x);
 					break;
 				case V4L2_SLICED_WSS_625:
@@ -282,7 +282,7 @@
 
 		switch (id2) {
 		case 1:
-			id2 = V4L2_SLICED_TELETEXT_B;
+			id2 = V4L2_SLICED_TELETEXT_PAL_B;
 			break;
 		case 4:
 			id2 = V4L2_SLICED_WSS_625;
diff --git a/drivers/media/video/cx25840/cx25840.h b/drivers/media/video/cx25840/cx25840.h
index fd22f30..dd70664 100644
--- a/drivers/media/video/cx25840/cx25840.h
+++ b/drivers/media/video/cx25840/cx25840.h
@@ -78,6 +78,7 @@
 	enum cx25840_video_input vid_input;
 	enum cx25840_audio_input aud_input;
 	u32 audclk_freq;
+	int audmode;
 };
 
 /* ----------------------------------------------------------------------- */
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index 87d79df..e140996 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -50,6 +50,7 @@
 	depends on VIDEO_CX88_DVB
 	select DVB_MT352
 	select VIDEO_CX88_VP3054
+	select DVB_ZL10353
 	select DVB_OR51132
 	select DVB_CX22702
 	select DVB_LGDT330X
@@ -81,6 +82,16 @@
 	  which also require support for the VP-3054
 	  Secondary I2C bus, such at DNTV Live! DVB-T Pro.
 
+config VIDEO_CX88_DVB_ZL10353
+	bool "Zarlink ZL10353 DVB-T Support"
+	default y
+	depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+	select DVB_ZL10353
+	---help---
+	  This adds DVB-T support for cards based on the
+	  Connexant 2388x chip and the ZL10353 demodulator,
+	  successor to the Zarlink MT352.
+
 config VIDEO_CX88_DVB_OR51132
 	bool "OR51132 ATSC Support"
 	default y
diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile
index 2b90278..6482b9a 100644
--- a/drivers/media/video/cx88/Makefile
+++ b/drivers/media/video/cx88/Makefile
@@ -17,6 +17,7 @@
 extra-cflags-$(CONFIG_DVB_OR51132)   += -DHAVE_OR51132=1
 extra-cflags-$(CONFIG_DVB_LGDT330X)  += -DHAVE_LGDT330X=1
 extra-cflags-$(CONFIG_DVB_MT352)     += -DHAVE_MT352=1
+extra-cflags-$(CONFIG_DVB_ZL10353)   += -DHAVE_ZL10353=1
 extra-cflags-$(CONFIG_DVB_NXT200X)   += -DHAVE_NXT200X=1
 extra-cflags-$(CONFIG_DVB_CX24123)   += -DHAVE_CX24123=1
 extra-cflags-$(CONFIG_VIDEO_CX88_VP3054)+= -DHAVE_VP3054_I2C=1
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
index 2acccd6..bffef1d 100644
--- a/drivers/media/video/cx88/cx88-alsa.c
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -672,6 +672,11 @@
 	chip = (snd_cx88_card_t *) card->private_data;
 
 	core = cx88_core_get(pci);
+	if (NULL == core) {
+		err = -EINVAL;
+		kfree (chip);
+		return err;
+	}
 
 	if (!pci_dma_supported(pci,0xffffffff)) {
 		dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name);
@@ -688,11 +693,6 @@
 	spin_lock_init(&chip->reg_lock);
 
 	cx88_reset(core);
-	if (NULL == core) {
-		err = -EINVAL;
-		kfree (chip);
-		return err;
-	}
 	chip->core = core;
 
 	/* get irq */
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 1bc9992..c7042cf 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -184,17 +184,18 @@
 		.input          = {{
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
-			.gpio1  = 0x309f,
+			.gpio1  = 0xe09f,
 		},{
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
-			.gpio1  = 0x305f,
+			.gpio1  = 0xe05f,
 		},{
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
-			.gpio1  = 0x305f,
+			.gpio1  = 0xe05f,
 		}},
 		.radio = {
+			.gpio1  = 0xe0df,
 			.type   = CX88_RADIO,
 		},
 	},
@@ -322,19 +323,19 @@
 		.input          = {{
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
-			.gpio0  = 0xff00,
+			.gpio0  = 0xbff0,
 		},{
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
-			.gpio0  = 0xff03,
+			.gpio0  = 0xbff3,
 		},{
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
-			.gpio0  = 0xff03,
+			.gpio0  = 0xbff3,
 		}},
 		.radio = {
 			.type   = CX88_RADIO,
-			.gpio0  = 0xff00,
+			.gpio0  = 0xbff0,
 		},
 	},
 	[CX88_BOARD_ASUS_PVR_416] = {
@@ -1048,6 +1049,50 @@
 		}},
 		.dvb            = 1,
 	},
+	[CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT] = {
+		/* FIXME: Standard video using the cx88 broadcast decoder is
+		 * working, but blackbird isn't working yet, audio is only
+		 * working correctly for television mode. S-Video and Composite
+		 * are working for video-only, so I have them disabled for now.
+		 */
+		.name           = "KWorld HardwareMpegTV XPert",
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x3de2,
+			.gpio2  = 0x00ff,
+		}},
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0  = 0x3de6,
+			.gpio2  = 0x00ff,
+		},
+	},
+	[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID] = {
+		.name           = "DViCO FusionHDTV DVB-T Hybrid",
+		.tuner_type     = TUNER_THOMSON_FE6600,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x0000a75f,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x0000a75b,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x0000a75b,
+		}},
+		.dvb            = 1,
+	},
 
 };
 const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
@@ -1254,6 +1299,18 @@
 		.subdevice = 0xdb11,
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS,
 		/* Re-branded DViCO: UltraView DVB-T Plus */
+	},{
+		.subvendor = 0x17de,
+		.subdevice = 0x0840,
+		.card      = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT,
+	},{
+		.subvendor = 0x18ac,
+		.subdevice = 0xdb40,
+		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID,
+	},{
+		.subvendor = 0x18ac,
+		.subdevice = 0xdb44,
+		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID,
 	},
 };
 const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
@@ -1373,6 +1430,40 @@
 }
 
 /* ----------------------------------------------------------------------- */
+/* some DViCO specific stuff                                               */
+
+static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core)
+{
+	struct i2c_msg msg = { .addr = 0x45, .flags = 0 };
+	int i, err;
+	static u8 init_bufs[13][5] = {
+		{ 0x10, 0x00, 0x20, 0x01, 0x03 },
+		{ 0x10, 0x10, 0x01, 0x00, 0x21 },
+		{ 0x10, 0x10, 0x10, 0x00, 0xCA },
+		{ 0x10, 0x10, 0x12, 0x00, 0x08 },
+		{ 0x10, 0x10, 0x13, 0x00, 0x0A },
+		{ 0x10, 0x10, 0x16, 0x01, 0xC0 },
+		{ 0x10, 0x10, 0x22, 0x01, 0x3D },
+		{ 0x10, 0x10, 0x73, 0x01, 0x2E },
+		{ 0x10, 0x10, 0x72, 0x00, 0xC5 },
+		{ 0x10, 0x10, 0x71, 0x01, 0x97 },
+		{ 0x10, 0x10, 0x70, 0x00, 0x0F },
+		{ 0x10, 0x10, 0xB0, 0x00, 0x01 },
+		{ 0x03, 0x0C },
+	};
+
+	for (i = 0; i < 13; i++) {
+		msg.buf = init_bufs[i];
+		msg.len = (i != 12 ? 5 : 2);
+		err = i2c_transfer(&core->i2c_adap, &msg, 1);
+		if (err != 1) {
+			printk("dvico_fusionhdtv_hybrid_init buf %d failed (err = %d)!\n", i, err);
+			return;
+		}
+	}
+}
+
+/* ----------------------------------------------------------------------- */
 
 void cx88_card_list(struct cx88_core *core, struct pci_dev *pci)
 {
@@ -1438,11 +1529,15 @@
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
+	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
 		/* GPIO0:0 is hooked to mt352 reset pin */
 		cx_set(MO_GP0_IO, 0x00000101);
 		cx_clear(MO_GP0_IO, 0x00000001);
 		msleep(1);
 		cx_set(MO_GP0_IO, 0x00000101);
+		if (0 == core->i2c_rc &&
+		    core->board == CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID)
+			dvico_fusionhdtv_hybrid_init(core);
 		break;
 	case CX88_BOARD_KWORLD_DVB_T:
 	case CX88_BOARD_DNTV_LIVE_DVB_T:
@@ -1460,7 +1555,7 @@
 		if (0 == core->i2c_rc) {
 			/* enable tuner */
 			int i;
-			u8 buffer [] = { 0x10,0x12,0x13,0x04,0x16,0x00,0x14,0x04,0x017,0x00 };
+			static const u8 buffer [] = { 0x10,0x12,0x13,0x04,0x16,0x00,0x14,0x04,0x017,0x00 };
 			core->i2c_client.addr = 0x0a;
 
 			for (i = 0; i < 5; i++)
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index 3720f24..c2cdbaf 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -163,7 +163,7 @@
 
 	/* save pointer to jmp instruction address */
 	risc->jmp = rp;
-	BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size);
+	BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size);
 	return 0;
 }
 
@@ -188,7 +188,7 @@
 
 	/* save pointer to jmp instruction address */
 	risc->jmp = rp;
-	BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size);
+	BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size);
 	return 0;
 }
 
@@ -215,8 +215,7 @@
 void
 cx88_free_buffer(struct pci_dev *pci, struct cx88_buffer *buf)
 {
-	if (in_interrupt())
-		BUG();
+	BUG_ON(in_interrupt());
 	videobuf_waiton(&buf->vb,0,0);
 	videobuf_dma_pci_unmap(pci, &buf->vb.dma);
 	videobuf_dma_free(&buf->vb.dma);
@@ -1061,7 +1060,7 @@
 	core->pci_bus  = pci->bus->number;
 	core->pci_slot = PCI_SLOT(pci->devfn);
 	core->pci_irqmask = 0x00fc00;
-	init_MUTEX(&core->lock);
+	mutex_init(&core->lock);
 
 	core->nr = cx88_devcount++;
 	sprintf(core->name,"cx88[%d]",core->nr);
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index e48aa3f..a9fc269 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -40,6 +40,9 @@
 #  include "cx88-vp3054-i2c.h"
 # endif
 #endif
+#ifdef HAVE_ZL10353
+# include "zl10353.h"
+#endif
 #ifdef HAVE_CX22702
 # include "cx22702.h"
 #endif
@@ -111,6 +114,21 @@
 
 /* ------------------------------------------------------------------ */
 
+#if defined(HAVE_MT352) || defined(HAVE_ZL10353)
+static int zarlink_pll_set(struct dvb_frontend *fe,
+			      struct dvb_frontend_parameters *params,
+			      u8 *pllbuf)
+{
+	struct cx8802_dev *dev = fe->dvb->priv;
+
+	pllbuf[0] = dev->core->pll_addr << 1;
+	dvb_pll_configure(dev->core->pll_desc, pllbuf + 1,
+			  params->frequency,
+			  params->u.ofdm.bandwidth);
+	return 0;
+}
+#endif
+
 #ifdef HAVE_MT352
 static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe)
 {
@@ -176,35 +194,22 @@
 	return 0;
 }
 
-static int mt352_pll_set(struct dvb_frontend* fe,
-			 struct dvb_frontend_parameters* params,
-			 u8* pllbuf)
-{
-	struct cx8802_dev *dev= fe->dvb->priv;
-
-	pllbuf[0] = dev->core->pll_addr << 1;
-	dvb_pll_configure(dev->core->pll_desc, pllbuf+1,
-			  params->frequency,
-			  params->u.ofdm.bandwidth);
-	return 0;
-}
-
 static struct mt352_config dvico_fusionhdtv = {
 	.demod_address = 0x0F,
 	.demod_init    = dvico_fusionhdtv_demod_init,
-	.pll_set       = mt352_pll_set,
+	.pll_set       = zarlink_pll_set,
 };
 
 static struct mt352_config dntv_live_dvbt_config = {
 	.demod_address = 0x0f,
 	.demod_init    = dntv_live_dvbt_demod_init,
-	.pll_set       = mt352_pll_set,
+	.pll_set       = zarlink_pll_set,
 };
 
 static struct mt352_config dvico_fusionhdtv_dual = {
 	.demod_address = 0x0F,
 	.demod_init    = dvico_dual_demod_init,
-	.pll_set       = mt352_pll_set,
+	.pll_set       = zarlink_pll_set,
 };
 
 #ifdef HAVE_VP3054_I2C
@@ -294,6 +299,46 @@
 #endif
 #endif
 
+#ifdef HAVE_ZL10353
+static int dvico_hybrid_tune_pll(struct dvb_frontend *fe,
+				 struct dvb_frontend_parameters *params,
+				 u8 *pllbuf)
+{
+	struct cx8802_dev *dev= fe->dvb->priv;
+	struct i2c_msg msg =
+		{ .addr = dev->core->pll_addr, .flags = 0,
+		  .buf = pllbuf + 1, .len = 4 };
+	int err;
+
+	pllbuf[0] = dev->core->pll_addr << 1;
+	dvb_pll_configure(dev->core->pll_desc, pllbuf + 1,
+			  params->frequency,
+			  params->u.ofdm.bandwidth);
+
+	if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
+		printk(KERN_WARNING "cx88-dvb: %s error "
+			   "(addr %02x <- %02x, err = %i)\n",
+			   __FUNCTION__, pllbuf[0], pllbuf[1], err);
+		if (err < 0)
+			return err;
+		else
+			return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static struct zl10353_config dvico_fusionhdtv_hybrid = {
+	.demod_address = 0x0F,
+	.pll_set       = dvico_hybrid_tune_pll,
+};
+
+static struct zl10353_config dvico_fusionhdtv_plus_v1_1 = {
+	.demod_address = 0x0F,
+	.pll_set       = zarlink_pll_set,
+};
+#endif
+
 #ifdef HAVE_CX22702
 static struct cx22702_config connexant_refboard_config = {
 	.demod_address = 0x43,
@@ -500,6 +545,23 @@
 						   &dev->core->i2c_adap);
 		break;
 #endif
+#if defined(HAVE_MT352) || defined(HAVE_ZL10353)
+	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
+		dev->core->pll_addr = 0x60;
+		dev->core->pll_desc = &dvb_pll_thomson_dtt7579;
+#ifdef HAVE_MT352
+		dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv,
+						 &dev->core->i2c_adap);
+		if (dev->dvb.frontend != NULL)
+			break;
+#endif
+#ifdef HAVE_ZL10353
+		/* ZL10353 replaces MT352 on later cards */
+		dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_plus_v1_1,
+						   &dev->core->i2c_adap);
+#endif
+		break;
+#endif /* HAVE_MT352 || HAVE_ZL10353 */
 #ifdef HAVE_MT352
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
 		dev->core->pll_addr = 0x61;
@@ -507,12 +569,6 @@
 		dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv,
 						 &dev->core->i2c_adap);
 		break;
-	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
-		dev->core->pll_addr = 0x60;
-		dev->core->pll_desc = &dvb_pll_thomson_dtt7579;
-		dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv,
-						 &dev->core->i2c_adap);
-		break;
 	case CX88_BOARD_KWORLD_DVB_T:
 	case CX88_BOARD_DNTV_LIVE_DVB_T:
 	case CX88_BOARD_ADSTECH_DVB_T_PCI:
@@ -540,6 +596,14 @@
 						 &dev->core->i2c_adap);
 		break;
 #endif
+#ifdef HAVE_ZL10353
+	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
+		dev->core->pll_addr = 0x61;
+		dev->core->pll_desc = &dvb_pll_thomson_fe6600;
+		dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_hybrid,
+						   &dev->core->i2c_adap);
+		break;
+#endif
 #ifdef HAVE_OR51132
 	case CX88_BOARD_PCHDTV_HD3000:
 		dev->dvb.frontend = or51132_attach(&pchdtv_hd3000,
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index 165d948..78a63b7 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -34,337 +34,6 @@
 
 /* ---------------------------------------------------------------------- */
 
-/* DigitalNow DNTV Live DVB-T Remote */
-static IR_KEYTAB_TYPE ir_codes_dntv_live_dvb_t[IR_KEYTAB_SIZE] = {
-	[0x00] = KEY_ESC,		/* 'go up a level?' */
-	/* Keys 0 to 9 */
-	[0x0a] = KEY_KP0,
-	[0x01] = KEY_KP1,
-	[0x02] = KEY_KP2,
-	[0x03] = KEY_KP3,
-	[0x04] = KEY_KP4,
-	[0x05] = KEY_KP5,
-	[0x06] = KEY_KP6,
-	[0x07] = KEY_KP7,
-	[0x08] = KEY_KP8,
-	[0x09] = KEY_KP9,
-
-	[0x0b] = KEY_TUNER,		/* tv/fm */
-	[0x0c] = KEY_SEARCH,		/* scan */
-	[0x0d] = KEY_STOP,
-	[0x0e] = KEY_PAUSE,
-	[0x0f] = KEY_LIST,		/* source */
-
-	[0x10] = KEY_MUTE,
-	[0x11] = KEY_REWIND,		/* backward << */
-	[0x12] = KEY_POWER,
-	[0x13] = KEY_S,			/* snap */
-	[0x14] = KEY_AUDIO,		/* stereo */
-	[0x15] = KEY_CLEAR,		/* reset */
-	[0x16] = KEY_PLAY,
-	[0x17] = KEY_ENTER,
-	[0x18] = KEY_ZOOM,		/* full screen */
-	[0x19] = KEY_FASTFORWARD,	/* forward >> */
-	[0x1a] = KEY_CHANNELUP,
-	[0x1b] = KEY_VOLUMEUP,
-	[0x1c] = KEY_INFO,		/* preview */
-	[0x1d] = KEY_RECORD,		/* record */
-	[0x1e] = KEY_CHANNELDOWN,
-	[0x1f] = KEY_VOLUMEDOWN,
-};
-
-/* ---------------------------------------------------------------------- */
-
-/* IO-DATA BCTV7E Remote */
-static IR_KEYTAB_TYPE ir_codes_iodata_bctv7e[IR_KEYTAB_SIZE] = {
-	[0x40] = KEY_TV,
-	[0x20] = KEY_RADIO,		/* FM */
-	[0x60] = KEY_EPG,
-	[0x00] = KEY_POWER,
-
-	/* Keys 0 to 9 */
-	[0x44] = KEY_KP0,		/* 10 */
-	[0x50] = KEY_KP1,
-	[0x30] = KEY_KP2,
-	[0x70] = KEY_KP3,
-	[0x48] = KEY_KP4,
-	[0x28] = KEY_KP5,
-	[0x68] = KEY_KP6,
-	[0x58] = KEY_KP7,
-	[0x38] = KEY_KP8,
-	[0x78] = KEY_KP9,
-
-	[0x10] = KEY_L,			/* Live */
-	[0x08] = KEY_T,			/* Time Shift */
-
-	[0x18] = KEY_PLAYPAUSE,		/* Play */
-
-	[0x24] = KEY_ENTER,		/* 11 */
-	[0x64] = KEY_ESC,		/* 12 */
-	[0x04] = KEY_M,			/* Multi */
-
-	[0x54] = KEY_VIDEO,
-	[0x34] = KEY_CHANNELUP,
-	[0x74] = KEY_VOLUMEUP,
-	[0x14] = KEY_MUTE,
-
-	[0x4c] = KEY_S,			/* SVIDEO */
-	[0x2c] = KEY_CHANNELDOWN,
-	[0x6c] = KEY_VOLUMEDOWN,
-	[0x0c] = KEY_ZOOM,
-
-	[0x5c] = KEY_PAUSE,
-	[0x3c] = KEY_C,			/* || (red) */
-	[0x7c] = KEY_RECORD,		/* recording */
-	[0x1c] = KEY_STOP,
-
-	[0x41] = KEY_REWIND,		/* backward << */
-	[0x21] = KEY_PLAY,
-	[0x61] = KEY_FASTFORWARD,	/* forward >> */
-	[0x01] = KEY_NEXT,		/* skip >| */
-};
-
-/* ---------------------------------------------------------------------- */
-
-/* ADS Tech Instant TV DVB-T PCI Remote */
-static IR_KEYTAB_TYPE ir_codes_adstech_dvb_t_pci[IR_KEYTAB_SIZE] = {
-	/* Keys 0 to 9 */
-	[0x4d] = KEY_0,
-	[0x57] = KEY_1,
-	[0x4f] = KEY_2,
-	[0x53] = KEY_3,
-	[0x56] = KEY_4,
-	[0x4e] = KEY_5,
-	[0x5e] = KEY_6,
-	[0x54] = KEY_7,
-	[0x4c] = KEY_8,
-	[0x5c] = KEY_9,
-
-	[0x5b] = KEY_POWER,
-	[0x5f] = KEY_MUTE,
-	[0x55] = KEY_GOTO,
-	[0x5d] = KEY_SEARCH,
-	[0x17] = KEY_EPG,		/* Guide */
-	[0x1f] = KEY_MENU,
-	[0x0f] = KEY_UP,
-	[0x46] = KEY_DOWN,
-	[0x16] = KEY_LEFT,
-	[0x1e] = KEY_RIGHT,
-	[0x0e] = KEY_SELECT,		/* Enter */
-	[0x5a] = KEY_INFO,
-	[0x52] = KEY_EXIT,
-	[0x59] = KEY_PREVIOUS,
-	[0x51] = KEY_NEXT,
-	[0x58] = KEY_REWIND,
-	[0x50] = KEY_FORWARD,
-	[0x44] = KEY_PLAYPAUSE,
-	[0x07] = KEY_STOP,
-	[0x1b] = KEY_RECORD,
-	[0x13] = KEY_TUNER,		/* Live */
-	[0x0a] = KEY_A,
-	[0x12] = KEY_B,
-	[0x03] = KEY_PROG1,		/* 1 */
-	[0x01] = KEY_PROG2,		/* 2 */
-	[0x00] = KEY_PROG3,		/* 3 */
-	[0x06] = KEY_DVD,
-	[0x48] = KEY_AUX,		/* Photo */
-	[0x40] = KEY_VIDEO,
-	[0x19] = KEY_AUDIO,		/* Music */
-	[0x0b] = KEY_CHANNELUP,
-	[0x08] = KEY_CHANNELDOWN,
-	[0x15] = KEY_VOLUMEUP,
-	[0x1c] = KEY_VOLUMEDOWN,
-};
-
-/* ---------------------------------------------------------------------- */
-
-/* MSI TV@nywhere remote */
-static IR_KEYTAB_TYPE ir_codes_msi_tvanywhere[IR_KEYTAB_SIZE] = {
-	/* Keys 0 to 9 */
-	[0x00] = KEY_0,
-	[0x01] = KEY_1,
-	[0x02] = KEY_2,
-	[0x03] = KEY_3,
-	[0x04] = KEY_4,
-	[0x05] = KEY_5,
-	[0x06] = KEY_6,
-	[0x07] = KEY_7,
-	[0x08] = KEY_8,
-	[0x09] = KEY_9,
-
-	[0x0c] = KEY_MUTE,
-	[0x0f] = KEY_SCREEN,		/* Full Screen */
-	[0x10] = KEY_F,			/* Funtion */
-	[0x11] = KEY_T,			/* Time shift */
-	[0x12] = KEY_POWER,
-	[0x13] = KEY_MEDIA,		/* MTS */
-	[0x14] = KEY_SLOW,
-	[0x16] = KEY_REWIND,		/* backward << */
-	[0x17] = KEY_ENTER,		/* Return */
-	[0x18] = KEY_FASTFORWARD,	/* forward >> */
-	[0x1a] = KEY_CHANNELUP,
-	[0x1b] = KEY_VOLUMEUP,
-	[0x1e] = KEY_CHANNELDOWN,
-	[0x1f] = KEY_VOLUMEDOWN,
-};
-
-/* ---------------------------------------------------------------------- */
-
-/* Cinergy 1400 DVB-T */
-static IR_KEYTAB_TYPE ir_codes_cinergy_1400[IR_KEYTAB_SIZE] = {
-	[0x01] = KEY_POWER,
-	[0x02] = KEY_1,
-	[0x03] = KEY_2,
-	[0x04] = KEY_3,
-	[0x05] = KEY_4,
-	[0x06] = KEY_5,
-	[0x07] = KEY_6,
-	[0x08] = KEY_7,
-	[0x09] = KEY_8,
-	[0x0a] = KEY_9,
-	[0x0c] = KEY_0,
-
-	[0x0b] = KEY_VIDEO,
-	[0x0d] = KEY_REFRESH,
-	[0x0e] = KEY_SELECT,
-	[0x0f] = KEY_EPG,
-	[0x10] = KEY_UP,
-	[0x11] = KEY_LEFT,
-	[0x12] = KEY_OK,
-	[0x13] = KEY_RIGHT,
-	[0x14] = KEY_DOWN,
-	[0x15] = KEY_TEXT,
-	[0x16] = KEY_INFO,
-
-	[0x17] = KEY_RED,
-	[0x18] = KEY_GREEN,
-	[0x19] = KEY_YELLOW,
-	[0x1a] = KEY_BLUE,
-
-	[0x1b] = KEY_CHANNELUP,
-	[0x1c] = KEY_VOLUMEUP,
-	[0x1d] = KEY_MUTE,
-	[0x1e] = KEY_VOLUMEDOWN,
-	[0x1f] = KEY_CHANNELDOWN,
-
-	[0x40] = KEY_PAUSE,
-	[0x4c] = KEY_PLAY,
-	[0x58] = KEY_RECORD,
-	[0x54] = KEY_PREVIOUS,
-	[0x48] = KEY_STOP,
-	[0x5c] = KEY_NEXT,
-};
-
-/* ---------------------------------------------------------------------- */
-
-/* AVERTV STUDIO 303 Remote */
-static IR_KEYTAB_TYPE ir_codes_avertv_303[IR_KEYTAB_SIZE] = {
-	[ 0x2a ] = KEY_KP1,
-	[ 0x32 ] = KEY_KP2,
-	[ 0x3a ] = KEY_KP3,
-	[ 0x4a ] = KEY_KP4,
-	[ 0x52 ] = KEY_KP5,
-	[ 0x5a ] = KEY_KP6,
-	[ 0x6a ] = KEY_KP7,
-	[ 0x72 ] = KEY_KP8,
-	[ 0x7a ] = KEY_KP9,
-	[ 0x0e ] = KEY_KP0,
-
-	[ 0x02 ] = KEY_POWER,
-	[ 0x22 ] = KEY_VIDEO,
-	[ 0x42 ] = KEY_AUDIO,
-	[ 0x62 ] = KEY_ZOOM,
-	[ 0x0a ] = KEY_TV,
-	[ 0x12 ] = KEY_CD,
-	[ 0x1a ] = KEY_TEXT,
-
-	[ 0x16 ] = KEY_SUBTITLE,
-	[ 0x1e ] = KEY_REWIND,
-	[ 0x06 ] = KEY_PRINT,
-
-	[ 0x2e ] = KEY_SEARCH,
-	[ 0x36 ] = KEY_SLEEP,
-	[ 0x3e ] = KEY_SHUFFLE,
-	[ 0x26 ] = KEY_MUTE,
-
-	[ 0x4e ] = KEY_RECORD,
-	[ 0x56 ] = KEY_PAUSE,
-	[ 0x5e ] = KEY_STOP,
-	[ 0x46 ] = KEY_PLAY,
-
-	[ 0x6e ] = KEY_RED,
-	[ 0x0b ] = KEY_GREEN,
-	[ 0x66 ] = KEY_YELLOW,
-	[ 0x03 ] = KEY_BLUE,
-
-	[ 0x76 ] = KEY_LEFT,
-	[ 0x7e ] = KEY_RIGHT,
-	[ 0x13 ] = KEY_DOWN,
-	[ 0x1b ] = KEY_UP,
-};
-
-/* ---------------------------------------------------------------------- */
-
-/* DigitalNow DNTV Live! DVB-T Pro Remote */
-static IR_KEYTAB_TYPE ir_codes_dntv_live_dvbt_pro[IR_KEYTAB_SIZE] = {
-	[ 0x16 ] = KEY_POWER,
-	[ 0x5b ] = KEY_HOME,
-
-	[ 0x55 ] = KEY_TV,		/* live tv */
-	[ 0x58 ] = KEY_TUNER,		/* digital Radio */
-	[ 0x5a ] = KEY_RADIO,		/* FM radio */
-	[ 0x59 ] = KEY_DVD,		/* dvd menu */
-	[ 0x03 ] = KEY_1,
-	[ 0x01 ] = KEY_2,
-	[ 0x06 ] = KEY_3,
-	[ 0x09 ] = KEY_4,
-	[ 0x1d ] = KEY_5,
-	[ 0x1f ] = KEY_6,
-	[ 0x0d ] = KEY_7,
-	[ 0x19 ] = KEY_8,
-	[ 0x1b ] = KEY_9,
-	[ 0x0c ] = KEY_CANCEL,
-	[ 0x15 ] = KEY_0,
-	[ 0x4a ] = KEY_CLEAR,
-	[ 0x13 ] = KEY_BACK,
-	[ 0x00 ] = KEY_TAB,
-	[ 0x4b ] = KEY_UP,
-	[ 0x4e ] = KEY_LEFT,
-	[ 0x4f ] = KEY_OK,
-	[ 0x52 ] = KEY_RIGHT,
-	[ 0x51 ] = KEY_DOWN,
-	[ 0x1e ] = KEY_VOLUMEUP,
-	[ 0x0a ] = KEY_VOLUMEDOWN,
-	[ 0x02 ] = KEY_CHANNELDOWN,
-	[ 0x05 ] = KEY_CHANNELUP,
-	[ 0x11 ] = KEY_RECORD,
-	[ 0x14 ] = KEY_PLAY,
-	[ 0x4c ] = KEY_PAUSE,
-	[ 0x1a ] = KEY_STOP,
-	[ 0x40 ] = KEY_REWIND,
-	[ 0x12 ] = KEY_FASTFORWARD,
-	[ 0x41 ] = KEY_PREVIOUSSONG,	/* replay |< */
-	[ 0x42 ] = KEY_NEXTSONG,	/* skip >| */
-	[ 0x54 ] = KEY_CAMERA,		/* capture */
-	[ 0x50 ] = KEY_LANGUAGE,	/* sap */
-	[ 0x47 ] = KEY_TV2,		/* pip */
-	[ 0x4d ] = KEY_SCREEN,
-	[ 0x43 ] = KEY_SUBTITLE,
-	[ 0x10 ] = KEY_MUTE,
-	[ 0x49 ] = KEY_AUDIO,		/* l/r */
-	[ 0x07 ] = KEY_SLEEP,
-	[ 0x08 ] = KEY_VIDEO,		/* a/v */
-	[ 0x0e ] = KEY_PREVIOUS,	/* recall */
-	[ 0x45 ] = KEY_ZOOM,		/* zoom + */
-	[ 0x46 ] = KEY_ANGLE,		/* zoom - */
-	[ 0x56 ] = KEY_RED,
-	[ 0x57 ] = KEY_GREEN,
-	[ 0x5c ] = KEY_YELLOW,
-	[ 0x5d ] = KEY_BLUE,
-};
-
-/* ---------------------------------------------------------------------- */
-
 struct cx88_IR {
 	struct cx88_core *core;
 	struct input_dev *input;
@@ -517,6 +186,7 @@
 		ir->mask_keydown = 0x02;
 		ir->polling = 5; /* ms */
 		break;
+       case CX88_BOARD_PROLINK_PLAYTVPVR:
 	case CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO:
 		ir_codes = ir_codes_pixelview;
 		ir->gpio_addr = MO_GP1_IO;
@@ -524,6 +194,13 @@
 		ir->mask_keyup = 0x80;
 		ir->polling = 1; /* ms */
 		break;
+	case CX88_BOARD_KWORLD_LTV883:
+		ir_codes = ir_codes_pixelview;
+		ir->gpio_addr = MO_GP1_IO;
+		ir->mask_keycode = 0x1f;
+		ir->mask_keyup = 0x60;
+		ir->polling = 1; /* ms */
+		break;
 	case CX88_BOARD_ADSTECH_DVB_T_PCI:
 		ir_codes = ir_codes_adstech_dvb_t_pci;
 		ir->gpio_addr = MO_GP1_IO;
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 073494c..6c97aa74 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -227,7 +227,7 @@
 			.minimum       = 0x00,
 			.maximum       = 0xff,
 			.step          = 1,
-			.default_value = 0,
+			.default_value = 0x7f,
 			.type          = V4L2_CTRL_TYPE_INTEGER,
 		},
 		.off                   = 128,
@@ -255,7 +255,7 @@
 			.minimum       = 0,
 			.maximum       = 0xff,
 			.step          = 1,
-			.default_value = 0,
+			.default_value = 0x7f,
 			.type          = V4L2_CTRL_TYPE_INTEGER,
 		},
 		.off                   = 128,
@@ -300,7 +300,7 @@
 			.minimum       = 0,
 			.maximum       = 0x3f,
 			.step          = 1,
-			.default_value = 0x1f,
+			.default_value = 0x3f,
 			.type          = V4L2_CTRL_TYPE_INTEGER,
 		},
 		.reg                   = AUD_VOL_CTL,
@@ -336,17 +336,17 @@
 		return 1;
 
 	/* is it free? */
-	down(&core->lock);
+	mutex_lock(&core->lock);
 	if (dev->resources & bit) {
 		/* no, someone else uses it */
-		up(&core->lock);
+		mutex_unlock(&core->lock);
 		return 0;
 	}
 	/* it's free, grab it */
 	fh->resources  |= bit;
 	dev->resources |= bit;
 	dprintk(1,"res: get %d\n",bit);
-	up(&core->lock);
+	mutex_unlock(&core->lock);
 	return 1;
 }
 
@@ -366,14 +366,13 @@
 void res_free(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bits)
 {
 	struct cx88_core *core = dev->core;
-	if ((fh->resources & bits) != bits)
-		BUG();
+	BUG_ON((fh->resources & bits) != bits);
 
-	down(&core->lock);
+	mutex_lock(&core->lock);
 	fh->resources  &= ~bits;
 	dev->resources &= ~bits;
 	dprintk(1,"res: put %d\n",bits);
-	up(&core->lock);
+	mutex_unlock(&core->lock);
 }
 
 /* ------------------------------------------------------------------ */
@@ -909,7 +908,8 @@
 	value = c->sreg ? cx_sread(c->sreg) : cx_read(c->reg);
 	switch (ctl->id) {
 	case V4L2_CID_AUDIO_BALANCE:
-		ctl->value = (value & 0x40) ? (value & 0x3f) : (0x40 - (value & 0x3f));
+		ctl->value = ((value & 0x7f) < 0x40) ? ((value & 0x7f) + 0x40)
+					: (0x7f - (value & 0x7f));
 		break;
 	case V4L2_CID_AUDIO_VOLUME:
 		ctl->value = 0x3f - (value & 0x3f);
@@ -918,9 +918,9 @@
 		ctl->value = ((value + (c->off << c->shift)) & c->mask) >> c->shift;
 		break;
 	}
-	printk("get_control id=0x%X reg=0x%02x val=0x%02x (mask 0x%02x)%s\n",
-					ctl->id, c->reg, ctl->value,
-					c->mask, c->sreg ? " [shadowed]" : "");
+	dprintk(1,"get_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n",
+				ctl->id, c->v.name, ctl->value, c->reg,
+				value,c->mask, c->sreg ? " [shadowed]" : "");
 	return 0;
 }
 
@@ -946,7 +946,7 @@
 	mask=c->mask;
 	switch (ctl->id) {
 	case V4L2_CID_AUDIO_BALANCE:
-		value = (ctl->value < 0x40) ? (0x40 - ctl->value) : ctl->value;
+		value = (ctl->value < 0x40) ? (0x7f - ctl->value) : (ctl->value - 0x40);
 		break;
 	case V4L2_CID_AUDIO_VOLUME:
 		value = 0x3f - (ctl->value & 0x3f);
@@ -969,9 +969,9 @@
 		value = ((ctl->value - c->off) << c->shift) & c->mask;
 		break;
 	}
-	printk("set_control id=0x%X reg=0x%02x val=0x%02x (mask 0x%02x)%s\n",
-					ctl->id, c->reg, value,
-					mask, c->sreg ? " [shadowed]" : "");
+	dprintk(1,"set_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n",
+				ctl->id, c->v.name, ctl->value, c->reg, value,
+				mask, c->sreg ? " [shadowed]" : "");
 	if (c->sreg) {
 		cx_sandor(c->sreg, c->reg, mask, value);
 	} else {
@@ -987,8 +987,7 @@
 
 	for (i = 0; i < CX8800_CTLS; i++) {
 		ctrl.id=cx8800_ctls[i].v.id;
-		ctrl.value=cx8800_ctls[i].v.default_value
-				+cx8800_ctls[i].off;
+		ctrl.value=cx8800_ctls[i].v.default_value;
 		set_control(core, &ctrl);
 	}
 }
@@ -1252,7 +1251,7 @@
 {
 	int err;
 
-	dprintk( 1, "CORE IOCTL: 0x%x\n", cmd );
+	dprintk(2, "CORE IOCTL: 0x%x\n", cmd );
 	if (video_debug > 1)
 		v4l_print_ioctl(core->name,cmd);
 
@@ -1291,9 +1290,9 @@
 		if (i == ARRAY_SIZE(tvnorms))
 			return -EINVAL;
 
-		down(&core->lock);
+		mutex_lock(&core->lock);
 		cx88_set_tvnorm(core,&tvnorms[i]);
-		up(&core->lock);
+		mutex_unlock(&core->lock);
 		return 0;
 	}
 
@@ -1343,10 +1342,10 @@
 
 		if (*i >= 4)
 			return -EINVAL;
-		down(&core->lock);
+		mutex_lock(&core->lock);
 		cx88_newstation(core);
 		video_mux(core,*i);
-		up(&core->lock);
+		mutex_unlock(&core->lock);
 		return 0;
 	}
 
@@ -1438,7 +1437,7 @@
 			return -EINVAL;
 		if (1 == radio && f->type != V4L2_TUNER_RADIO)
 			return -EINVAL;
-		down(&core->lock);
+		mutex_lock(&core->lock);
 		core->freq = f->frequency;
 		cx88_newstation(core);
 		cx88_call_i2c_clients(core,VIDIOC_S_FREQUENCY,f);
@@ -1447,7 +1446,7 @@
 		msleep (10);
 		cx88_set_tvaudio(core);
 
-		up(&core->lock);
+		mutex_unlock(&core->lock);
 		return 0;
 	}
 
@@ -1921,11 +1920,11 @@
 	pci_set_drvdata(pci_dev,dev);
 
 	/* initial device configuration */
-	down(&core->lock);
+	mutex_lock(&core->lock);
 	cx88_set_tvnorm(core,tvnorms);
 	init_controls(core);
 	video_mux(core,0);
-	up(&core->lock);
+	mutex_unlock(&core->lock);
 
 	/* start tvaudio thread */
 	if (core->tuner_type != TUNER_ABSENT)
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index e9fd55b..cfa8668 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -35,6 +35,7 @@
 #include "cx88-reg.h"
 
 #include <linux/version.h>
+#include <linux/mutex.h>
 #define CX88_VERSION_CODE KERNEL_VERSION(0,0,5)
 
 #ifndef TRUE
@@ -62,7 +63,7 @@
 /* need "shadow" registers for some write-only ones ... */
 #define SHADOW_AUD_VOL_CTL           1
 #define SHADOW_AUD_BAL_CTL           2
-#define SHADOW_MAX                   2
+#define SHADOW_MAX                   3
 
 /* FM Radio deemphasis type */
 enum cx88_deemph_type {
@@ -187,6 +188,8 @@
 #define CX88_BOARD_DNTV_LIVE_DVB_T_PRO     42
 #define CX88_BOARD_KWORLD_DVB_T_CX22702    43
 #define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL 44
+#define CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT 45
+#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID 46
 
 enum cx88_itype {
 	CX88_VMUX_COMPOSITE1 = 1,
@@ -308,8 +311,7 @@
 	/* IR remote control state */
 	struct cx88_IR             *ir;
 
-	struct semaphore           lock;
-
+	struct mutex               lock;
 	/* various v4l controls */
 	u32                        freq;
 
diff --git a/drivers/media/video/dpc7146.c b/drivers/media/video/dpc7146.c
index 2831bdd..0fcc935 100644
--- a/drivers/media/video/dpc7146.c
+++ b/drivers/media/video/dpc7146.c
@@ -1,6 +1,6 @@
 /*
     dpc7146.c - v4l2 driver for the dpc7146 demonstration board
-    
+
     Copyright (C) 2000-2003 Michael Hunold <michael@mihu.de>
 
     This program is free software; you can redistribute it and/or modify
@@ -52,7 +52,7 @@
 #define SAA711X_DECODED_BYTES_OF_TS_2   0x1C
 #define SAA711X_STATUS_BYTE             0x1F
 
-#define DPC_BOARD_CAN_DO_VBI(dev)   (dev->revision != 0) 
+#define DPC_BOARD_CAN_DO_VBI(dev)   (dev->revision != 0)
 
 static int debug = 0;
 module_param(debug, int, 0);
@@ -81,16 +81,16 @@
 	struct video_device	*video_dev;
 	struct video_device	*vbi_dev;
 
-	struct i2c_adapter	i2c_adapter;	
+	struct i2c_adapter	i2c_adapter;
 	struct i2c_client	*saa7111a;
-	
+
 	int cur_input;	/* current input */
 };
 
 /* fixme: add vbi stuff here */
 static int dpc_probe(struct saa7146_dev* dev)
 {
-	struct dpc* dpc = NULL;	
+	struct dpc* dpc = NULL;
 	struct i2c_client *client;
 	struct list_head *item;
 
@@ -118,20 +118,20 @@
 	/* loop through all i2c-devices on the bus and look who is there */
 	list_for_each(item,&dpc->i2c_adapter.clients) {
 		client = list_entry(item, struct i2c_client, list);
-		if( I2C_SAA7111A == client->addr ) 
+		if( I2C_SAA7111A == client->addr )
 			dpc->saa7111a = client;
 	}
 
 	/* check if all devices are present */
 	if( 0 == dpc->saa7111a ) {
-		DEB_D(("dpc_v4l2.o: dpc_attach failed for this device.\n"));	
+		DEB_D(("dpc_v4l2.o: dpc_attach failed for this device.\n"));
 		i2c_del_adapter(&dpc->i2c_adapter);
 		kfree(dpc);
 		return -ENODEV;
 	}
-	
-	/* all devices are present, probe was successful */	
-	DEB_D(("dpc_v4l2.o: dpc_probe succeeded for this device.\n"));	
+
+	/* all devices are present, probe was successful */
+	DEB_D(("dpc_v4l2.o: dpc_probe succeeded for this device.\n"));
 
 	/* we store the pointer in our private data field */
 	dev->ext_priv = dpc;
@@ -182,7 +182,7 @@
 static int dpc_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
 {
 	struct dpc* dpc = (struct dpc*)dev->ext_priv;
-	
+
 	DEB_D(("dpc_v4l2.o: dpc_attach called.\n"));
 
 	/* checking for i2c-devices can be omitted here, because we
@@ -193,7 +193,7 @@
 		ERR(("cannot register capture v4l2 device. skipping.\n"));
 		return -1;
 	}
-	
+
 	/* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
 	if( 0 != DPC_BOARD_CAN_DO_VBI(dev)) {
 		if( 0 != saa7146_register_device(&dpc->vbi_dev, dev, "dpc", VFL_TYPE_VBI)) {
@@ -205,18 +205,18 @@
 
 	printk("dpc: found 'dpc7146 demonstration board'-%d.\n",dpc_num);
 	dpc_num++;
-	
+
 	/* the rest */
 	dpc->cur_input = 0;
 	dpc_init_done(dev);
-	
+
 	return 0;
 }
 
 static int dpc_detach(struct saa7146_dev* dev)
 {
 	struct dpc* dpc = (struct dpc*)dev->ext_priv;
-	
+
 	DEB_EE(("dev:%p\n",dev));
 
 	i2c_release_client(dpc->saa7111a);
@@ -238,25 +238,25 @@
 int dpc_vbi_bypass(struct saa7146_dev* dev)
 {
 	struct dpc* dpc = (struct dpc*)dev->ext_priv;
-	
+
 	int i = 1;
 
 	/* switch bypass in saa7111a */
 	if ( 0 != dpc->saa7111a->driver->command(dpc->saa7111a,SAA711X_VBI_BYPASS, &i)) {
 		printk("dpc_v4l2.o: VBI_BYPASS: could not address saa7111a.\n");
 		return -1;
-	}			
+	}
 
 	return 0;
 }
 #endif
 
-static int dpc_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) 
+static int dpc_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
 {
 	struct saa7146_dev *dev = fh->dev;
 	struct dpc* dpc = (struct dpc*)dev->ext_priv;
 /*
-	struct saa7146_vv *vv = dev->vv_data; 
+	struct saa7146_vv *vv = dev->vv_data;
 */
 	switch(cmd)
 	{
@@ -264,11 +264,11 @@
 	{
 		struct v4l2_input *i = arg;
 		DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index));
-		
+
 		if( i->index < 0 || i->index >= DPC_INPUTS) {
 			return -EINVAL;
 		}
-		
+
 		memcpy(i, &dpc_inputs[i->index], sizeof(struct v4l2_input));
 
 		DEB_D(("dpc_v4l2.o: v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n",i->index));
@@ -289,13 +289,13 @@
 		if (input < 0 || input >= DPC_INPUTS) {
 			return -EINVAL;
 		}
-	
+
 		dpc->cur_input = input;
 
 		/* fixme: switch input here, switch audio, too! */
 //		saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, input_port_selection[input].hps_sync);
 		printk("dpc_v4l2.o: VIDIOC_S_INPUT: fixme switch input.\n");
-		
+
 		return 0;
 	}
 	default:
@@ -334,8 +334,8 @@
 static struct saa7146_extension extension;
 
 static struct saa7146_pci_extension_data dpc = {
-        .ext_priv = "Multimedia eXtension Board",
-        .ext = &extension,
+	.ext_priv = "Multimedia eXtension Board",
+	.ext = &extension,
 };
 
 static struct pci_device_id pci_tbl[] = {
@@ -357,7 +357,7 @@
 	.capabilities	= V4L2_CAP_VBI_CAPTURE,
 	.stds		= &standard[0],
 	.num_stds	= sizeof(standard)/sizeof(struct saa7146_standard),
-	.std_callback	= &std_callback, 
+	.std_callback	= &std_callback,
 	.ioctls		= &ioctls[0],
 	.ioctl		= dpc_ioctl,
 };
@@ -365,7 +365,7 @@
 static struct saa7146_extension extension = {
 	.name		= "dpc7146 demonstration board",
 	.flags		= SAA7146_USE_I2C_IRQ,
-	
+
 	.pci_tbl	= &pci_tbl[0],
 	.module		= THIS_MODULE,
 
@@ -375,7 +375,7 @@
 
 	.irq_mask	= 0,
 	.irq_func	= NULL,
-};	
+};
 
 static int __init dpc_init_module(void)
 {
@@ -383,7 +383,7 @@
 		DEB_S(("failed to register extension.\n"));
 		return -ENODEV;
 	}
-	
+
 	return 0;
 }
 
diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig
index 885fd01..5a793ae 100644
--- a/drivers/media/video/em28xx/Kconfig
+++ b/drivers/media/video/em28xx/Kconfig
@@ -5,6 +5,7 @@
 	select VIDEO_TUNER
 	select VIDEO_TVEEPROM
 	select VIDEO_IR
+	select VIDEO_SAA711X
 	---help---
 	  This is a video4linux driver for Empia 28xx based TV cards.
 
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 58f7b41..4e22fc4 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -72,6 +72,24 @@
 			.amux     = 1,
 		}},
 	},
+	[EM2820_BOARD_KWORLD_PVRTV2800RF] = {
+		.name         = "Kworld PVR TV 2800 RF",
+		.is_em2800    = 0,
+		.vchannels    = 2,
+		.norm         = VIDEO_MODE_PAL,
+		.tda9887_conf = TDA9887_PRESENT,
+		.has_tuner    = 1,
+		.decoder      = EM28XX_SAA7113,
+		.input           = {{
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = 0,
+			.amux     = 1,
+		},{
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = 9,
+			.amux     = 1,
+		}},
+	},
 	[EM2820_BOARD_TERRATEC_CINERGY_250] = {
 		.name         = "Terratec Cinergy 250 USB",
 		.vchannels    = 3,
@@ -83,7 +101,7 @@
 		.input          = {{
 			.type     = EM28XX_VMUX_TELEVISION,
 			.vmux     = 2,
-			.amux     = 0,
+			.amux     = 1,
 		},{
 			.type     = EM28XX_VMUX_COMPOSITE1,
 			.vmux     = 0,
@@ -257,27 +275,51 @@
 	{ },
 };
 
+void em28xx_pre_card_setup(struct em28xx *dev)
+{
+	/* request some modules */
+	switch(dev->model){
+		case EM2880_BOARD_TERRATEC_PRODIGY_XS:
+		case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+		case EM2880_BOARD_TERRATEC_HYBRID_XS:
+			{
+				em28xx_write_regs_req(dev, 0x00, 0x08, "\x7d", 1); // reset through GPIO?
+				break;
+			}
+	}
+}
+
 void em28xx_card_setup(struct em28xx *dev)
 {
 	/* request some modules */
-	if (dev->model == EM2820_BOARD_HAUPPAUGE_WINTV_USB_2) {
-		struct tveeprom tv;
+	switch(dev->model){
+		case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
+			{
+				struct tveeprom tv;
 #ifdef CONFIG_MODULES
-		request_module("tveeprom");
-		request_module("ir-kbd-i2c");
-		request_module("msp3400");
+				request_module("tveeprom");
+				request_module("ir-kbd-i2c");
+				request_module("msp3400");
 #endif
-		/* Call first TVeeprom */
+				/* Call first TVeeprom */
 
-		dev->i2c_client.addr = 0xa0 >> 1;
-		tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata);
+				dev->i2c_client.addr = 0xa0 >> 1;
+				tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata);
 
-		dev->tuner_type= tv.tuner_type;
-		if (tv.audio_processor == AUDIO_CHIP_MSP34XX) {
-			dev->i2s_speed=2048000;
-			dev->has_msp34xx=1;
-		} else
-			dev->has_msp34xx=0;
+				dev->tuner_type= tv.tuner_type;
+				if (tv.audio_processor == AUDIO_CHIP_MSP34XX) {
+					dev->i2s_speed=2048000;
+					dev->has_msp34xx=1;
+				} else
+					dev->has_msp34xx=0;
+				break;
+			}
+		case EM2820_BOARD_KWORLD_PVRTV2800RF:
+			{
+				em28xx_write_regs_req(dev,0x00,0x08, "\xf9", 1); // GPIO enables sound on KWORLD PVR TV 2800RF
+				break;
+			}
+
 	}
 }
 
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
index 6ca8631..5b6cece 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -420,7 +420,6 @@
 		tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
 		tun_setup.type = dev->tuner_type;
 		tun_setup.addr = dev->tuner_addr;
-
 		em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
 	}
 
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index 30dfa53..31e89e4 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -43,91 +43,6 @@
 #define dprintk(fmt, arg...)	if (ir_debug) \
 	printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg)
 
-/* ---------------------------------------------------------------------- */
-
-static IR_KEYTAB_TYPE ir_codes_em_terratec[IR_KEYTAB_SIZE] = {
-	[ 0x01 ] = KEY_CHANNEL,
-	[ 0x02 ] = KEY_SELECT,
-	[ 0x03 ] = KEY_MUTE,
-	[ 0x04 ] = KEY_POWER,
-	[ 0x05 ] = KEY_KP1,
-	[ 0x06 ] = KEY_KP2,
-	[ 0x07 ] = KEY_KP3,
-	[ 0x08 ] = KEY_CHANNELUP,
-	[ 0x09 ] = KEY_KP4,
-	[ 0x0a ] = KEY_KP5,
-	[ 0x0b ] = KEY_KP6,
-	[ 0x0c ] = KEY_CHANNELDOWN,
-	[ 0x0d ] = KEY_KP7,
-	[ 0x0e ] = KEY_KP8,
-	[ 0x0f ] = KEY_KP9,
-	[ 0x10 ] = KEY_VOLUMEUP,
-	[ 0x11 ] = KEY_KP0,
-	[ 0x12 ] = KEY_MENU,
-	[ 0x13 ] = KEY_PRINT,
-	[ 0x14 ] = KEY_VOLUMEDOWN,
-	[ 0x16 ] = KEY_PAUSE,
-	[ 0x18 ] = KEY_RECORD,
-	[ 0x19 ] = KEY_REWIND,
-	[ 0x1a ] = KEY_PLAY,
-	[ 0x1b ] = KEY_FORWARD,
-	[ 0x1c ] = KEY_BACKSPACE,
-	[ 0x1e ] = KEY_STOP,
-	[ 0x40 ] = KEY_ZOOM,
-};
-
-static IR_KEYTAB_TYPE ir_codes_em_pinnacle_usb[IR_KEYTAB_SIZE] = {
-	[ 0x3a ] = KEY_KP0,
-	[ 0x31 ] = KEY_KP1,
-	[ 0x32 ] = KEY_KP2,
-	[ 0x33 ] = KEY_KP3,
-	[ 0x34 ] = KEY_KP4,
-	[ 0x35 ] = KEY_KP5,
-	[ 0x36 ] = KEY_KP6,
-	[ 0x37 ] = KEY_KP7,
-	[ 0x38 ] = KEY_KP8,
-	[ 0x39 ] = KEY_KP9,
-
-	[ 0x2f ] = KEY_POWER,
-
-	[ 0x2e ] = KEY_P,
-	[ 0x1f ] = KEY_L,
-	[ 0x2b ] = KEY_I,
-
-	[ 0x2d ] = KEY_ZOOM,
-	[ 0x1e ] = KEY_ZOOM,
-	[ 0x1b ] = KEY_VOLUMEUP,
-	[ 0x0f ] = KEY_VOLUMEDOWN,
-	[ 0x17 ] = KEY_CHANNELUP,
-	[ 0x1c ] = KEY_CHANNELDOWN,
-	[ 0x25 ] = KEY_INFO,
-
-	[ 0x3c ] = KEY_MUTE,
-
-	[ 0x3d ] = KEY_LEFT,
-	[ 0x3b ] = KEY_RIGHT,
-
-	[ 0x3f ] = KEY_UP,
-	[ 0x3e ] = KEY_DOWN,
-	[ 0x1a ] = KEY_PAUSE,
-
-	[ 0x1d ] = KEY_MENU,
-	[ 0x19 ] = KEY_PLAY,
-	[ 0x16 ] = KEY_REWIND,
-	[ 0x13 ] = KEY_FORWARD,
-	[ 0x15 ] = KEY_PAUSE,
-	[ 0x0e ] = KEY_REWIND,
-	[ 0x0d ] = KEY_PLAY,
-	[ 0x0b ] = KEY_STOP,
-	[ 0x07 ] = KEY_FORWARD,
-	[ 0x27 ] = KEY_RECORD,
-	[ 0x26 ] = KEY_TUNER,
-	[ 0x29 ] = KEY_TEXT,
-	[ 0x2a ] = KEY_MEDIA,
-	[ 0x18 ] = KEY_EPG,
-	[ 0x27 ] = KEY_RECORD,
-};
-
 /* ----------------------------------------------------------------------- */
 
 static int get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 5b26780..780342f 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -28,6 +28,7 @@
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/bitmap.h>
 #include <linux/usb.h>
 #include <linux/i2c.h>
 #include <linux/version.h>
@@ -59,8 +60,14 @@
 static LIST_HEAD(em28xx_devlist);
 
 static unsigned int card[]     = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
+static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
+static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
 module_param_array(card,  int, NULL, 0444);
+module_param_array(video_nr, int, NULL, 0444);
+module_param_array(vbi_nr, int, NULL, 0444);
 MODULE_PARM_DESC(card,"card type");
+MODULE_PARM_DESC(video_nr,"video device numbers");
+MODULE_PARM_DESC(vbi_nr,"vbi device numbers");
 
 static int tuner = -1;
 module_param(tuner, int, 0444);
@@ -70,6 +77,9 @@
 module_param(video_debug,int,0644);
 MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
 
+/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */
+static unsigned long em28xx_devused;
+
 /* supported tv norms */
 static struct em28xx_tvnorm tvnorms[] = {
 	{
@@ -91,23 +101,6 @@
 	}
 };
 
-static const unsigned char saa7114_i2c_init[] = {
-	0x00,0x00,0x01,0x08,0x02,0xc4,0x03,0x30,0x04,0x90,0x05,0x90,0x06,0xeb,0x07,0xe0,
-	0x08,0x88,0x09,0x40,0x0a,0x80,0x0b,0x44,0x0c,0x40,0x0d,0x00,0x0e,0x81,0x0f,0x2a,
-	0x10,0x06,0x11,0x00,0x12,0xc8,0x13,0x80,0x14,0x00,0x15,0x11,0x16,0x01,0x17,0x42,
-	0x18,0x40,0x19,0x80,0x40,0x00,0x41,0xff,0x42,0xff,0x43,0xff,0x44,0xff,0x45,0xff,
-	0x46,0xff,0x47,0xff,0x48,0xff,0x49,0xff,0x4a,0xff,0x4b,0xff,0x4c,0xff,0x4d,0xff,
-	0x4e,0xff,0x4f,0xff,0x50,0xff,0x51,0xff,0x52,0xff,0x53,0xff,0x54,0x5f,0x55,0xff,
-	0x56,0xff,0x57,0xff,0x58,0x00,0x59,0x47,0x5a,0x03,0x5b,0x03,0x5d,0x3e,0x5e,0x00,
-	0x80,0x1c,0x83,0x01,0x84,0xa5,0x85,0x10,0x86,0x45,0x87,0x41,0x88,0xf0,0x88,0x00,
-	0x88,0xf0,0x90,0x00,0x91,0x08,0x92,0x00,0x93,0x80,0x94,0x08,0x95,0x00,0x96,0xc0,
-	0x97,0x02,0x98,0x13,0x99,0x00,0x9a,0x38,0x9b,0x01,0x9c,0x80,0x9d,0x02,0x9e,0x06,
-	0x9f,0x01,0xa0,0x01,0xa1,0x00,0xa2,0x00,0xa4,0x80,0xa5,0x36,0xa6,0x36,0xa8,0x67,
-	0xa9,0x04,0xaa,0x00,0xac,0x33,0xad,0x02,0xae,0x00,0xb0,0xcd,0xb1,0x04,0xb2,0xcd,
-	0xb3,0x04,0xb4,0x01,0xb8,0x00,0xb9,0x00,0xba,0x00,0xbb,0x00,0xbc,0x00,0xbd,0x00,
-	0xbe,0x00,0xbf,0x00
-};
-
 #define TVNORMS ARRAY_SIZE(tvnorms)
 
 /* supported controls */
@@ -134,65 +127,6 @@
 	}
 };
 
-/* FIXME: These are specific to saa711x - should be moved to its code */
-static struct v4l2_queryctrl saa711x_qctrl[] = {
-	{
-		.id = V4L2_CID_BRIGHTNESS,
-		.type = V4L2_CTRL_TYPE_INTEGER,
-		.name = "Brightness",
-		.minimum = -128,
-		.maximum = 127,
-		.step = 1,
-		.default_value = 0,
-		.flags = 0,
-	},{
-		.id = V4L2_CID_CONTRAST,
-		.type = V4L2_CTRL_TYPE_INTEGER,
-		.name = "Contrast",
-		.minimum = 0x0,
-		.maximum = 0x1f,
-		.step = 0x1,
-		.default_value = 0x10,
-		.flags = 0,
-	},{
-		.id = V4L2_CID_SATURATION,
-		.type = V4L2_CTRL_TYPE_INTEGER,
-		.name = "Saturation",
-		.minimum = 0x0,
-		.maximum = 0x1f,
-		.step = 0x1,
-		.default_value = 0x10,
-		.flags = 0,
-	},{
-		.id = V4L2_CID_RED_BALANCE,
-		.type = V4L2_CTRL_TYPE_INTEGER,
-		.name = "Red chroma balance",
-		.minimum = -128,
-		.maximum = 127,
-		.step = 1,
-		.default_value = 0,
-		.flags = 0,
-	},{
-		.id = V4L2_CID_BLUE_BALANCE,
-		.type = V4L2_CTRL_TYPE_INTEGER,
-		.name = "Blue chroma balance",
-		.minimum = -128,
-		.maximum = 127,
-		.step = 1,
-		.default_value = 0,
-		.flags = 0,
-	},{
-		.id = V4L2_CID_GAMMA,
-		.type = V4L2_CTRL_TYPE_INTEGER,
-		.name = "Gamma",
-		.minimum = 0x0,
-		.maximum = 0x3f,
-		.step = 0x1,
-		.default_value = 0x20,
-		.flags = 0,
-	}
-};
-
 static struct usb_driver em28xx_usb_driver;
 
 static DEFINE_MUTEX(em28xx_sysfs_lock);
@@ -211,6 +145,11 @@
 	em28xx_write_regs_req(dev, 0x00, 0x06, "\x40", 1);
 
 	/* enable vbi capturing */
+
+/*	em28xx_write_regs_req(dev,0x00,0x0e,"\xC0",1); audio register */
+/*	em28xx_write_regs_req(dev,0x00,0x0f,"\x80",1); clk register */
+	em28xx_write_regs_req(dev,0x00,0x11,"\x51",1);
+
 	em28xx_audio_usb_mute(dev, 1);
 	dev->mute = 1;		/* maybe not the right place... */
 	dev->volume = 0x1f;
@@ -230,22 +169,9 @@
 static void em28xx_config_i2c(struct em28xx *dev)
 {
 	struct v4l2_frequency f;
-	struct video_decoder_init em28xx_vdi = {.data = NULL };
-
-
-	/* configure decoder */
-	if(dev->model == EM2820_BOARD_MSI_VOX_USB_2){
-		em28xx_vdi.data=saa7114_i2c_init;
-		em28xx_vdi.len=sizeof(saa7114_i2c_init);
-	}
-
-
-	em28xx_i2c_call_clients(dev, DECODER_INIT, &em28xx_vdi);
-	em28xx_i2c_call_clients(dev, DECODER_SET_INPUT, &dev->ctl_input);
-/*	em28xx_i2c_call_clients(dev,DECODER_SET_PICTURE, &dev->vpic); */
-/*	em28xx_i2c_call_clients(dev,DECODER_SET_NORM,&dev->tvnorm->id); */
-/*	em28xx_i2c_call_clients(dev,DECODER_ENABLE_OUTPUT,&output); */
-/*	em28xx_i2c_call_clients(dev,DECODER_DUMP, NULL); */
+	em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, NULL);
+	em28xx_i2c_call_clients(dev, VIDIOC_S_INPUT, &dev->ctl_input);
+	em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL);
 
 	/* configure tuner */
 	f.tuner = 0;
@@ -285,8 +211,7 @@
 	dev->ctl_input = index;
 	dev->ctl_ainput = INPUT(index)->amux;
 
-	em28xx_i2c_call_clients(dev, DECODER_SET_INPUT, &input);
-
+	em28xx_i2c_call_clients(dev, VIDIOC_S_INPUT, &input);
 
 	em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,input,dev->ctl_ainput);
 
@@ -298,11 +223,11 @@
 		em28xx_audio_source(dev, ainput);
 	} else {
 		switch (dev->ctl_ainput) {
-		case 0:
-			ainput = EM28XX_AUDIO_SRC_TUNER;
-			break;
-		default:
-			ainput = EM28XX_AUDIO_SRC_LINE;
+			case 0:
+				ainput = EM28XX_AUDIO_SRC_TUNER;
+				break;
+			default:
+				ainput = EM28XX_AUDIO_SRC_LINE;
 		}
 		em28xx_audio_source(dev, ainput);
 	}
@@ -323,13 +248,20 @@
 		h = list_entry(list, struct em28xx, devlist);
 		if (h->vdev->minor == minor) {
 			dev  = h;
+			dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		}
+		if (h->vbi_dev->minor == minor) {
+			dev  = h;
+			dev->type = V4L2_BUF_TYPE_VBI_CAPTURE;
 		}
 	}
+	if (NULL == dev)
+		return -ENODEV;
 
 	filp->private_data=dev;
 
-
-	em28xx_videodbg("users=%d\n", dev->users);
+	em28xx_videodbg("open minor=%d type=%s users=%d\n",
+				minor,v4l2_type_names[dev->type],dev->users);
 
 	if (!down_read_trylock(&em28xx_disconnect))
 		return -ERESTARTSYS;
@@ -340,40 +272,36 @@
 		return -EBUSY;
 	}
 
-/*	if(dev->vbi_dev->minor == minor){
-		dev->type=V4L2_BUF_TYPE_VBI_CAPTURE;
-	}*/
-	if (dev->vdev->minor == minor) {
-		dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	}
-
-	init_MUTEX(&dev->fileop_lock);	/* to 1 == available */
+	mutex_init(&dev->fileop_lock);	/* to 1 == available */
 	spin_lock_init(&dev->queue_lock);
 	init_waitqueue_head(&dev->wait_frame);
 	init_waitqueue_head(&dev->wait_stream);
 
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 
-	em28xx_set_alternate(dev);
+	if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		em28xx_set_alternate(dev);
 
-	dev->width = norm_maxw(dev);
-	dev->height = norm_maxh(dev);
-	dev->frame_size = dev->width * dev->height * 2;
-	dev->field_size = dev->frame_size >> 1;	/*both_fileds ? dev->frame_size>>1 : dev->frame_size; */
-	dev->bytesperline = dev->width * 2;
-	dev->hscale = 0;
-	dev->vscale = 0;
+		dev->width = norm_maxw(dev);
+		dev->height = norm_maxh(dev);
+		dev->frame_size = dev->width * dev->height * 2;
+		dev->field_size = dev->frame_size >> 1;	/*both_fileds ? dev->frame_size>>1 : dev->frame_size; */
+		dev->bytesperline = dev->width * 2;
+		dev->hscale = 0;
+		dev->vscale = 0;
 
-	em28xx_capture_start(dev, 1);
-	em28xx_resolution_set(dev);
+		em28xx_capture_start(dev, 1);
+		em28xx_resolution_set(dev);
 
-	/* device needs to be initialized before isoc transfer */
-	video_mux(dev, 0);
+		/* device needs to be initialized before isoc transfer */
+		video_mux(dev, 0);
 
-	/* start the transfer */
-	errCode = em28xx_init_isoc(dev);
-	if (errCode)
-		goto err;
+		/* start the transfer */
+		errCode = em28xx_init_isoc(dev);
+		if (errCode)
+			goto err;
+
+	}
 
 	dev->users++;
 	filp->private_data = dev;
@@ -386,10 +314,8 @@
 
 	dev->state |= DEV_INITIALIZED;
 
-	video_mux(dev, 0);
-
-      err:
-	up(&dev->lock);
+err:
+	mutex_unlock(&dev->lock);
 	up_read(&em28xx_disconnect);
 	return errCode;
 }
@@ -403,14 +329,21 @@
 {
 	mutex_lock(&em28xx_sysfs_lock);
 
-	em28xx_info("V4L2 device /dev/video%d deregistered\n",
-		    dev->vdev->minor);
+	/*FIXME: I2C IR should be disconnected */
+
+	em28xx_info("V4L2 devices /dev/video%d and /dev/vbi%d deregistered\n",
+				dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN,
+				dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN);
 	list_del(&dev->devlist);
 	video_unregister_device(dev->vdev);
-/*	video_unregister_device(dev->vbi_dev); */
+	video_unregister_device(dev->vbi_dev);
 	em28xx_i2c_unregister(dev);
 	usb_put_dev(dev->udev);
 	mutex_unlock(&em28xx_sysfs_lock);
+
+
+	/* Mark device as unused */
+	em28xx_devused&=~(1<<dev->devno);
 }
 
 /*
@@ -424,7 +357,7 @@
 
 	em28xx_videodbg("users=%d\n", dev->users);
 
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 
 	em28xx_uninit_isoc(dev);
 
@@ -433,7 +366,7 @@
 	/* the device is already disconnect, free the remaining resources */
 	if (dev->state & DEV_DISCONNECTED) {
 		em28xx_release_resources(dev);
-		up(&dev->lock);
+		mutex_unlock(&dev->lock);
 		kfree(dev);
 		return 0;
 	}
@@ -449,7 +382,7 @@
 
 	dev->users--;
 	wake_up_interruptible_nr(&dev->open, 1);
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 	return 0;
 }
 
@@ -466,32 +399,54 @@
 	int ret = 0;
 	struct em28xx *dev = filp->private_data;
 
-	if (down_interruptible(&dev->fileop_lock))
+	if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		em28xx_videodbg("V4l2_Buf_type_videocapture is set\n");
+	}
+	if (dev->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+		em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n");
+		em28xx_videodbg("not supported yet! ...\n");
+		if (copy_to_user(buf, "", 1)) {
+			mutex_unlock(&dev->fileop_lock);
+			return -EFAULT;
+		}
+		return (1);
+	}
+	if (dev->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
+		em28xx_videodbg("V4L2_BUF_TYPE_SLICED_VBI_CAPTURE is set\n");
+		em28xx_videodbg("not supported yet! ...\n");
+		if (copy_to_user(buf, "", 1)) {
+			mutex_unlock(&dev->fileop_lock);
+			return -EFAULT;
+		}
+		return (1);
+	}
+
+	if (mutex_lock_interruptible(&dev->fileop_lock))
 		return -ERESTARTSYS;
 
 	if (dev->state & DEV_DISCONNECTED) {
 		em28xx_videodbg("device not present\n");
-		up(&dev->fileop_lock);
+		mutex_unlock(&dev->fileop_lock);
 		return -ENODEV;
 	}
 
 	if (dev->state & DEV_MISCONFIGURED) {
 		em28xx_videodbg("device misconfigured; close and open it again\n");
-		up(&dev->fileop_lock);
+		mutex_unlock(&dev->fileop_lock);
 		return -EIO;
 	}
 
 	if (dev->io == IO_MMAP) {
 		em28xx_videodbg ("IO method is set to mmap; close and open"
 				" the device again to choose the read method\n");
-		up(&dev->fileop_lock);
+		mutex_unlock(&dev->fileop_lock);
 		return -EINVAL;
 	}
 
 	if (dev->io == IO_NONE) {
 		if (!em28xx_request_buffers(dev, EM28XX_NUM_READ_FRAMES)) {
 			em28xx_errdev("read failed, not enough memory\n");
-			up(&dev->fileop_lock);
+			mutex_unlock(&dev->fileop_lock);
 			return -ENOMEM;
 		}
 		dev->io = IO_READ;
@@ -500,13 +455,13 @@
 	}
 
 	if (!count) {
-		up(&dev->fileop_lock);
+		mutex_unlock(&dev->fileop_lock);
 		return 0;
 	}
 
 	if (list_empty(&dev->outqueue)) {
 		if (filp->f_flags & O_NONBLOCK) {
-			up(&dev->fileop_lock);
+			mutex_unlock(&dev->fileop_lock);
 			return -EAGAIN;
 		}
 		ret = wait_event_interruptible
@@ -514,11 +469,11 @@
 		     (!list_empty(&dev->outqueue)) ||
 		     (dev->state & DEV_DISCONNECTED));
 		if (ret) {
-			up(&dev->fileop_lock);
+			mutex_unlock(&dev->fileop_lock);
 			return ret;
 		}
 		if (dev->state & DEV_DISCONNECTED) {
-			up(&dev->fileop_lock);
+			mutex_unlock(&dev->fileop_lock);
 			return -ENODEV;
 		}
 	}
@@ -537,12 +492,12 @@
 		count = f->buf.length;
 
 	if (copy_to_user(buf, f->bufmem, count)) {
-		up(&dev->fileop_lock);
+		mutex_unlock(&dev->fileop_lock);
 		return -EFAULT;
 	}
 	*f_pos += count;
 
-	up(&dev->fileop_lock);
+	mutex_unlock(&dev->fileop_lock);
 
 	return count;
 }
@@ -556,7 +511,7 @@
 	unsigned int mask = 0;
 	struct em28xx *dev = filp->private_data;
 
-	if (down_interruptible(&dev->fileop_lock))
+	if (mutex_lock_interruptible(&dev->fileop_lock))
 		return POLLERR;
 
 	if (dev->state & DEV_DISCONNECTED) {
@@ -582,13 +537,13 @@
 			if (!list_empty(&dev->outqueue))
 				mask |= POLLIN | POLLRDNORM;
 
-			up(&dev->fileop_lock);
+			mutex_unlock(&dev->fileop_lock);
 
 			return mask;
 		}
 	}
 
-	up(&dev->fileop_lock);
+	mutex_unlock(&dev->fileop_lock);
 	return POLLERR;
 }
 
@@ -628,25 +583,25 @@
 
 	struct em28xx *dev = filp->private_data;
 
-	if (down_interruptible(&dev->fileop_lock))
+	if (mutex_lock_interruptible(&dev->fileop_lock))
 		return -ERESTARTSYS;
 
 	if (dev->state & DEV_DISCONNECTED) {
 		em28xx_videodbg("mmap: device not present\n");
-		up(&dev->fileop_lock);
+		mutex_unlock(&dev->fileop_lock);
 		return -ENODEV;
 	}
 
 	if (dev->state & DEV_MISCONFIGURED) {
 		em28xx_videodbg ("mmap: Device is misconfigured; close and "
 						"open it again\n");
-		up(&dev->fileop_lock);
+		mutex_unlock(&dev->fileop_lock);
 		return -EIO;
 	}
 
 	if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
 	    size != PAGE_ALIGN(dev->frame[0].buf.length)) {
-		up(&dev->fileop_lock);
+		mutex_unlock(&dev->fileop_lock);
 		return -EINVAL;
 	}
 
@@ -656,7 +611,7 @@
 	}
 	if (i == dev->num_frames) {
 		em28xx_videodbg("mmap: user supplied mapping address is out of range\n");
-		up(&dev->fileop_lock);
+		mutex_unlock(&dev->fileop_lock);
 		return -EINVAL;
 	}
 
@@ -668,7 +623,7 @@
 	while (size > 0) {	/* size is page-aligned */
 		if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
 			em28xx_videodbg("mmap: vm_insert_page failed\n");
-			up(&dev->fileop_lock);
+			mutex_unlock(&dev->fileop_lock);
 			return -EAGAIN;
 		}
 		start += PAGE_SIZE;
@@ -680,7 +635,7 @@
 	vma->vm_private_data = &dev->frame[i];
 
 	em28xx_vm_open(vma);
-	up(&dev->fileop_lock);
+	mutex_unlock(&dev->fileop_lock);
 	return 0;
 }
 
@@ -702,43 +657,6 @@
 	}
 }
 
-/*FIXME: should be moved to saa711x */
-static int saa711x_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
-{
-	s32 tmp;
-	switch (ctrl->id) {
-	case V4L2_CID_BRIGHTNESS:
-		if ((tmp = em28xx_brightness_get(dev)) < 0)
-			return -EIO;
-		ctrl->value = (s32) ((s8) tmp);	/* FIXME: clenaer way to extend sign? */
-		return 0;
-	case V4L2_CID_CONTRAST:
-		if ((ctrl->value = em28xx_contrast_get(dev)) < 0)
-			return -EIO;
-		return 0;
-	case V4L2_CID_SATURATION:
-		if ((ctrl->value = em28xx_saturation_get(dev)) < 0)
-			return -EIO;
-		return 0;
-	case V4L2_CID_RED_BALANCE:
-		if ((tmp = em28xx_v_balance_get(dev)) < 0)
-			return -EIO;
-		ctrl->value = (s32) ((s8) tmp);	/* FIXME: clenaer way to extend sign? */
-		return 0;
-	case V4L2_CID_BLUE_BALANCE:
-		if ((tmp = em28xx_u_balance_get(dev)) < 0)
-			return -EIO;
-		ctrl->value = (s32) ((s8) tmp);	/* FIXME: clenaer way to extend sign? */
-		return 0;
-	case V4L2_CID_GAMMA:
-		if ((ctrl->value = em28xx_gamma_get(dev)) < 0)
-			return -EIO;
-		return 0;
-	default:
-		return -EINVAL;
-	}
-}
-
 /*
  * em28xx_set_ctrl()
  * mute or set new saturation, brightness or contrast
@@ -761,27 +679,6 @@
 	}
 }
 
-/*FIXME: should be moved to saa711x */
-static int saa711x_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
-{
-	switch (ctrl->id) {
-	case V4L2_CID_BRIGHTNESS:
-		return em28xx_brightness_set(dev, ctrl->value);
-	case V4L2_CID_CONTRAST:
-		return em28xx_contrast_set(dev, ctrl->value);
-	case V4L2_CID_SATURATION:
-		return em28xx_saturation_set(dev, ctrl->value);
-	case V4L2_CID_RED_BALANCE:
-		return em28xx_v_balance_set(dev, ctrl->value);
-	case V4L2_CID_BLUE_BALANCE:
-		return em28xx_u_balance_set(dev, ctrl->value);
-	case V4L2_CID_GAMMA:
-		return em28xx_gamma_set(dev, ctrl->value);
-	default:
-		return -EINVAL;
-	}
-}
-
 /*
  * em28xx_stream_interrupt()
  * stops streaming
@@ -802,7 +699,8 @@
 	else if (ret) {
 		dev->state |= DEV_MISCONFIGURED;
 		em28xx_videodbg("device is misconfigured; close and "
-			"open /dev/video%d again\n", dev->vdev->minor);
+			"open /dev/video%d again\n",
+				dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN);
 		return ret;
 	}
 
@@ -853,6 +751,181 @@
 	return 0;
 }
 
+static int em28xx_get_fmt(struct em28xx *dev, struct v4l2_format *format)
+{
+	em28xx_videodbg("VIDIOC_G_FMT: type=%s\n",
+		(format->type ==V4L2_BUF_TYPE_VIDEO_CAPTURE) ?
+		"V4L2_BUF_TYPE_VIDEO_CAPTURE" :
+		(format->type ==V4L2_BUF_TYPE_VBI_CAPTURE) ?
+		"V4L2_BUF_TYPE_VBI_CAPTURE" :
+		(format->type ==V4L2_CAP_SLICED_VBI_CAPTURE) ?
+		"V4L2_BUF_TYPE_SLICED_VBI_CAPTURE " :
+		"not supported");
+
+	switch (format->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+	{
+		format->fmt.pix.width = dev->width;
+		format->fmt.pix.height = dev->height;
+		format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+		format->fmt.pix.bytesperline = dev->bytesperline;
+		format->fmt.pix.sizeimage = dev->frame_size;
+		format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+		format->fmt.pix.field = dev->interlaced ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;	/* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
+
+		em28xx_videodbg("VIDIOC_G_FMT: %dx%d\n", dev->width,
+			dev->height);
+		break;
+	}
+
+	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+	{
+		format->fmt.sliced.service_set=0;
+
+		em28xx_i2c_call_clients(dev,VIDIOC_G_FMT,format);
+
+		if (format->fmt.sliced.service_set==0)
+			return -EINVAL;
+
+		break;
+	}
+
+	default:
+		return -EINVAL;
+	}
+	return (0);
+}
+
+static int em28xx_set_fmt(struct em28xx *dev, unsigned int cmd, struct v4l2_format *format)
+{
+	u32 i;
+	int ret = 0;
+	int width = format->fmt.pix.width;
+	int height = format->fmt.pix.height;
+	unsigned int hscale, vscale;
+	unsigned int maxh, maxw;
+
+	maxw = norm_maxw(dev);
+	maxh = norm_maxh(dev);
+
+	em28xx_videodbg("%s: type=%s\n",
+			cmd == VIDIOC_TRY_FMT ?
+			"VIDIOC_TRY_FMT" : "VIDIOC_S_FMT",
+			format->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
+			"V4L2_BUF_TYPE_VIDEO_CAPTURE" :
+			format->type == V4L2_BUF_TYPE_VBI_CAPTURE ?
+			"V4L2_BUF_TYPE_VBI_CAPTURE " :
+			"not supported");
+
+	if (format->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
+		em28xx_i2c_call_clients(dev,VIDIOC_G_FMT,format);
+
+		if (format->fmt.sliced.service_set==0)
+			return -EINVAL;
+
+		return 0;
+	}
+
+
+	if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	em28xx_videodbg("%s: requested %dx%d\n",
+		cmd == VIDIOC_TRY_FMT ?
+		"VIDIOC_TRY_FMT" : "VIDIOC_S_FMT",
+		format->fmt.pix.width, format->fmt.pix.height);
+
+	/* FIXME: Move some code away from here */
+	/* width must even because of the YUYV format */
+	/* height must be even because of interlacing */
+	height &= 0xfffe;
+	width &= 0xfffe;
+
+	if (height < 32)
+		height = 32;
+	if (height > maxh)
+		height = maxh;
+	if (width < 48)
+		width = 48;
+	if (width > maxw)
+		width = maxw;
+
+	if(dev->is_em2800){
+		/* the em2800 can only scale down to 50% */
+		if(height % (maxh / 2))
+			height=maxh;
+		if(width % (maxw / 2))
+			width=maxw;
+		/* according to empiatech support */
+		/* the MaxPacketSize is to small to support */
+		/* framesizes larger than 640x480 @ 30 fps */
+		/* or 640x576 @ 25 fps. As this would cut */
+		/* of a part of the image we prefer */
+		/* 360x576 or 360x480 for now */
+		if(width == maxw && height == maxh)
+			width /= 2;
+	}
+
+	if ((hscale = (((unsigned long)maxw) << 12) / width - 4096L) >= 0x4000)
+		hscale = 0x3fff;
+
+	width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
+
+	if ((vscale = (((unsigned long)maxh) << 12) / height - 4096L) >= 0x4000)
+		vscale = 0x3fff;
+
+	height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
+
+	format->fmt.pix.width = width;
+	format->fmt.pix.height = height;
+	format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+	format->fmt.pix.bytesperline = width * 2;
+	format->fmt.pix.sizeimage = width * 2 * height;
+	format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+	format->fmt.pix.field = V4L2_FIELD_INTERLACED;
+
+	em28xx_videodbg("%s: returned %dx%d (%d, %d)\n",
+		cmd == VIDIOC_TRY_FMT ?
+		"VIDIOC_TRY_FMT" :"VIDIOC_S_FMT",
+		format->fmt.pix.width, format->fmt.pix.height, hscale, vscale);
+
+	if (cmd == VIDIOC_TRY_FMT)
+		return 0;
+
+	for (i = 0; i < dev->num_frames; i++)
+		if (dev->frame[i].vma_use_count) {
+			em28xx_videodbg("VIDIOC_S_FMT failed. "
+				"Unmap the buffers first.\n");
+			return -EINVAL;
+		}
+
+	/* stop io in case it is already in progress */
+	if (dev->stream == STREAM_ON) {
+		em28xx_videodbg("VIDIOC_SET_FMT: interupting stream\n");
+		if ((ret = em28xx_stream_interrupt(dev)))
+			return ret;
+	}
+
+	em28xx_release_buffers(dev);
+	dev->io = IO_NONE;
+
+	/* set new image size */
+	dev->width = width;
+	dev->height = height;
+	dev->frame_size = dev->width * dev->height * 2;
+	dev->field_size = dev->frame_size >> 1;
+	dev->bytesperline = dev->width * 2;
+	dev->hscale = hscale;
+	dev->vscale = vscale;
+	em28xx_uninit_isoc(dev);
+	em28xx_set_alternate(dev);
+	em28xx_capture_start(dev, 1);
+	em28xx_resolution_set(dev);
+	em28xx_init_isoc(dev);
+
+	return 0;
+}
+
 /*
  * em28xx_v4l2_do_ioctl()
  * This function is _not_ called directly, but from
@@ -868,392 +941,325 @@
 	switch (cmd) {
 		/* ---------- tv norms ---------- */
 	case VIDIOC_ENUMSTD:
-		{
-			struct v4l2_standard *e = arg;
-			unsigned int i;
+	{
+		struct v4l2_standard *e = arg;
+		unsigned int i;
 
-			i = e->index;
-			if (i >= TVNORMS)
-				return -EINVAL;
-			ret = v4l2_video_std_construct(e, tvnorms[e->index].id,
-						       tvnorms[e->index].name);
-			e->index = i;
-			if (ret < 0)
-				return ret;
-			return 0;
-		}
+		i = e->index;
+		if (i >= TVNORMS)
+			return -EINVAL;
+		ret = v4l2_video_std_construct(e, tvnorms[e->index].id,
+						tvnorms[e->index].name);
+		e->index = i;
+		if (ret < 0)
+			return ret;
+		return 0;
+	}
 	case VIDIOC_G_STD:
-		{
-			v4l2_std_id *id = arg;
+	{
+		v4l2_std_id *id = arg;
 
-			*id = dev->tvnorm->id;
-			return 0;
-		}
+		*id = dev->tvnorm->id;
+		return 0;
+	}
 	case VIDIOC_S_STD:
-		{
-			v4l2_std_id *id = arg;
-			unsigned int i;
+	{
+		v4l2_std_id *id = arg;
+		unsigned int i;
 
+		for (i = 0; i < TVNORMS; i++)
+			if (*id == tvnorms[i].id)
+				break;
+		if (i == TVNORMS)
 			for (i = 0; i < TVNORMS; i++)
-				if (*id == tvnorms[i].id)
+				if (*id & tvnorms[i].id)
 					break;
-			if (i == TVNORMS)
-				for (i = 0; i < TVNORMS; i++)
-					if (*id & tvnorms[i].id)
-						break;
-			if (i == TVNORMS)
-				return -EINVAL;
+		if (i == TVNORMS)
+			return -EINVAL;
 
-			down(&dev->lock);
-			dev->tvnorm = &tvnorms[i];
+		mutex_lock(&dev->lock);
+		dev->tvnorm = &tvnorms[i];
 
-			em28xx_set_norm(dev, dev->width, dev->height);
+		em28xx_set_norm(dev, dev->width, dev->height);
 
-/*
-		dev->width=norm_maxw(dev);
-		dev->height=norm_maxh(dev);
-		dev->frame_size=dev->width*dev->height*2;
-		dev->field_size=dev->frame_size>>1;
-		dev->bytesperline=dev->width*2;
-		dev->hscale=0;
-		dev->vscale=0;
+		em28xx_i2c_call_clients(dev, VIDIOC_S_STD,
+					&dev->tvnorm->id);
 
-		em28xx_resolution_set(dev);
-*/
-/*
-		em28xx_uninit_isoc(dev);
-		em28xx_set_alternate(dev);
-		em28xx_capture_start(dev, 1);
-		em28xx_resolution_set(dev);
-		em28xx_init_isoc(dev);
-*/
-			em28xx_i2c_call_clients(dev, DECODER_SET_NORM,
-						&tvnorms[i].mode);
-			em28xx_i2c_call_clients(dev, VIDIOC_S_STD,
-						&dev->tvnorm->id);
+		mutex_unlock(&dev->lock);
 
-			up(&dev->lock);
+		return 0;
+	}
 
-			return 0;
-		}
-
-		/* ------ input switching ---------- */
+	/* ------ input switching ---------- */
 	case VIDIOC_ENUMINPUT:
-		{
-			struct v4l2_input *i = arg;
-			unsigned int n;
-			static const char *iname[] = {
-				[EM28XX_VMUX_COMPOSITE1] = "Composite1",
-				[EM28XX_VMUX_COMPOSITE2] = "Composite2",
-				[EM28XX_VMUX_COMPOSITE3] = "Composite3",
-				[EM28XX_VMUX_COMPOSITE4] = "Composite4",
-				[EM28XX_VMUX_SVIDEO] = "S-Video",
-				[EM28XX_VMUX_TELEVISION] = "Television",
-				[EM28XX_VMUX_CABLE] = "Cable TV",
-				[EM28XX_VMUX_DVB] = "DVB",
-				[EM28XX_VMUX_DEBUG] = "for debug only",
-			};
+	{
+		struct v4l2_input *i = arg;
+		unsigned int n;
+		static const char *iname[] = {
+			[EM28XX_VMUX_COMPOSITE1] = "Composite1",
+			[EM28XX_VMUX_COMPOSITE2] = "Composite2",
+			[EM28XX_VMUX_COMPOSITE3] = "Composite3",
+			[EM28XX_VMUX_COMPOSITE4] = "Composite4",
+			[EM28XX_VMUX_SVIDEO] = "S-Video",
+			[EM28XX_VMUX_TELEVISION] = "Television",
+			[EM28XX_VMUX_CABLE] = "Cable TV",
+			[EM28XX_VMUX_DVB] = "DVB",
+			[EM28XX_VMUX_DEBUG] = "for debug only",
+		};
 
-			n = i->index;
-			if (n >= MAX_EM28XX_INPUT)
-				return -EINVAL;
-			if (0 == INPUT(n)->type)
-				return -EINVAL;
-			memset(i, 0, sizeof(*i));
-			i->index = n;
-			i->type = V4L2_INPUT_TYPE_CAMERA;
-			strcpy(i->name, iname[INPUT(n)->type]);
-			if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) ||
-			    (EM28XX_VMUX_CABLE == INPUT(n)->type))
-				i->type = V4L2_INPUT_TYPE_TUNER;
-			for (n = 0; n < ARRAY_SIZE(tvnorms); n++)
-				i->std |= tvnorms[n].id;
-			return 0;
-		}
-
+		n = i->index;
+		if (n >= MAX_EM28XX_INPUT)
+			return -EINVAL;
+		if (0 == INPUT(n)->type)
+			return -EINVAL;
+		memset(i, 0, sizeof(*i));
+		i->index = n;
+		i->type = V4L2_INPUT_TYPE_CAMERA;
+		strcpy(i->name, iname[INPUT(n)->type]);
+		if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) ||
+			(EM28XX_VMUX_CABLE == INPUT(n)->type))
+			i->type = V4L2_INPUT_TYPE_TUNER;
+		for (n = 0; n < ARRAY_SIZE(tvnorms); n++)
+			i->std |= tvnorms[n].id;
+		return 0;
+	}
 	case VIDIOC_G_INPUT:
-		{
-			int *i = arg;
-			*i = dev->ctl_input;
+	{
+		int *i = arg;
+		*i = dev->ctl_input;
 
-			return 0;
-		}
-
+		return 0;
+	}
 	case VIDIOC_S_INPUT:
-		{
-			int *index = arg;
+	{
+		int *index = arg;
 
-			if (*index >= MAX_EM28XX_INPUT)
-				return -EINVAL;
-			if (0 == INPUT(*index)->type)
-				return -EINVAL;
+		if (*index >= MAX_EM28XX_INPUT)
+			return -EINVAL;
+		if (0 == INPUT(*index)->type)
+			return -EINVAL;
 
-			down(&dev->lock);
-			video_mux(dev, *index);
-			up(&dev->lock);
+		mutex_lock(&dev->lock);
+		video_mux(dev, *index);
+		mutex_unlock(&dev->lock);
 
-			return 0;
-		}
-
+		return 0;
+	}
 	case VIDIOC_G_AUDIO:
-		{
-			struct v4l2_audio *a = arg;
-			unsigned int index = a->index;
+	{
+		struct v4l2_audio *a = arg;
+		unsigned int index = a->index;
 
-			if (a->index > 1)
-				return -EINVAL;
-			memset(a, 0, sizeof(*a));
-			index = dev->ctl_ainput;
+		if (a->index > 1)
+			return -EINVAL;
+		memset(a, 0, sizeof(*a));
+		index = dev->ctl_ainput;
 
-			if (index == 0) {
-				strcpy(a->name, "Television");
-			} else {
-				strcpy(a->name, "Line In");
-			}
-			a->capability = V4L2_AUDCAP_STEREO;
-			a->index = index;
-			return 0;
+		if (index == 0) {
+			strcpy(a->name, "Television");
+		} else {
+			strcpy(a->name, "Line In");
 		}
-
+		a->capability = V4L2_AUDCAP_STEREO;
+		a->index = index;
+		return 0;
+	}
 	case VIDIOC_S_AUDIO:
-		{
-			struct v4l2_audio *a = arg;
-			if (a->index != dev->ctl_ainput)
-				return -EINVAL;
+	{
+		struct v4l2_audio *a = arg;
 
-			return 0;
-		}
+		if (a->index != dev->ctl_ainput)
+			return -EINVAL;
 
-		/* --- controls ---------------------------------------------- */
+		return 0;
+	}
+
+	/* --- controls ---------------------------------------------- */
 	case VIDIOC_QUERYCTRL:
-		{
-			struct v4l2_queryctrl *qc = arg;
-			int i, id=qc->id;
+	{
+		struct v4l2_queryctrl *qc = arg;
+		int i, id=qc->id;
 
-			memset(qc,0,sizeof(*qc));
-			qc->id=id;
+		memset(qc,0,sizeof(*qc));
+		qc->id=id;
 
-			if (!dev->has_msp34xx) {
-				for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
-					if (qc->id && qc->id == em28xx_qctrl[i].id) {
-						memcpy(qc, &(em28xx_qctrl[i]),
-						sizeof(*qc));
-						return 0;
-					}
-				}
-			}
-			if (dev->decoder == EM28XX_TVP5150) {
-				em28xx_i2c_call_clients(dev,cmd,qc);
-				if (qc->type)
-					return 0;
-				else
-					return -EINVAL;
-			}
-			for (i = 0; i < ARRAY_SIZE(saa711x_qctrl); i++) {
-				if (qc->id && qc->id == saa711x_qctrl[i].id) {
-					memcpy(qc, &(saa711x_qctrl[i]),
-					       sizeof(*qc));
+		if (!dev->has_msp34xx) {
+			for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
+				if (qc->id && qc->id == em28xx_qctrl[i].id) {
+					memcpy(qc, &(em28xx_qctrl[i]),
+					sizeof(*qc));
 					return 0;
 				}
 			}
-
-			return -EINVAL;
 		}
-
+		em28xx_i2c_call_clients(dev,cmd,qc);
+		if (qc->type)
+			return 0;
+		else
+			return -EINVAL;
+	}
 	case VIDIOC_G_CTRL:
-		{
-			struct v4l2_control *ctrl = arg;
-			int retval=-EINVAL;
+	{
+		struct v4l2_control *ctrl = arg;
+		int retval=-EINVAL;
 
-			if (!dev->has_msp34xx)
-				retval=em28xx_get_ctrl(dev, ctrl);
-			if (retval==-EINVAL) {
-				if (dev->decoder == EM28XX_TVP5150) {
-					em28xx_i2c_call_clients(dev,cmd,arg);
-					return 0;
-				}
-
-				return saa711x_get_ctrl(dev, ctrl);
-			} else return retval;
-		}
-
+		if (!dev->has_msp34xx)
+			retval=em28xx_get_ctrl(dev, ctrl);
+		if (retval==-EINVAL) {
+			em28xx_i2c_call_clients(dev,cmd,arg);
+			return 0;
+		} else return retval;
+	}
 	case VIDIOC_S_CTRL:
-		{
-			struct v4l2_control *ctrl = arg;
-			u8 i;
+	{
+		struct v4l2_control *ctrl = arg;
+		u8 i;
 
-			if (!dev->has_msp34xx){
-				for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
-					if (ctrl->id == em28xx_qctrl[i].id) {
-						if (ctrl->value <
-						em28xx_qctrl[i].minimum
-						|| ctrl->value >
-						em28xx_qctrl[i].maximum)
-							return -ERANGE;
-						return em28xx_set_ctrl(dev, ctrl);
-					}
+		if (!dev->has_msp34xx){
+			for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
+				if (ctrl->id == em28xx_qctrl[i].id) {
+					if (ctrl->value <
+					em28xx_qctrl[i].minimum
+					|| ctrl->value >
+					em28xx_qctrl[i].maximum)
+						return -ERANGE;
+					return em28xx_set_ctrl(dev, ctrl);
 				}
 			}
-
-			if (dev->decoder == EM28XX_TVP5150) {
-				em28xx_i2c_call_clients(dev,cmd,arg);
-				return 0;
-			} else if (!dev->has_msp34xx) {
-				for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
-					if (ctrl->id == em28xx_qctrl[i].id) {
-						if (ctrl->value <
-						em28xx_qctrl[i].minimum
-						|| ctrl->value >
-						em28xx_qctrl[i].maximum)
-							return -ERANGE;
-						return em28xx_set_ctrl(dev, ctrl);
-					}
-				}
-				for (i = 0; i < ARRAY_SIZE(saa711x_qctrl); i++) {
-					if (ctrl->id == saa711x_qctrl[i].id) {
-						if (ctrl->value <
-						saa711x_qctrl[i].minimum
-						|| ctrl->value >
-						saa711x_qctrl[i].maximum)
-							return -ERANGE;
-						return saa711x_set_ctrl(dev, ctrl);
-					}
-				}
-			}
-
-			return -EINVAL;
 		}
 
-		/* --- tuner ioctls ------------------------------------------ */
+		em28xx_i2c_call_clients(dev,cmd,arg);
+		return 0;
+	}
+	/* --- tuner ioctls ------------------------------------------ */
 	case VIDIOC_G_TUNER:
-		{
-			struct v4l2_tuner *t = arg;
-			int status = 0;
+	{
+		struct v4l2_tuner *t = arg;
+		int status = 0;
 
-			if (0 != t->index)
-				return -EINVAL;
+		if (0 != t->index)
+			return -EINVAL;
 
-			memset(t, 0, sizeof(*t));
-			strcpy(t->name, "Tuner");
-			t->type = V4L2_TUNER_ANALOG_TV;
-			t->capability = V4L2_TUNER_CAP_NORM;
-			t->rangehigh = 0xffffffffUL;	/* FIXME: set correct range */
+		memset(t, 0, sizeof(*t));
+		strcpy(t->name, "Tuner");
+		t->type = V4L2_TUNER_ANALOG_TV;
+		t->capability = V4L2_TUNER_CAP_NORM;
+		t->rangehigh = 0xffffffffUL;	/* FIXME: set correct range */
 /*		t->signal = 0xffff;*/
 /*		em28xx_i2c_call_clients(dev,VIDIOC_G_TUNER,t);*/
-			/* No way to get signal strength? */
-			down(&dev->lock);
-			em28xx_i2c_call_clients(dev, DECODER_GET_STATUS,
-						&status);
-			up(&dev->lock);
-			t->signal =
-			    (status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0;
+		/* No way to get signal strength? */
+		mutex_lock(&dev->lock);
+		em28xx_i2c_call_clients(dev, DECODER_GET_STATUS,
+					&status);
+		mutex_unlock(&dev->lock);
+		t->signal =
+			(status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0;
 
-			em28xx_videodbg("VIDIO_G_TUNER: signal=%x, afc=%x\n", t->signal,
-				 t->afc);
-			return 0;
-		}
+		em28xx_videodbg("VIDIO_G_TUNER: signal=%x, afc=%x\n", t->signal,
+				t->afc);
+		return 0;
+	}
 	case VIDIOC_S_TUNER:
-		{
-			struct v4l2_tuner *t = arg;
-			int status = 0;
+	{
+		struct v4l2_tuner *t = arg;
+		int status = 0;
 
-			if (0 != t->index)
-				return -EINVAL;
-			memset(t, 0, sizeof(*t));
-			strcpy(t->name, "Tuner");
-			t->type = V4L2_TUNER_ANALOG_TV;
-			t->capability = V4L2_TUNER_CAP_NORM;
-			t->rangehigh = 0xffffffffUL;	/* FIXME: set correct range */
+		if (0 != t->index)
+			return -EINVAL;
+		memset(t, 0, sizeof(*t));
+		strcpy(t->name, "Tuner");
+		t->type = V4L2_TUNER_ANALOG_TV;
+		t->capability = V4L2_TUNER_CAP_NORM;
+		t->rangehigh = 0xffffffffUL;	/* FIXME: set correct range */
 /*		t->signal = 0xffff; */
-			/* No way to get signal strength? */
-			down(&dev->lock);
-			em28xx_i2c_call_clients(dev, DECODER_GET_STATUS,
-						&status);
-			up(&dev->lock);
-			t->signal =
-			    (status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0;
+		/* No way to get signal strength? */
+		mutex_lock(&dev->lock);
+		em28xx_i2c_call_clients(dev, DECODER_GET_STATUS,
+					&status);
+		mutex_unlock(&dev->lock);
+		t->signal =
+			(status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0;
 
-			em28xx_videodbg("VIDIO_S_TUNER: signal=%x, afc=%x\n",
-				 t->signal, t->afc);
-			return 0;
-		}
+		em28xx_videodbg("VIDIO_S_TUNER: signal=%x, afc=%x\n",
+				t->signal, t->afc);
+		return 0;
+	}
 	case VIDIOC_G_FREQUENCY:
-		{
-			struct v4l2_frequency *f = arg;
+	{
+		struct v4l2_frequency *f = arg;
 
-			memset(f, 0, sizeof(*f));
-			f->type = V4L2_TUNER_ANALOG_TV;
-			f->frequency = dev->ctl_freq;
+		memset(f, 0, sizeof(*f));
+		f->type = V4L2_TUNER_ANALOG_TV;
+		f->frequency = dev->ctl_freq;
 
-			return 0;
-		}
+		return 0;
+	}
 	case VIDIOC_S_FREQUENCY:
-		{
-			struct v4l2_frequency *f = arg;
+	{
+		struct v4l2_frequency *f = arg;
 
-			if (0 != f->tuner)
-				return -EINVAL;
+		if (0 != f->tuner)
+			return -EINVAL;
 
-			if (V4L2_TUNER_ANALOG_TV != f->type)
-				return -EINVAL;
+		if (V4L2_TUNER_ANALOG_TV != f->type)
+			return -EINVAL;
 
-			down(&dev->lock);
-			dev->ctl_freq = f->frequency;
-			em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f);
-			up(&dev->lock);
-			return 0;
-		}
-
+		mutex_lock(&dev->lock);
+		dev->ctl_freq = f->frequency;
+		em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f);
+		mutex_unlock(&dev->lock);
+		return 0;
+	}
 	case VIDIOC_CROPCAP:
-		{
-			struct v4l2_cropcap *cc = arg;
+	{
+		struct v4l2_cropcap *cc = arg;
 
-			if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-				return -EINVAL;
-			cc->bounds.left = 0;
-			cc->bounds.top = 0;
-			cc->bounds.width = dev->width;
-			cc->bounds.height = dev->height;
-			cc->defrect = cc->bounds;
-			cc->pixelaspect.numerator = 54;	/* 4:3 FIXME: remove magic numbers */
-			cc->pixelaspect.denominator = 59;
-			return 0;
-		}
+		if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			return -EINVAL;
+		cc->bounds.left = 0;
+		cc->bounds.top = 0;
+		cc->bounds.width = dev->width;
+		cc->bounds.height = dev->height;
+		cc->defrect = cc->bounds;
+		cc->pixelaspect.numerator = 54;	/* 4:3 FIXME: remove magic numbers */
+		cc->pixelaspect.denominator = 59;
+		return 0;
+	}
 	case VIDIOC_STREAMON:
-		{
-			int *type = arg;
+	{
+		int *type = arg;
 
-			if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE
-			    || dev->io != IO_MMAP)
-				return -EINVAL;
+		if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE
+			|| dev->io != IO_MMAP)
+			return -EINVAL;
 
-			if (list_empty(&dev->inqueue))
-				return -EINVAL;
+		if (list_empty(&dev->inqueue))
+			return -EINVAL;
 
-			dev->stream = STREAM_ON;	/* FIXME: Start video capture here? */
+		dev->stream = STREAM_ON;	/* FIXME: Start video capture here? */
 
-			em28xx_videodbg("VIDIOC_STREAMON: starting stream\n");
+		em28xx_videodbg("VIDIOC_STREAMON: starting stream\n");
 
-			return 0;
-		}
+		return 0;
+	}
 	case VIDIOC_STREAMOFF:
-		{
-			int *type = arg;
-			int ret;
+	{
+		int *type = arg;
+		int ret;
 
-			if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE
-			    || dev->io != IO_MMAP)
-				return -EINVAL;
+		if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE
+			|| dev->io != IO_MMAP)
+			return -EINVAL;
 
-			if (dev->stream == STREAM_ON) {
-				em28xx_videodbg ("VIDIOC_STREAMOFF: interrupting stream\n");
-				if ((ret = em28xx_stream_interrupt(dev)))
-					return ret;
-			}
-			em28xx_empty_framequeues(dev);
-
-			return 0;
+		if (dev->stream == STREAM_ON) {
+			em28xx_videodbg ("VIDIOC_STREAMOFF: interrupting stream\n");
+			if ((ret = em28xx_stream_interrupt(dev)))
+				return ret;
 		}
+		em28xx_empty_framequeues(dev);
+
+		return 0;
+	}
 	default:
 		return v4l_compat_translate_ioctl(inode, filp, cmd, arg,
 						  driver_ioctl);
@@ -1283,327 +1289,170 @@
 		/* --- capabilities ------------------------------------------ */
 	case VIDIOC_QUERYCAP:
 		{
-			struct v4l2_capability *cap = arg;
+		struct v4l2_capability *cap = arg;
 
-			memset(cap, 0, sizeof(*cap));
-			strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
-			strlcpy(cap->card, em28xx_boards[dev->model].name,
-				sizeof(cap->card));
-			strlcpy(cap->bus_info, dev->udev->dev.bus_id,
-				sizeof(cap->bus_info));
-			cap->version = EM28XX_VERSION_CODE;
-			cap->capabilities =
-			    V4L2_CAP_VIDEO_CAPTURE |
-			    V4L2_CAP_AUDIO |
-			    V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
-			if (dev->has_tuner)
-				cap->capabilities |= V4L2_CAP_TUNER;
-			return 0;
-		}
-
-		/* --- capture ioctls ---------------------------------------- */
+		memset(cap, 0, sizeof(*cap));
+		strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
+		strlcpy(cap->card, em28xx_boards[dev->model].name,
+			sizeof(cap->card));
+		strlcpy(cap->bus_info, dev->udev->dev.bus_id,
+			sizeof(cap->bus_info));
+		cap->version = EM28XX_VERSION_CODE;
+		cap->capabilities =
+				V4L2_CAP_SLICED_VBI_CAPTURE |
+				V4L2_CAP_VIDEO_CAPTURE |
+				V4L2_CAP_AUDIO |
+				V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+		if (dev->has_tuner)
+			cap->capabilities |= V4L2_CAP_TUNER;
+		return 0;
+	}
+	/* --- capture ioctls ---------------------------------------- */
 	case VIDIOC_ENUM_FMT:
-		{
-			struct v4l2_fmtdesc *fmtd = arg;
+	{
+		struct v4l2_fmtdesc *fmtd = arg;
 
-			if (fmtd->index != 0)
-				return -EINVAL;
-			memset(fmtd, 0, sizeof(*fmtd));
-			fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-			strcpy(fmtd->description, "Packed YUY2");
-			fmtd->pixelformat = V4L2_PIX_FMT_YUYV;
-			memset(fmtd->reserved, 0, sizeof(fmtd->reserved));
-			return 0;
-		}
-
+		if (fmtd->index != 0)
+			return -EINVAL;
+		memset(fmtd, 0, sizeof(*fmtd));
+		fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		strcpy(fmtd->description, "Packed YUY2");
+		fmtd->pixelformat = V4L2_PIX_FMT_YUYV;
+		memset(fmtd->reserved, 0, sizeof(fmtd->reserved));
+		return 0;
+	}
 	case VIDIOC_G_FMT:
-		{
-			struct v4l2_format *format = arg;
-
-			em28xx_videodbg("VIDIOC_G_FMT: type=%s\n",
-				 format->type ==
-				 V4L2_BUF_TYPE_VIDEO_CAPTURE ?
-				 "V4L2_BUF_TYPE_VIDEO_CAPTURE" : format->type ==
-				 V4L2_BUF_TYPE_VBI_CAPTURE ?
-				 "V4L2_BUF_TYPE_VBI_CAPTURE " :
-				 "not supported");
-
-			if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-				return -EINVAL;
-
-			format->fmt.pix.width = dev->width;
-			format->fmt.pix.height = dev->height;
-			format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
-			format->fmt.pix.bytesperline = dev->bytesperline;
-			format->fmt.pix.sizeimage = dev->frame_size;
-			format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-			format->fmt.pix.field = dev->interlaced ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;	/* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
-
-			em28xx_videodbg("VIDIOC_G_FMT: %dx%d\n", dev->width,
-				 dev->height);
-			return 0;
-		}
+		return em28xx_get_fmt(dev, (struct v4l2_format *) arg);
 
 	case VIDIOC_TRY_FMT:
 	case VIDIOC_S_FMT:
-		{
-			struct v4l2_format *format = arg;
-			u32 i;
-			int ret = 0;
-			int width = format->fmt.pix.width;
-			int height = format->fmt.pix.height;
-			unsigned int hscale, vscale;
-			unsigned int maxh, maxw;
+		return em28xx_set_fmt(dev, cmd, (struct v4l2_format *)arg);
 
-			maxw = norm_maxw(dev);
-			maxh = norm_maxh(dev);
-
-/*		int both_fields; */
-
-			em28xx_videodbg("%s: type=%s\n",
-				 cmd ==
-				 VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" :
-				 "VIDIOC_S_FMT",
-				 format->type ==
-				 V4L2_BUF_TYPE_VIDEO_CAPTURE ?
-				 "V4L2_BUF_TYPE_VIDEO_CAPTURE" : format->type ==
-				 V4L2_BUF_TYPE_VBI_CAPTURE ?
-				 "V4L2_BUF_TYPE_VBI_CAPTURE " :
-				 "not supported");
-
-			if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-				return -EINVAL;
-
-			em28xx_videodbg("%s: requested %dx%d\n",
-				 cmd ==
-				 VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" :
-				 "VIDIOC_S_FMT", format->fmt.pix.width,
-				 format->fmt.pix.height);
-
-			/* FIXME: Move some code away from here */
-			/* width must even because of the YUYV format */
-			/* height must be even because of interlacing */
-			height &= 0xfffe;
-			width &= 0xfffe;
-
-			if (height < 32)
-				height = 32;
-			if (height > maxh)
-				height = maxh;
-			if (width < 48)
-				width = 48;
-			if (width > maxw)
-				width = maxw;
-
-			if(dev->is_em2800){
-				/* the em2800 can only scale down to 50% */
-				if(height % (maxh / 2))
-					height=maxh;
-				if(width % (maxw / 2))
-					width=maxw;
-				/* according to empiatech support */
-				/* the MaxPacketSize is to small to support */
-				/* framesizes larger than 640x480 @ 30 fps */
-				/* or 640x576 @ 25 fps. As this would cut */
-				/* of a part of the image we prefer */
-				/* 360x576 or 360x480 for now */
-				if(width == maxw && height == maxh)
-					width /= 2;
-			}
-
-			if ((hscale =
-			     (((unsigned long)maxw) << 12) / width - 4096L) >=
-			    0x4000)
-				hscale = 0x3fff;
-			width =
-			    (((unsigned long)maxw) << 12) / (hscale + 4096L);
-
-			if ((vscale =
-			     (((unsigned long)maxh) << 12) / height - 4096L) >=
-			    0x4000)
-				vscale = 0x3fff;
-			height =
-			    (((unsigned long)maxh) << 12) / (vscale + 4096L);
-
-			format->fmt.pix.width = width;
-			format->fmt.pix.height = height;
-			format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
-			format->fmt.pix.bytesperline = width * 2;
-			format->fmt.pix.sizeimage = width * 2 * height;
-			format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-			format->fmt.pix.field = V4L2_FIELD_INTERLACED;
-
-			em28xx_videodbg("%s: returned %dx%d (%d, %d)\n",
-				 cmd ==
-				 VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" :
-				 "VIDIOC_S_FMT", format->fmt.pix.width,
-				 format->fmt.pix.height, hscale, vscale);
-
-			if (cmd == VIDIOC_TRY_FMT)
-				return 0;
-
-			for (i = 0; i < dev->num_frames; i++)
-				if (dev->frame[i].vma_use_count) {
-					em28xx_videodbg("VIDIOC_S_FMT failed. "
-						"Unmap the buffers first.\n");
-					return -EINVAL;
-				}
-
-			/* stop io in case it is already in progress */
-			if (dev->stream == STREAM_ON) {
-				em28xx_videodbg("VIDIOC_SET_FMT: interupting stream\n");
-				if ((ret = em28xx_stream_interrupt(dev)))
-					return ret;
-			}
-
-			em28xx_release_buffers(dev);
-			dev->io = IO_NONE;
-
-			/* set new image size */
-			dev->width = width;
-			dev->height = height;
-			dev->frame_size = dev->width * dev->height * 2;
-			dev->field_size = dev->frame_size >> 1;	/*both_fileds ? dev->frame_size>>1 : dev->frame_size; */
-			dev->bytesperline = dev->width * 2;
-			dev->hscale = hscale;
-			dev->vscale = vscale;
-/*			dev->both_fileds = both_fileds; */
-			em28xx_uninit_isoc(dev);
-			em28xx_set_alternate(dev);
-			em28xx_capture_start(dev, 1);
-			em28xx_resolution_set(dev);
-			em28xx_init_isoc(dev);
-
-			return 0;
-		}
-
-		/* --- streaming capture ------------------------------------- */
 	case VIDIOC_REQBUFS:
-		{
-			struct v4l2_requestbuffers *rb = arg;
-			u32 i;
-			int ret;
+	{
+		struct v4l2_requestbuffers *rb = arg;
+		u32 i;
+		int ret;
 
-			if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-			    rb->memory != V4L2_MEMORY_MMAP)
-				return -EINVAL;
+		if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+			rb->memory != V4L2_MEMORY_MMAP)
+			return -EINVAL;
 
-			if (dev->io == IO_READ) {
-				em28xx_videodbg ("method is set to read;"
-					" close and open the device again to"
-					" choose the mmap I/O method\n");
-				return -EINVAL;
-			}
-
-			for (i = 0; i < dev->num_frames; i++)
-				if (dev->frame[i].vma_use_count) {
-					em28xx_videodbg ("VIDIOC_REQBUFS failed; previous buffers are still mapped\n");
-					return -EINVAL;
-				}
-
-			if (dev->stream == STREAM_ON) {
-				em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n");
-				if ((ret = em28xx_stream_interrupt(dev)))
-					return ret;
-			}
-
-			em28xx_empty_framequeues(dev);
-
-			em28xx_release_buffers(dev);
-			if (rb->count)
-				rb->count =
-				    em28xx_request_buffers(dev, rb->count);
-
-			dev->frame_current = NULL;
-
-			em28xx_videodbg ("VIDIOC_REQBUFS: setting io method to mmap: num bufs %i\n",
-						     rb->count);
-			dev->io = rb->count ? IO_MMAP : IO_NONE;
-			return 0;
+		if (dev->io == IO_READ) {
+			em28xx_videodbg ("method is set to read;"
+				" close and open the device again to"
+				" choose the mmap I/O method\n");
+			return -EINVAL;
 		}
 
+		for (i = 0; i < dev->num_frames; i++)
+			if (dev->frame[i].vma_use_count) {
+				em28xx_videodbg ("VIDIOC_REQBUFS failed; previous buffers are still mapped\n");
+				return -EINVAL;
+			}
+
+		if (dev->stream == STREAM_ON) {
+			em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n");
+			if ((ret = em28xx_stream_interrupt(dev)))
+				return ret;
+		}
+
+		em28xx_empty_framequeues(dev);
+
+		em28xx_release_buffers(dev);
+		if (rb->count)
+			rb->count =
+				em28xx_request_buffers(dev, rb->count);
+
+		dev->frame_current = NULL;
+
+		em28xx_videodbg ("VIDIOC_REQBUFS: setting io method to mmap: num bufs %i\n",
+						rb->count);
+		dev->io = rb->count ? IO_MMAP : IO_NONE;
+		return 0;
+	}
 	case VIDIOC_QUERYBUF:
-		{
-			struct v4l2_buffer *b = arg;
+	{
+		struct v4l2_buffer *b = arg;
 
-			if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-			    b->index >= dev->num_frames || dev->io != IO_MMAP)
-				return -EINVAL;
+		if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+			b->index >= dev->num_frames || dev->io != IO_MMAP)
+			return -EINVAL;
 
-			memcpy(b, &dev->frame[b->index].buf, sizeof(*b));
+		memcpy(b, &dev->frame[b->index].buf, sizeof(*b));
 
-			if (dev->frame[b->index].vma_use_count) {
-				b->flags |= V4L2_BUF_FLAG_MAPPED;
-			}
-			if (dev->frame[b->index].state == F_DONE)
-				b->flags |= V4L2_BUF_FLAG_DONE;
-			else if (dev->frame[b->index].state != F_UNUSED)
-				b->flags |= V4L2_BUF_FLAG_QUEUED;
-			return 0;
+		if (dev->frame[b->index].vma_use_count) {
+			b->flags |= V4L2_BUF_FLAG_MAPPED;
 		}
+		if (dev->frame[b->index].state == F_DONE)
+			b->flags |= V4L2_BUF_FLAG_DONE;
+		else if (dev->frame[b->index].state != F_UNUSED)
+			b->flags |= V4L2_BUF_FLAG_QUEUED;
+		return 0;
+	}
 	case VIDIOC_QBUF:
-		{
-			struct v4l2_buffer *b = arg;
-			unsigned long lock_flags;
+	{
+		struct v4l2_buffer *b = arg;
+		unsigned long lock_flags;
 
-			if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-			    b->index >= dev->num_frames || dev->io != IO_MMAP) {
-				return -EINVAL;
-			}
-
-			if (dev->frame[b->index].state != F_UNUSED) {
-				return -EAGAIN;
-			}
-			dev->frame[b->index].state = F_QUEUED;
-
-			/* add frame to fifo */
-			spin_lock_irqsave(&dev->queue_lock, lock_flags);
-			list_add_tail(&dev->frame[b->index].frame,
-				      &dev->inqueue);
-			spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
-
-			return 0;
+		if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+			b->index >= dev->num_frames || dev->io != IO_MMAP) {
+			return -EINVAL;
 		}
+
+		if (dev->frame[b->index].state != F_UNUSED) {
+			return -EAGAIN;
+		}
+		dev->frame[b->index].state = F_QUEUED;
+
+		/* add frame to fifo */
+		spin_lock_irqsave(&dev->queue_lock, lock_flags);
+		list_add_tail(&dev->frame[b->index].frame,
+				&dev->inqueue);
+		spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+
+		return 0;
+	}
 	case VIDIOC_DQBUF:
-		{
-			struct v4l2_buffer *b = arg;
-			struct em28xx_frame_t *f;
-			unsigned long lock_flags;
-			int ret = 0;
+	{
+		struct v4l2_buffer *b = arg;
+		struct em28xx_frame_t *f;
+		unsigned long lock_flags;
+		int ret = 0;
 
-			if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE
-			    || dev->io != IO_MMAP)
+		if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE
+			|| dev->io != IO_MMAP)
+			return -EINVAL;
+
+		if (list_empty(&dev->outqueue)) {
+			if (dev->stream == STREAM_OFF)
 				return -EINVAL;
-
-			if (list_empty(&dev->outqueue)) {
-				if (dev->stream == STREAM_OFF)
-					return -EINVAL;
-				if (filp->f_flags & O_NONBLOCK)
-					return -EAGAIN;
-				ret = wait_event_interruptible
-				    (dev->wait_frame,
-				     (!list_empty(&dev->outqueue)) ||
-				     (dev->state & DEV_DISCONNECTED));
-				if (ret)
-					return ret;
-				if (dev->state & DEV_DISCONNECTED)
-					return -ENODEV;
-			}
-
-			spin_lock_irqsave(&dev->queue_lock, lock_flags);
-			f = list_entry(dev->outqueue.next,
-				       struct em28xx_frame_t, frame);
-			list_del(dev->outqueue.next);
-			spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
-
-			f->state = F_UNUSED;
-			memcpy(b, &f->buf, sizeof(*b));
-
-			if (f->vma_use_count)
-				b->flags |= V4L2_BUF_FLAG_MAPPED;
-
-			return 0;
+			if (filp->f_flags & O_NONBLOCK)
+				return -EAGAIN;
+			ret = wait_event_interruptible
+				(dev->wait_frame,
+				(!list_empty(&dev->outqueue)) ||
+				(dev->state & DEV_DISCONNECTED));
+			if (ret)
+				return ret;
+			if (dev->state & DEV_DISCONNECTED)
+				return -ENODEV;
 		}
+
+		spin_lock_irqsave(&dev->queue_lock, lock_flags);
+		f = list_entry(dev->outqueue.next,
+				struct em28xx_frame_t, frame);
+		list_del(dev->outqueue.next);
+		spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+
+		f->state = F_UNUSED;
+		memcpy(b, &f->buf, sizeof(*b));
+
+		if (f->vma_use_count)
+			b->flags |= V4L2_BUF_FLAG_MAPPED;
+
+		return 0;
+	}
 	default:
 		return em28xx_do_ioctl(inode, filp, dev, cmd, arg,
 				       em28xx_video_do_ioctl);
@@ -1621,25 +1470,25 @@
 	int ret = 0;
 	struct em28xx *dev = filp->private_data;
 
-	if (down_interruptible(&dev->fileop_lock))
+	if (mutex_lock_interruptible(&dev->fileop_lock))
 		return -ERESTARTSYS;
 
 	if (dev->state & DEV_DISCONNECTED) {
 		em28xx_errdev("v4l2 ioctl: device not present\n");
-		up(&dev->fileop_lock);
+		mutex_unlock(&dev->fileop_lock);
 		return -ENODEV;
 	}
 
 	if (dev->state & DEV_MISCONFIGURED) {
 		em28xx_errdev
 		    ("v4l2 ioctl: device is misconfigured; close and open it again\n");
-		up(&dev->fileop_lock);
+		mutex_unlock(&dev->fileop_lock);
 		return -EIO;
 	}
 
 	ret = video_usercopy(inode, filp, cmd, arg, em28xx_video_do_ioctl);
 
-	up(&dev->fileop_lock);
+	mutex_unlock(&dev->fileop_lock);
 
 	return ret;
 }
@@ -1673,7 +1522,7 @@
 
 	dev->udev = udev;
 	dev->model = model;
-	init_MUTEX(&dev->lock);
+	mutex_init(&dev->lock);
 	init_waitqueue_head(&dev->open);
 
 	dev->em28xx_write_regs = em28xx_write_regs;
@@ -1729,10 +1578,11 @@
 	dev->vpic.depth = 16;
 	dev->vpic.palette = VIDEO_PALETTE_YUV422;
 
+	em28xx_pre_card_setup(dev);
 #ifdef CONFIG_MODULES
 	/* request some modules */
 	if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114)
-		request_module("saa711x");
+		request_module("saa7115");
 	if (dev->decoder == EM28XX_TVP5150)
 		request_module("tvp5150");
 	if (dev->has_tuner)
@@ -1744,10 +1594,11 @@
 	if (errCode) {
 		em28xx_errdev("error configuring device\n");
 		kfree(dev);
+		em28xx_devused&=~(1<<dev->devno);
 		return -ENOMEM;
 	}
 
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 	/* register i2c bus */
 	em28xx_i2c_register(dev);
 
@@ -1757,7 +1608,7 @@
 	/* configure the device */
 	em28xx_config_i2c(dev);
 
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 
 	errCode = em28xx_config(dev);
 
@@ -1770,9 +1621,30 @@
 	if (NULL == dev->vdev) {
 		em28xx_errdev("cannot allocate video_device.\n");
 		kfree(dev);
+		em28xx_devused&=~(1<<dev->devno);
 		return -ENOMEM;
 	}
 
+	dev->vbi_dev = video_device_alloc();
+	if (NULL == dev->vbi_dev) {
+		em28xx_errdev("cannot allocate video_device.\n");
+		kfree(dev->vdev);
+		kfree(dev);
+		em28xx_devused&=~(1<<dev->devno);
+		return -ENOMEM;
+	}
+
+	/* Fills VBI device info */
+	dev->vbi_dev->type = VFL_TYPE_VBI;
+	dev->vbi_dev->hardware = 0;
+	dev->vbi_dev->fops = &em28xx_v4l_fops;
+	dev->vbi_dev->minor = -1;
+	dev->vbi_dev->dev = &dev->udev->dev;
+	dev->vbi_dev->release = video_device_release;
+	snprintf(dev->vbi_dev->name, sizeof(dev->vbi_dev->name), "%s#%d %s",
+							 "em28xx",dev->devno,"vbi");
+
+	/* Fills CAPTURE device info */
 	dev->vdev->type = VID_TYPE_CAPTURE;
 	if (dev->has_tuner)
 		dev->vdev->type |= VID_TYPE_TUNER;
@@ -1781,21 +1653,39 @@
 	dev->vdev->minor = -1;
 	dev->vdev->dev = &dev->udev->dev;
 	dev->vdev->release = video_device_release;
-	snprintf(dev->vdev->name, sizeof(dev->vdev->name), "%s",
-		 "em28xx video");
+	snprintf(dev->vdev->name, sizeof(dev->vbi_dev->name), "%s#%d %s",
+							 "em28xx",dev->devno,"video");
+
 	list_add_tail(&dev->devlist,&em28xx_devlist);
 
 	/* register v4l2 device */
-	down(&dev->lock);
-	if ((retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1))) {
+	mutex_lock(&dev->lock);
+	if ((retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
+					 video_nr[dev->devno]))) {
 		em28xx_errdev("unable to register video device (error=%i).\n",
 			      retval);
-		up(&dev->lock);
+		mutex_unlock(&dev->lock);
 		list_del(&dev->devlist);
 		video_device_release(dev->vdev);
 		kfree(dev);
+		em28xx_devused&=~(1<<dev->devno);
 		return -ENODEV;
 	}
+
+	if (video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
+					vbi_nr[dev->devno]) < 0) {
+		printk("unable to register vbi device\n");
+		mutex_unlock(&dev->lock);
+		list_del(&dev->devlist);
+		video_device_release(dev->vbi_dev);
+		video_device_release(dev->vdev);
+		kfree(dev);
+		em28xx_devused&=~(1<<dev->devno);
+		return -ENODEV;
+	} else {
+		printk("registered VBI\n");
+	}
+
 	if (dev->has_msp34xx) {
 		/* Send a reset to other chips via gpio */
 		em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1);
@@ -1806,10 +1696,11 @@
 	}
 	video_mux(dev, 0);
 
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 
-	em28xx_info("V4L2 device registered as /dev/video%d\n",
-		    dev->vdev->minor);
+	em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n",
+				dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN,
+				dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN);
 
 	return 0;
 }
@@ -1831,6 +1722,9 @@
 	udev = usb_get_dev(interface_to_usbdev(interface));
 	ifnum = interface->altsetting[0].desc.bInterfaceNumber;
 
+	/* Check to see next free device and mark as used */
+	nr=find_first_zero_bit(&em28xx_devused,EM28XX_MAXBOARDS);
+	em28xx_devused|=1<<nr;
 
 	/* Don't register audio interfaces */
 	if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
@@ -1838,6 +1732,8 @@
 				udev->descriptor.idVendor,udev->descriptor.idProduct,
 				ifnum,
 				interface->altsetting[0].desc.bInterfaceClass);
+
+		em28xx_devused&=~(1<<nr);
 		return -ENODEV;
 	}
 
@@ -1852,18 +1748,20 @@
 	if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
 	    USB_ENDPOINT_XFER_ISOC) {
 		em28xx_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n");
+		em28xx_devused&=~(1<<nr);
 		return -ENODEV;
 	}
 	if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
 		em28xx_err(DRIVER_NAME " probing error: endpoint is ISO OUT endpoint!\n");
+		em28xx_devused&=~(1<<nr);
 		return -ENODEV;
 	}
 
 	model=id->driver_info;
-	nr=interface->minor;
 
-	if (nr>EM28XX_MAXBOARDS) {
+	if (nr >= EM28XX_MAXBOARDS) {
 		printk (DRIVER_NAME ": Supports only %i em28xx boards.\n",EM28XX_MAXBOARDS);
+		em28xx_devused&=~(1<<nr);
 		return -ENOMEM;
 	}
 
@@ -1871,19 +1769,24 @@
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (dev == NULL) {
 		em28xx_err(DRIVER_NAME ": out of memory!\n");
+		em28xx_devused&=~(1<<nr);
 		return -ENOMEM;
 	}
 
+	snprintf(dev->name, 29, "em28xx #%d", nr);
+	dev->devno=nr;
+
 	/* compute alternate max packet sizes */
 	uif = udev->actconfig->interface[0];
 
 	dev->num_alt=uif->num_altsetting;
-	printk(DRIVER_NAME ": Alternate settings: %i\n",dev->num_alt);
+	em28xx_info("Alternate settings: %i\n",dev->num_alt);
 //	dev->alt_max_pkt_size = kmalloc(sizeof(*dev->alt_max_pkt_size)*
 	dev->alt_max_pkt_size = kmalloc(32*
 						dev->num_alt,GFP_KERNEL);
 	if (dev->alt_max_pkt_size == NULL) {
-		em28xx_err(DRIVER_NAME ": out of memory!\n");
+		em28xx_errdev("out of memory!\n");
+		em28xx_devused&=~(1<<nr);
 		return -ENOMEM;
 	}
 
@@ -1892,27 +1795,26 @@
 							wMaxPacketSize);
 		dev->alt_max_pkt_size[i] =
 		    (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
-		printk(DRIVER_NAME ": Alternate setting %i, max size= %i\n",i,
+		em28xx_info("Alternate setting %i, max size= %i\n",i,
 							dev->alt_max_pkt_size[i]);
 	}
 
-	snprintf(dev->name, 29, "em28xx #%d", nr);
-
 	if ((card[nr]>=0)&&(card[nr]<em28xx_bcount))
 		model=card[nr];
 
 	if ((model==EM2800_BOARD_UNKNOWN)||(model==EM2820_BOARD_UNKNOWN)) {
-		printk( "%s: Your board has no eeprom inside it and thus can't\n"
+		em28xx_errdev( "Your board has no eeprom inside it and thus can't\n"
 			"%s: be autodetected.  Please pass card=<n> insmod option to\n"
 			"%s: workaround that.  Redirect complaints to the vendor of\n"
-			"%s: the TV card.  Best regards,\n"
+			"%s: the TV card. Generic type will be used."
+			"%s: Best regards,\n"
 			"%s:         -- tux\n",
 			dev->name,dev->name,dev->name,dev->name,dev->name);
-		printk("%s: Here is a list of valid choices for the card=<n> insmod option:\n",
+		em28xx_errdev("%s: Here is a list of valid choices for the card=<n> insmod option:\n",
 			dev->name);
 		for (i = 0; i < em28xx_bcount; i++) {
-			printk("%s:    card=%d -> %s\n",
-				dev->name, i, em28xx_boards[i].name);
+			em28xx_errdev("    card=%d -> %s\n", i,
+							em28xx_boards[i].name);
 		}
 	}
 
@@ -1938,15 +1840,12 @@
 	struct em28xx *dev = usb_get_intfdata(interface);
 	usb_set_intfdata(interface, NULL);
 
-/*FIXME: IR should be disconnected */
-
 	if (!dev)
 		return;
 
-
 	down_write(&em28xx_disconnect);
 
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 
 	em28xx_info("disconnecting %s\n", dev->vdev->name);
 
@@ -1955,7 +1854,9 @@
 	if (dev->users) {
 		em28xx_warn
 		    ("device /dev/video%d is open! Deregistration and memory "
-		     "deallocation are deferred on close.\n", dev->vdev->minor);
+		     "deallocation are deferred on close.\n",
+				dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN);
+
 		dev->state |= DEV_MISCONFIGURED;
 		em28xx_uninit_isoc(dev);
 		dev->state |= DEV_DISCONNECTED;
@@ -1966,7 +1867,7 @@
 		em28xx_release_resources(dev);
 	}
 
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 
 	if (!dev->users) {
 		kfree(dev->alt_max_pkt_size);
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index 33de9d8..e1ddc2f 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -27,6 +27,7 @@
 
 #include <linux/videodev.h>
 #include <linux/i2c.h>
+#include <linux/mutex.h>
 #include <media/ir-kbd-i2c.h>
 
 /* Boards supported by driver */
@@ -41,6 +42,10 @@
 #define EM2800_BOARD_LEADTEK_WINFAST_USBII      7
 #define EM2800_BOARD_KWORLD_USB2800             8
 #define EM2820_BOARD_PINNACLE_DVC_90		9
+#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900	10
+#define EM2880_BOARD_TERRATEC_HYBRID_XS		11
+#define EM2820_BOARD_KWORLD_PVRTV2800RF		12
+#define EM2880_BOARD_TERRATEC_PRODIGY_XS	13
 
 #define UNSET -1
 
@@ -209,6 +214,7 @@
 	/* generic device properties */
 	char name[30];		/* name (including minor) of the device */
 	int model;		/* index in the device_data struct */
+	int devno;		/* marks the number of this device */
 	unsigned int is_em2800;
 	int video_inputs;	/* number of video inputs */
 	struct list_head	devlist;
@@ -256,7 +262,7 @@
 	enum em28xx_stream_state stream;
 	enum em28xx_io_method io;
 	/* locks */
-	struct semaphore lock, fileop_lock;
+	struct mutex lock, fileop_lock;
 	spinlock_t queue_lock;
 	struct list_head inqueue, outqueue;
 	wait_queue_head_t open, wait_frame, wait_stream;
@@ -326,6 +332,7 @@
 
 /* Provided by em28xx-cards.c */
 extern int em2800_variant_detect(struct usb_device* udev,int model);
+extern void em28xx_pre_card_setup(struct em28xx *dev);
 extern void em28xx_card_setup(struct em28xx *dev);
 extern struct em28xx_board em28xx_boards[];
 extern struct usb_device_id em28xx_id_table[];
diff --git a/drivers/media/video/hexium_gemini.c b/drivers/media/video/hexium_gemini.c
index e7bbeb1..c7fed34 100644
--- a/drivers/media/video/hexium_gemini.c
+++ b/drivers/media/video/hexium_gemini.c
@@ -1,9 +1,9 @@
 /*
     hexium_gemini.c - v4l2 driver for Hexium Gemini frame grabber cards
-               
+
     Visit http://www.mihu.de/linux/saa7146/ and follow the link
     to "hexium" for further details about this card.
-    
+
     Copyright (C) 2003 Michael Hunold <michael@mihu.de>
 
     This program is free software; you can redistribute it and/or modify
@@ -81,7 +81,7 @@
 
 	struct video_device	*video_dev;
 	struct i2c_adapter	i2c_adapter;
-		
+
 	int 		cur_input;	/* current input */
 	v4l2_std_id 	cur_std;	/* current standard */
 	int		cur_bw;		/* current black/white status */
@@ -174,7 +174,7 @@
 		.h_offset	= 1,	.h_pixels 	= 720,
 		.v_max_out	= 576,	.h_max_out	= 768,
 	}
-};		
+};
 
 /* bring hardware to a sane state. this has to be done, just in case someone
    wants to capture from this device before it has been properly initialized.
@@ -311,7 +311,7 @@
 	struct saa7146_dev *dev = fh->dev;
 	struct hexium *hexium = (struct hexium *) dev->ext_priv;
 /*
-	struct saa7146_vv *vv = dev->vv_data; 
+	struct saa7146_vv *vv = dev->vv_data;
 */
 	switch (cmd) {
 	case VIDIOC_ENUMINPUT:
diff --git a/drivers/media/video/hexium_orion.c b/drivers/media/video/hexium_orion.c
index aad4a18..137c473 100644
--- a/drivers/media/video/hexium_orion.c
+++ b/drivers/media/video/hexium_orion.c
@@ -3,7 +3,7 @@
 
     Visit http://www.mihu.de/linux/saa7146/ and follow the link
     to "hexium" for further details about this card.
-    
+
     Copyright (C) 2003 Michael Hunold <michael@mihu.de>
 
     This program is free software; you can redistribute it and/or modify
@@ -69,7 +69,7 @@
 {
 	int type;
 	struct video_device	*video_dev;
-	struct i2c_adapter	i2c_adapter;	
+	struct i2c_adapter	i2c_adapter;
 
 	int cur_input;	/* current input */
 };
@@ -86,7 +86,7 @@
 };
 
 static struct {
-	struct hexium_data data[8];	
+	struct hexium_data data[8];
 } hexium_input_select[] = {
 {
 	{ /* cvbs 1 */
@@ -153,7 +153,7 @@
 		{ 0x30, 0x60 },
 		{ 0x31, 0xB5 }, // ??
 		{ 0x21, 0x03 },
-	} 
+	}
 }, {
 	{ /* y/c 1 */
 		{ 0x06, 0x80 },
@@ -187,7 +187,7 @@
 		{ 0x31, 0x75 },
 		{ 0x21, 0x21 },
 	}
-}	
+}
 };
 
 static struct saa7146_standard hexium_standards[] = {
@@ -207,7 +207,7 @@
 		.h_offset	= 1,	.h_pixels 	= 720,
 		.v_max_out	= 576,	.h_max_out	= 768,
 	}
-};		
+};
 
 /* this is only called for old HV-PCI6/Orion cards
    without eeprom */
@@ -272,7 +272,7 @@
 		return 0;
 	}
 
-	/* check if this is an old hexium Orion card by looking at 
+	/* check if this is an old hexium Orion card by looking at
 	   a saa7110 at address 0x4e */
 	if (0 == (err = i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, &data))) {
 		printk("hexium_orion: device is a Hexium HV-PCI6/Orion (old).\n");
@@ -314,7 +314,7 @@
 {
 	union i2c_smbus_data data;
 	int i = 0;
-	
+
 	DEB_D((".\n"));
 
 	for (i = 0; i < 8; i++) {
@@ -375,7 +375,7 @@
 	struct saa7146_dev *dev = fh->dev;
 	struct hexium *hexium = (struct hexium *) dev->ext_priv;
 /*
-	struct saa7146_vv *vv = dev->vv_data; 
+	struct saa7146_vv *vv = dev->vv_data;
 */
 	switch (cmd) {
 	case VIDIOC_ENUMINPUT:
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 58b0e69..95bacf43 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -44,51 +44,17 @@
 #include <media/ir-common.h>
 #include <media/ir-kbd-i2c.h>
 
-/* Mark Phalan <phalanm@o2.ie> */
-static IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE] = {
-	[  0 ] = KEY_KP0,
-	[  1 ] = KEY_KP1,
-	[  2 ] = KEY_KP2,
-	[  3 ] = KEY_KP3,
-	[  4 ] = KEY_KP4,
-	[  5 ] = KEY_KP5,
-	[  6 ] = KEY_KP6,
-	[  7 ] = KEY_KP7,
-	[  8 ] = KEY_KP8,
-	[  9 ] = KEY_KP9,
-
-	[ 18 ] = KEY_POWER,
-	[ 16 ] = KEY_MUTE,
-	[ 31 ] = KEY_VOLUMEDOWN,
-	[ 27 ] = KEY_VOLUMEUP,
-	[ 26 ] = KEY_CHANNELUP,
-	[ 30 ] = KEY_CHANNELDOWN,
-	[ 14 ] = KEY_PAGEUP,
-	[ 29 ] = KEY_PAGEDOWN,
-	[ 19 ] = KEY_SOUND,
-
-	[ 24 ] = KEY_KPPLUSMINUS,	/* CH +/- */
-	[ 22 ] = KEY_SUBTITLE,		/* CC */
-	[ 13 ] = KEY_TEXT,		/* TTX */
-	[ 11 ] = KEY_TV,		/* AIR/CBL */
-	[ 17 ] = KEY_PC,		/* PC/TV */
-	[ 23 ] = KEY_OK,		/* CH RTN */
-	[ 25 ] = KEY_MODE, 		/* FUNC */
-	[ 12 ] = KEY_SEARCH, 		/* AUTOSCAN */
-
-	/* Not sure what to do with these ones! */
-	[ 15 ] = KEY_SELECT, 		/* SOURCE */
-	[ 10 ] = KEY_KPPLUS,		/* +100 */
-	[ 20 ] = KEY_KPEQUAL,		/* SYNC */
-	[ 28 ] = KEY_MEDIA,             /* PC/TV */
-};
-
 /* ----------------------------------------------------------------------- */
 /* insmod parameters                                                       */
 
 static int debug;
 module_param(debug, int, 0644);    /* debug level (0,1,2) */
 
+static int hauppauge = 0;
+module_param(hauppauge, int, 0644);    /* Choose Hauppauge remote */
+MODULE_PARM_DESC(hauppauge, "Specify Hauppauge remote: 0=black, 1=grey (defaults to 0)");
+
+
 #define DEVNAME "ir-kbd-i2c"
 #define dprintk(level, fmt, arg...)	if (debug >= level) \
 	printk(KERN_DEBUG DEVNAME ": " fmt , ## arg)
@@ -336,7 +302,11 @@
 		name        = "Hauppauge";
 		ir->get_key = get_key_haup;
 		ir_type     = IR_TYPE_RC5;
-		ir_codes    = ir_codes_rc5_tv;
+		if (hauppauge == 1) {
+			ir_codes    = ir_codes_hauppauge_new;
+		} else {
+			ir_codes    = ir_codes_rc5_tv;
+		}
 		break;
 	case 0x30:
 		name        = "KNC One";
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index 2869464..850bee9 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -925,7 +925,7 @@
 			return -EINVAL;
 		if (p->palette != VIDEO_PALETTE_YUV422)
 			return -EINVAL;
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 		sonypi_camera_command(SONYPI_COMMAND_SETCAMERABRIGHTNESS,
 				      p->brightness >> 10);
 		sonypi_camera_command(SONYPI_COMMAND_SETCAMERAHUE,
@@ -935,7 +935,7 @@
 		sonypi_camera_command(SONYPI_COMMAND_SETCAMERACONTRAST,
 				      p->contrast >> 10);
 		meye.picture = *p;
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		break;
 	}
 
@@ -946,21 +946,21 @@
 		if (*i < 0 || *i >= gbuffers)
 			return -EINVAL;
 
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 
 		switch (meye.grab_buffer[*i].state) {
 
 		case MEYE_BUF_UNUSED:
-			up(&meye.lock);
+			mutex_unlock(&meye.lock);
 			return -EINVAL;
 		case MEYE_BUF_USING:
 			if (file->f_flags & O_NONBLOCK) {
-				up(&meye.lock);
+				mutex_unlock(&meye.lock);
 				return -EAGAIN;
 			}
 			if (wait_event_interruptible(meye.proc_list,
 						     (meye.grab_buffer[*i].state != MEYE_BUF_USING))) {
-				up(&meye.lock);
+				mutex_unlock(&meye.lock);
 				return -EINTR;
 			}
 			/* fall through */
@@ -968,7 +968,7 @@
 			meye.grab_buffer[*i].state = MEYE_BUF_UNUSED;
 			kfifo_get(meye.doneq, (unsigned char *)&unused, sizeof(int));
 		}
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		break;
 	}
 
@@ -987,7 +987,7 @@
 		if (meye.grab_buffer[vm->frame].state != MEYE_BUF_UNUSED)
 			return -EBUSY;
 
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 		if (vm->width == 640 && vm->height == 480) {
 			if (meye.params.subsample) {
 				meye.params.subsample = 0;
@@ -999,7 +999,7 @@
 				restart = 1;
 			}
 		} else {
-			up(&meye.lock);
+			mutex_unlock(&meye.lock);
 			return -EINVAL;
 		}
 
@@ -1007,7 +1007,7 @@
 			mchip_continuous_start();
 		meye.grab_buffer[vm->frame].state = MEYE_BUF_USING;
 		kfifo_put(meye.grabq, (unsigned char *)&vm->frame, sizeof(int));
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		break;
 	}
 
@@ -1039,7 +1039,7 @@
 			return -EINVAL;
 		if (jp->framerate > 31)
 			return -EINVAL;
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 		if (meye.params.subsample != jp->subsample ||
 		    meye.params.quality != jp->quality)
 			mchip_hic_stop();	/* need restart */
@@ -1050,7 +1050,7 @@
 				      meye.params.agc);
 		sonypi_camera_command(SONYPI_COMMAND_SETCAMERAPICTURE,
 				      meye.params.picture);
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		break;
 	}
 
@@ -1068,12 +1068,12 @@
 		}
 		if (meye.grab_buffer[*nb].state != MEYE_BUF_UNUSED)
 			return -EBUSY;
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 		if (meye.mchip_mode != MCHIP_HIC_MODE_CONT_COMP)
 			mchip_cont_compression_start();
 		meye.grab_buffer[*nb].state = MEYE_BUF_USING;
 		kfifo_put(meye.grabq, (unsigned char *)nb, sizeof(int));
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		break;
 	}
 
@@ -1084,20 +1084,20 @@
 		if (*i < 0 || *i >= gbuffers)
 			return -EINVAL;
 
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 		switch (meye.grab_buffer[*i].state) {
 
 		case MEYE_BUF_UNUSED:
-			up(&meye.lock);
+			mutex_unlock(&meye.lock);
 			return -EINVAL;
 		case MEYE_BUF_USING:
 			if (file->f_flags & O_NONBLOCK) {
-				up(&meye.lock);
+				mutex_unlock(&meye.lock);
 				return -EAGAIN;
 			}
 			if (wait_event_interruptible(meye.proc_list,
 						     (meye.grab_buffer[*i].state != MEYE_BUF_USING))) {
-				up(&meye.lock);
+				mutex_unlock(&meye.lock);
 				return -EINTR;
 			}
 			/* fall through */
@@ -1106,7 +1106,7 @@
 			kfifo_get(meye.doneq, (unsigned char *)&unused, sizeof(int));
 		}
 		*i = meye.grab_buffer[*i].size;
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		break;
 	}
 
@@ -1116,14 +1116,14 @@
 			return -EINVAL;
 		if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED)
 			return -EBUSY;
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 		meye.grab_buffer[0].state = MEYE_BUF_USING;
 		mchip_take_picture();
 		mchip_get_picture(
 			meye.grab_fbuffer,
 			mchip_hsize() * mchip_vsize() * 2);
 		meye.grab_buffer[0].state = MEYE_BUF_DONE;
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		break;
 	}
 
@@ -1134,7 +1134,7 @@
 			return -EINVAL;
 		if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED)
 			return -EBUSY;
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 		meye.grab_buffer[0].state = MEYE_BUF_USING;
 		*len = -1;
 		while (*len == -1) {
@@ -1142,7 +1142,7 @@
 			*len = mchip_compress_frame(meye.grab_fbuffer, gbufsize);
 		}
 		meye.grab_buffer[0].state = MEYE_BUF_DONE;
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		break;
 	}
 
@@ -1285,7 +1285,7 @@
 	case VIDIOC_S_CTRL: {
 		struct v4l2_control *c = arg;
 
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 		switch (c->id) {
 		case V4L2_CID_BRIGHTNESS:
 			sonypi_camera_command(
@@ -1329,17 +1329,17 @@
 			meye.params.framerate = c->value;
 			break;
 		default:
-			up(&meye.lock);
+			mutex_unlock(&meye.lock);
 			return -EINVAL;
 		}
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		break;
 	}
 
 	case VIDIOC_G_CTRL: {
 		struct v4l2_control *c = arg;
 
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 		switch (c->id) {
 		case V4L2_CID_BRIGHTNESS:
 			c->value = meye.picture.brightness >> 10;
@@ -1369,10 +1369,10 @@
 			c->value = meye.params.framerate;
 			break;
 		default:
-			up(&meye.lock);
+			mutex_unlock(&meye.lock);
 			return -EINVAL;
 		}
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		break;
 	}
 
@@ -1469,7 +1469,7 @@
 		    f->fmt.pix.field != V4L2_FIELD_NONE)
 			return -EINVAL;
 		f->fmt.pix.field = V4L2_FIELD_NONE;
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 		if (f->fmt.pix.width <= 320) {
 			f->fmt.pix.width = 320;
 			f->fmt.pix.height = 240;
@@ -1487,7 +1487,7 @@
 			meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP;
 			break;
 		}
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
 		f->fmt.pix.sizeimage = f->fmt.pix.height *
 				       f->fmt.pix.bytesperline;
@@ -1509,11 +1509,11 @@
 			/* already allocated, no modifications */
 			break;
 		}
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 		if (meye.grab_fbuffer) {
 			for (i = 0; i < gbuffers; i++)
 				if (meye.vma_use_count[i]) {
-					up(&meye.lock);
+					mutex_unlock(&meye.lock);
 					return -EINVAL;
 				}
 			rvfree(meye.grab_fbuffer, gbuffers * gbufsize);
@@ -1525,12 +1525,12 @@
 		if (!meye.grab_fbuffer) {
 			printk(KERN_ERR "meye: v4l framebuffer allocation"
 					" failed\n");
-			up(&meye.lock);
+			mutex_unlock(&meye.lock);
 			return -ENOMEM;
 		}
 		for (i = 0; i < gbuffers; i++)
 			meye.vma_use_count[i] = 0;
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		break;
 	}
 
@@ -1569,12 +1569,12 @@
 			return -EINVAL;
 		if (meye.grab_buffer[buf->index].state != MEYE_BUF_UNUSED)
 			return -EINVAL;
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 		buf->flags |= V4L2_BUF_FLAG_QUEUED;
 		buf->flags &= ~V4L2_BUF_FLAG_DONE;
 		meye.grab_buffer[buf->index].state = MEYE_BUF_USING;
 		kfifo_put(meye.grabq, (unsigned char *)&buf->index, sizeof(int));
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		break;
 	}
 
@@ -1587,23 +1587,23 @@
 		if (buf->memory != V4L2_MEMORY_MMAP)
 			return -EINVAL;
 
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 		if (kfifo_len(meye.doneq) == 0 && file->f_flags & O_NONBLOCK) {
-			up(&meye.lock);
+			mutex_unlock(&meye.lock);
 			return -EAGAIN;
 		}
 		if (wait_event_interruptible(meye.proc_list,
 					     kfifo_len(meye.doneq) != 0) < 0) {
-			up(&meye.lock);
+			mutex_unlock(&meye.lock);
 			return -EINTR;
 		}
 		if (!kfifo_get(meye.doneq, (unsigned char *)&reqnr,
 			       sizeof(int))) {
-			up(&meye.lock);
+			mutex_unlock(&meye.lock);
 			return -EBUSY;
 		}
 		if (meye.grab_buffer[reqnr].state != MEYE_BUF_DONE) {
-			up(&meye.lock);
+			mutex_unlock(&meye.lock);
 			return -EINVAL;
 		}
 		buf->index = reqnr;
@@ -1616,12 +1616,12 @@
 		buf->m.offset = reqnr * gbufsize;
 		buf->length = gbufsize;
 		meye.grab_buffer[reqnr].state = MEYE_BUF_UNUSED;
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		break;
 	}
 
 	case VIDIOC_STREAMON: {
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 		switch (meye.mchip_mode) {
 		case MCHIP_HIC_MODE_CONT_OUT:
 			mchip_continuous_start();
@@ -1630,23 +1630,23 @@
 			mchip_cont_compression_start();
 			break;
 		default:
-			up(&meye.lock);
+			mutex_unlock(&meye.lock);
 			return -EINVAL;
 		}
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		break;
 	}
 
 	case VIDIOC_STREAMOFF: {
 		int i;
 
-		down(&meye.lock);
+		mutex_lock(&meye.lock);
 		mchip_hic_stop();
 		kfifo_reset(meye.grabq);
 		kfifo_reset(meye.doneq);
 		for (i = 0; i < MEYE_MAX_BUFNBRS; i++)
 			meye.grab_buffer[i].state = MEYE_BUF_UNUSED;
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		break;
 	}
 
@@ -1672,11 +1672,11 @@
 {
 	unsigned int res = 0;
 
-	down(&meye.lock);
+	mutex_lock(&meye.lock);
 	poll_wait(file, &meye.proc_list, wait);
 	if (kfifo_len(meye.doneq))
 		res = POLLIN | POLLRDNORM;
-	up(&meye.lock);
+	mutex_unlock(&meye.lock);
 	return res;
 }
 
@@ -1704,9 +1704,9 @@
 	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
 	unsigned long page, pos;
 
-	down(&meye.lock);
+	mutex_lock(&meye.lock);
 	if (size > gbuffers * gbufsize) {
-		up(&meye.lock);
+		mutex_unlock(&meye.lock);
 		return -EINVAL;
 	}
 	if (!meye.grab_fbuffer) {
@@ -1716,7 +1716,7 @@
 		meye.grab_fbuffer = rvmalloc(gbuffers*gbufsize);
 		if (!meye.grab_fbuffer) {
 			printk(KERN_ERR "meye: v4l framebuffer allocation failed\n");
-			up(&meye.lock);
+			mutex_unlock(&meye.lock);
 			return -ENOMEM;
 		}
 		for (i = 0; i < gbuffers; i++)
@@ -1727,7 +1727,7 @@
 	while (size > 0) {
 		page = vmalloc_to_pfn((void *)pos);
 		if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-			up(&meye.lock);
+			mutex_unlock(&meye.lock);
 			return -EAGAIN;
 		}
 		start += PAGE_SIZE;
@@ -1744,7 +1744,7 @@
 	vma->vm_private_data = (void *) (offset / gbufsize);
 	meye_vm_open(vma);
 
-	up(&meye.lock);
+	mutex_unlock(&meye.lock);
 	return 0;
 }
 
@@ -1913,7 +1913,7 @@
 		goto outvideoreg;
 	}
 
-	init_MUTEX(&meye.lock);
+	mutex_init(&meye.lock);
 	init_waitqueue_head(&meye.proc_list);
 	meye.picture.depth = 16;
 	meye.picture.palette = VIDEO_PALETTE_YUV422;
diff --git a/drivers/media/video/meye.h b/drivers/media/video/meye.h
index e8cd897..0d09a0e 100644
--- a/drivers/media/video/meye.h
+++ b/drivers/media/video/meye.h
@@ -260,6 +260,8 @@
 
 /* private API definitions */
 #include <linux/meye.h>
+#include <linux/mutex.h>
+
 
 /* Enable jpg software correction */
 #define MEYE_JPEG_CORRECTION	1
@@ -301,7 +303,7 @@
 					/* list of buffers */
 	struct meye_grab_buffer grab_buffer[MEYE_MAX_BUFNBRS];
 	int vma_use_count[MEYE_MAX_BUFNBRS]; /* mmap count */
-	struct semaphore lock;		/* semaphore for open/mmap... */
+	struct mutex lock;		/* mutex for open/mmap... */
 	struct kfifo *grabq;		/* queue for buffers to be grabbed */
 	spinlock_t grabq_lock;		/* lock protecting the queue */
 	struct kfifo *doneq;		/* queue for grabbed buffers */
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
index 69ed369..11ea976 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/video/msp3400-driver.c
@@ -411,9 +411,9 @@
 	if (rxsubchans & V4L2_TUNER_SUB_STEREO)
 		mode |= VIDEO_SOUND_STEREO;
 	if (rxsubchans & V4L2_TUNER_SUB_LANG2)
-		mode |= VIDEO_SOUND_LANG2;
+		mode |= VIDEO_SOUND_LANG2 | VIDEO_SOUND_STEREO;
 	if (rxsubchans & V4L2_TUNER_SUB_LANG1)
-		mode |= VIDEO_SOUND_LANG1;
+		mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_STEREO;
 	if (mode == 0)
 		mode |= VIDEO_SOUND_MONO;
 	return mode;
@@ -430,21 +430,6 @@
 	return V4L2_TUNER_MODE_MONO;
 }
 
-static void msp_any_detect_stereo(struct i2c_client *client)
-{
-	struct msp_state *state  = i2c_get_clientdata(client);
-
-	switch (state->opmode) {
-	case OPMODE_MANUAL:
-	case OPMODE_AUTODETECT:
-		autodetect_stereo(client);
-		break;
-	case OPMODE_AUTOSELECT:
-		msp34xxg_detect_stereo(client);
-		break;
-	}
-}
-
 static struct v4l2_queryctrl msp_qctrl_std[] = {
 	{
 		.id            = V4L2_CID_AUDIO_VOLUME,
@@ -506,22 +491,6 @@
 };
 
 
-static void msp_any_set_audmode(struct i2c_client *client, int audmode)
-{
-	struct msp_state *state = i2c_get_clientdata(client);
-
-	switch (state->opmode) {
-	case OPMODE_MANUAL:
-	case OPMODE_AUTODETECT:
-		state->watch_stereo = 0;
-		msp3400c_setstereo(client, audmode);
-		break;
-	case OPMODE_AUTOSELECT:
-		msp34xxg_set_audmode(client, audmode);
-		break;
-	}
-}
-
 static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
 {
 	struct msp_state *state = i2c_get_clientdata(client);
@@ -653,11 +622,10 @@
 		}
 		if (scart) {
 			state->rxsubchans = V4L2_TUNER_SUB_STEREO;
-			state->audmode = V4L2_TUNER_MODE_STEREO;
 			msp_set_scart(client, scart, 0);
 			msp_write_dsp(client, 0x000d, 0x1900);
 			if (state->opmode != OPMODE_AUTOSELECT)
-				msp3400c_setstereo(client, state->audmode);
+				msp_set_audmode(client);
 		}
 		msp_wake_thread(client);
 		break;
@@ -671,8 +639,8 @@
 		switch (state->opmode) {
 		case OPMODE_MANUAL:
 			/* set msp3400 to FM radio mode */
-			msp3400c_setmode(client, MSP_MODE_FM_RADIO);
-			msp3400c_setcarrier(client, MSP_CARRIER(10.7),
+			msp3400c_set_mode(client, MSP_MODE_FM_RADIO);
+			msp3400c_set_carrier(client, MSP_CARRIER(10.7),
 					    MSP_CARRIER(10.7));
 			msp_set_audio(client);
 			break;
@@ -706,7 +674,7 @@
 		if (state->radio)
 			break;
 		if (state->opmode == OPMODE_AUTOSELECT)
-			msp_any_detect_stereo(client);
+			msp_detect_stereo(client);
 		va->mode = msp_mode_v4l2_to_v4l1(state->rxsubchans);
 		break;
 	}
@@ -722,8 +690,9 @@
 		state->treble = va->treble;
 		msp_set_audio(client);
 
-		if (va->mode != 0 && state->radio == 0)
-			msp_any_set_audmode(client, msp_mode_v4l1_to_v4l2(va->mode));
+		if (va->mode != 0 && state->radio == 0) {
+			state->audmode = msp_mode_v4l1_to_v4l2(va->mode);
+		}
 		break;
 	}
 
@@ -831,11 +800,8 @@
 			return -EINVAL;
 		}
 
-		msp_any_detect_stereo(client);
-		if (state->audmode == V4L2_TUNER_MODE_STEREO) {
-			a->capability = V4L2_AUDCAP_STEREO;
-		}
-
+		a->capability = V4L2_AUDCAP_STEREO;
+		a->mode = 0;  /* TODO: add support for AVL */
 		break;
 	}
 
@@ -865,16 +831,10 @@
 		}
 		if (scart) {
 			state->rxsubchans = V4L2_TUNER_SUB_STEREO;
-			state->audmode = V4L2_TUNER_MODE_STEREO;
 			msp_set_scart(client, scart, 0);
 			msp_write_dsp(client, 0x000d, 0x1900);
 		}
-		if (sarg->capability == V4L2_AUDCAP_STEREO) {
-			state->audmode = V4L2_TUNER_MODE_STEREO;
-		} else {
-			state->audmode &= ~V4L2_TUNER_MODE_STEREO;
-		}
-		msp_any_set_audmode(client, state->audmode);
+		msp_set_audmode(client);
 		msp_wake_thread(client);
 		break;
 	}
@@ -886,7 +846,7 @@
 		if (state->radio)
 			break;
 		if (state->opmode == OPMODE_AUTOSELECT)
-			msp_any_detect_stereo(client);
+			msp_detect_stereo(client);
 		vt->audmode    = state->audmode;
 		vt->rxsubchans = state->rxsubchans;
 		vt->capability = V4L2_TUNER_CAP_STEREO |
@@ -898,11 +858,11 @@
 	{
 		struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
 
-		if (state->radio)
+		if (state->radio)  /* TODO: add mono/stereo support for radio */
 			break;
+		state->audmode = vt->audmode;
 		/* only set audmode */
-		if (vt->audmode != -1 && vt->audmode != 0)
-			msp_any_set_audmode(client, vt->audmode);
+		msp_set_audmode(client);
 		break;
 	}
 
@@ -927,7 +887,6 @@
 			return -EINVAL;
 		}
 		break;
-
 	}
 
 	case VIDIOC_S_AUDOUT:
@@ -993,7 +952,7 @@
 		const char *p;
 
 		if (state->opmode == OPMODE_AUTOSELECT)
-			msp_any_detect_stereo(client);
+			msp_detect_stereo(client);
 		v4l_info(client, "%s rev1 = 0x%04x rev2 = 0x%04x\n",
 				client->name, state->rev1, state->rev2);
 		v4l_info(client, "Audio:    volume %d%s\n",
@@ -1094,6 +1053,7 @@
 
 	memset(state, 0, sizeof(*state));
 	state->v4l2_std = V4L2_STD_NTSC;
+	state->audmode = V4L2_TUNER_MODE_LANG1;
 	state->volume = 58880;	/* 0db gain */
 	state->balance = 32768;	/* 0db gain */
 	state->bass = 32768;
diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c
index 2072c3e..852ab6a 100644
--- a/drivers/media/video/msp3400-kthreads.c
+++ b/drivers/media/video/msp3400-kthreads.c
@@ -109,7 +109,7 @@
 		{-2, -8, -10, 10, 50, 86},
 		{-4, -12, -9, 23, 79, 126},
 		MSP_CARRIER(6.5), MSP_CARRIER(6.5),
-		0x00c6, 0x0140, 0x0120, 0x7c03
+		0x00c6, 0x0140, 0x0120, 0x7c00
 	},
 };
 
@@ -154,54 +154,60 @@
 	return "unknown";
 }
 
-void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2)
+static void msp_set_source(struct i2c_client *client, u16 src)
+{
+	struct msp_state *state = i2c_get_clientdata(client);
+
+	if (msp_dolby) {
+		msp_write_dsp(client, 0x0008, 0x0520); /* I2S1 */
+		msp_write_dsp(client, 0x0009, 0x0620); /* I2S2 */
+	} else {
+		msp_write_dsp(client, 0x0008, src);
+		msp_write_dsp(client, 0x0009, src);
+	}
+	msp_write_dsp(client, 0x000a, src);
+	msp_write_dsp(client, 0x000b, src);
+	msp_write_dsp(client, 0x000c, src);
+	if (state->has_scart23_in_scart2_out)
+		msp_write_dsp(client, 0x0041, src);
+}
+
+void msp3400c_set_carrier(struct i2c_client *client, int cdo1, int cdo2)
 {
 	msp_write_dem(client, 0x0093, cdo1 & 0xfff);
 	msp_write_dem(client, 0x009b, cdo1 >> 12);
 	msp_write_dem(client, 0x00a3, cdo2 & 0xfff);
 	msp_write_dem(client, 0x00ab, cdo2 >> 12);
-	msp_write_dem(client, 0x0056, 0); /*LOAD_REG_1/2*/
+	msp_write_dem(client, 0x0056, 0); /* LOAD_REG_1/2 */
 }
 
-void msp3400c_setmode(struct i2c_client *client, int type)
+void msp3400c_set_mode(struct i2c_client *client, int mode)
 {
 	struct msp_state *state = i2c_get_clientdata(client);
+	struct msp3400c_init_data_dem *data = &msp3400c_init_data[mode];
 	int i;
 
-	v4l_dbg(1, msp_debug, client, "setmode: %d\n", type);
-	state->mode       = type;
-	state->audmode    = V4L2_TUNER_MODE_MONO;
+	v4l_dbg(1, msp_debug, client, "set_mode: %d\n", mode);
+	state->mode = mode;
 	state->rxsubchans = V4L2_TUNER_SUB_MONO;
 
-	msp_write_dem(client, 0x00bb, msp3400c_init_data[type].ad_cv);
+	msp_write_dem(client, 0x00bb, data->ad_cv);
 
 	for (i = 5; i >= 0; i--)               /* fir 1 */
-		msp_write_dem(client, 0x0001, msp3400c_init_data[type].fir1[i]);
+		msp_write_dem(client, 0x0001, data->fir1[i]);
 
 	msp_write_dem(client, 0x0005, 0x0004); /* fir 2 */
 	msp_write_dem(client, 0x0005, 0x0040);
 	msp_write_dem(client, 0x0005, 0x0000);
 	for (i = 5; i >= 0; i--)
-		msp_write_dem(client, 0x0005, msp3400c_init_data[type].fir2[i]);
+		msp_write_dem(client, 0x0005, data->fir2[i]);
 
-	msp_write_dem(client, 0x0083, msp3400c_init_data[type].mode_reg);
+	msp_write_dem(client, 0x0083, data->mode_reg);
 
-	msp3400c_setcarrier(client, msp3400c_init_data[type].cdo1,
-			    msp3400c_init_data[type].cdo2);
+	msp3400c_set_carrier(client, data->cdo1, data->cdo2);
 
-	msp_write_dem(client, 0x0056, 0); /*LOAD_REG_1/2*/
-
-	if (msp_dolby) {
-		msp_write_dsp(client, 0x0008, 0x0520); /* I2S1 */
-		msp_write_dsp(client, 0x0009, 0x0620); /* I2S2 */
-		msp_write_dsp(client, 0x000b, msp3400c_init_data[type].dsp_src);
-	} else {
-		msp_write_dsp(client, 0x0008, msp3400c_init_data[type].dsp_src);
-		msp_write_dsp(client, 0x0009, msp3400c_init_data[type].dsp_src);
-		msp_write_dsp(client, 0x000b, msp3400c_init_data[type].dsp_src);
-	}
-	msp_write_dsp(client, 0x000a, msp3400c_init_data[type].dsp_src);
-	msp_write_dsp(client, 0x000e, msp3400c_init_data[type].dsp_matrix);
+	msp_set_source(client, data->dsp_src);
+	msp_write_dsp(client, 0x000e, data->dsp_matrix);
 
 	if (state->has_nicam) {
 		/* nicam prescale */
@@ -209,29 +215,31 @@
 	}
 }
 
-/* turn on/off nicam + stereo */
-void msp3400c_setstereo(struct i2c_client *client, int mode)
+/* Set audio mode. Note that the pre-'G' models do not support BTSC+SAP,
+   nor do they support stereo BTSC. */
+static void msp3400c_set_audmode(struct i2c_client *client)
 {
 	static char *strmode[] = { "mono", "stereo", "lang2", "lang1" };
 	struct msp_state *state = i2c_get_clientdata(client);
-	int nicam = 0;		/* channel source: FM/AM or nicam */
-	int src = 0;
+	char *modestr = (state->audmode >= 0 && state->audmode < 4) ?
+		strmode[state->audmode] : "unknown";
+	int src = 0;	/* channel source: FM/AM, nicam or SCART */
 
 	if (state->opmode == OPMODE_AUTOSELECT) {
 		/* this method would break everything, let's make sure
 		 * it's never called
 		 */
-		v4l_dbg(1, msp_debug, client, "setstereo called with mode=%d instead of set_source (ignored)\n",
-		     mode);
+		v4l_dbg(1, msp_debug, client,
+			"set_audmode called with mode=%d instead of set_source (ignored)\n",
+			state->audmode);
 		return;
 	}
 
 	/* switch demodulator */
 	switch (state->mode) {
 	case MSP_MODE_FM_TERRA:
-		v4l_dbg(1, msp_debug, client, "FM setstereo: %s\n", strmode[mode]);
-		msp3400c_setcarrier(client, state->second, state->main);
-		switch (mode) {
+		v4l_dbg(1, msp_debug, client, "FM set_audmode: %s\n", modestr);
+		switch (state->audmode) {
 		case V4L2_TUNER_MODE_STEREO:
 			msp_write_dsp(client, 0x000e, 0x3001);
 			break;
@@ -243,50 +251,49 @@
 		}
 		break;
 	case MSP_MODE_FM_SAT:
-		v4l_dbg(1, msp_debug, client, "SAT setstereo: %s\n", strmode[mode]);
-		switch (mode) {
+		v4l_dbg(1, msp_debug, client, "SAT set_audmode: %s\n", modestr);
+		switch (state->audmode) {
 		case V4L2_TUNER_MODE_MONO:
-			msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5));
+			msp3400c_set_carrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5));
 			break;
 		case V4L2_TUNER_MODE_STEREO:
-			msp3400c_setcarrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02));
+			msp3400c_set_carrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02));
 			break;
 		case V4L2_TUNER_MODE_LANG1:
-			msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
+			msp3400c_set_carrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
 			break;
 		case V4L2_TUNER_MODE_LANG2:
-			msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
+			msp3400c_set_carrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
 			break;
 		}
 		break;
 	case MSP_MODE_FM_NICAM1:
 	case MSP_MODE_FM_NICAM2:
 	case MSP_MODE_AM_NICAM:
-		v4l_dbg(1, msp_debug, client, "NICAM setstereo: %s\n",strmode[mode]);
-		msp3400c_setcarrier(client,state->second,state->main);
+		v4l_dbg(1, msp_debug, client, "NICAM set_audmode: %s\n",modestr);
+		msp3400c_set_carrier(client, state->second, state->main);
 		if (state->nicam_on)
-			nicam=0x0100;
+			src = 0x0100;  /* NICAM */
 		break;
 	case MSP_MODE_BTSC:
-		v4l_dbg(1, msp_debug, client, "BTSC setstereo: %s\n",strmode[mode]);
-		nicam=0x0300;
+		v4l_dbg(1, msp_debug, client, "BTSC set_audmode: %s\n",modestr);
 		break;
 	case MSP_MODE_EXTERN:
-		v4l_dbg(1, msp_debug, client, "extern setstereo: %s\n",strmode[mode]);
-		nicam = 0x0200;
+		v4l_dbg(1, msp_debug, client, "extern set_audmode: %s\n",modestr);
+		src = 0x0200;  /* SCART */
 		break;
 	case MSP_MODE_FM_RADIO:
-		v4l_dbg(1, msp_debug, client, "FM-Radio setstereo: %s\n",strmode[mode]);
+		v4l_dbg(1, msp_debug, client, "FM-Radio set_audmode: %s\n",modestr);
 		break;
 	default:
-		v4l_dbg(1, msp_debug, client, "mono setstereo\n");
+		v4l_dbg(1, msp_debug, client, "mono set_audmode\n");
 		return;
 	}
 
 	/* switch audio */
-	switch (mode) {
+	switch (state->audmode) {
 	case V4L2_TUNER_MODE_STEREO:
-		src = 0x0020 | nicam;
+		src |= 0x0020;
 		break;
 	case V4L2_TUNER_MODE_MONO:
 		if (state->mode == MSP_MODE_AM_NICAM) {
@@ -297,29 +304,22 @@
 			src = 0x0200;
 			break;
 		}
+		if (state->rxsubchans & V4L2_TUNER_SUB_STEREO)
+			src = 0x0030;
+		break;
 	case V4L2_TUNER_MODE_LANG1:
-		src = 0x0000 | nicam;
+		/* switch to stereo for stereo transmission, otherwise
+		   keep first language */
+		if (state->rxsubchans & V4L2_TUNER_SUB_STEREO)
+			src |= 0x0020;
 		break;
 	case V4L2_TUNER_MODE_LANG2:
-		src = 0x0010 | nicam;
+		src |= 0x0010;
 		break;
 	}
-	v4l_dbg(1, msp_debug, client, "setstereo final source/matrix = 0x%x\n", src);
+	v4l_dbg(1, msp_debug, client, "set_audmode final source/matrix = 0x%x\n", src);
 
-	if (msp_dolby) {
-		msp_write_dsp(client, 0x0008, 0x0520);
-		msp_write_dsp(client, 0x0009, 0x0620);
-		msp_write_dsp(client, 0x000a, src);
-		msp_write_dsp(client, 0x000b, src);
-	} else {
-		msp_write_dsp(client, 0x0008, src);
-		msp_write_dsp(client, 0x0009, src);
-		msp_write_dsp(client, 0x000a, src);
-		msp_write_dsp(client, 0x000b, src);
-		msp_write_dsp(client, 0x000c, src);
-		if (state->has_scart23_in_scart2_out)
-			msp_write_dsp(client, 0x0041, src);
-	}
+	msp_set_source(client, src);
 }
 
 static void msp3400c_print_mode(struct i2c_client *client)
@@ -347,12 +347,12 @@
 
 /* ----------------------------------------------------------------------- */
 
-int autodetect_stereo(struct i2c_client *client)
+static int msp3400c_detect_stereo(struct i2c_client *client)
 {
 	struct msp_state *state = i2c_get_clientdata(client);
 	int val;
 	int rxsubchans = state->rxsubchans;
-	int newnicam   = state->nicam_on;
+	int newnicam = state->nicam_on;
 	int update = 0;
 
 	switch (state->mode) {
@@ -362,7 +362,7 @@
 			val -= 65536;
 		v4l_dbg(2, msp_debug, client, "stereo detect register: %d\n", val);
 		if (val > 4096) {
-			rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
+			rxsubchans = V4L2_TUNER_SUB_STEREO;
 		} else if (val < -4096) {
 			rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
 		} else {
@@ -386,14 +386,11 @@
 				break;
 			case 1:
 			case 9:
-				rxsubchans = V4L2_TUNER_SUB_MONO
-					| V4L2_TUNER_SUB_LANG1;
+				rxsubchans = V4L2_TUNER_SUB_MONO;
 				break;
 			case 2:
 			case 10:
-				rxsubchans = V4L2_TUNER_SUB_MONO
-					| V4L2_TUNER_SUB_LANG1
-					| V4L2_TUNER_SUB_LANG2;
+				rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
 				break;
 			default:
 				rxsubchans = V4L2_TUNER_SUB_MONO;
@@ -405,30 +402,17 @@
 			rxsubchans = V4L2_TUNER_SUB_MONO;
 		}
 		break;
-	case MSP_MODE_BTSC:
-		val = msp_read_dem(client, 0x200);
-		v4l_dbg(2, msp_debug, client, "status=0x%x (pri=%s, sec=%s, %s%s%s)\n",
-			val,
-			(val & 0x0002) ? "no"     : "yes",
-			(val & 0x0004) ? "no"     : "yes",
-			(val & 0x0040) ? "stereo" : "mono",
-			(val & 0x0080) ? ", nicam 2nd mono" : "",
-			(val & 0x0100) ? ", bilingual/SAP"  : "");
-		rxsubchans = V4L2_TUNER_SUB_MONO;
-		if (val & 0x0040) rxsubchans |= V4L2_TUNER_SUB_STEREO;
-		if (val & 0x0100) rxsubchans |= V4L2_TUNER_SUB_LANG1;
-		break;
 	}
 	if (rxsubchans != state->rxsubchans) {
 		update = 1;
-		v4l_dbg(1, msp_debug, client, "watch: rxsubchans %d => %d\n",
-			state->rxsubchans,rxsubchans);
+		v4l_dbg(1, msp_debug, client, "watch: rxsubchans %02x => %02x\n",
+			state->rxsubchans, rxsubchans);
 		state->rxsubchans = rxsubchans;
 	}
 	if (newnicam != state->nicam_on) {
 		update = 1;
 		v4l_dbg(1, msp_debug, client, "watch: nicam %d => %d\n",
-			state->nicam_on,newnicam);
+			state->nicam_on, newnicam);
 		state->nicam_on = newnicam;
 	}
 	return update;
@@ -443,13 +427,8 @@
 {
 	struct msp_state *state = i2c_get_clientdata(client);
 
-	if (autodetect_stereo(client)) {
-		if (state->rxsubchans & V4L2_TUNER_SUB_STEREO)
-			msp3400c_setstereo(client, V4L2_TUNER_MODE_STEREO);
-		else if (state->rxsubchans & V4L2_TUNER_SUB_LANG1)
-			msp3400c_setstereo(client, V4L2_TUNER_MODE_LANG1);
-		else
-			msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
+	if (msp3400c_detect_stereo(client)) {
+		msp3400c_set_audmode(client);
 	}
 
 	if (msp_once)
@@ -461,7 +440,7 @@
 	struct i2c_client *client = data;
 	struct msp_state *state = i2c_get_clientdata(client);
 	struct msp3400c_carrier_detect *cd;
-	int count, max1,max2,val1,val2, val,this;
+	int count, max1, max2, val1, val2, val, this;
 
 
 	v4l_dbg(1, msp_debug, client, "msp3400 daemon started\n");
@@ -471,7 +450,7 @@
 		v4l_dbg(2, msp_debug, client, "msp3400 thread: wakeup\n");
 
 	restart:
-		v4l_dbg(1, msp_debug, client, "thread: restart scan\n");
+		v4l_dbg(2, msp_debug, client, "thread: restart scan\n");
 		state->restart = 0;
 		if (kthread_should_stop())
 			break;
@@ -485,13 +464,14 @@
 
 		/* mute */
 		msp_set_mute(client);
-		msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ );
+		msp3400c_set_mode(client, MSP_MODE_AM_DETECT /* +1 */ );
 		val1 = val2 = 0;
 		max1 = max2 = -1;
 		state->watch_stereo = 0;
+		state->nicam_on = 0;
 
 		/* some time for the tuner to sync */
-		if (msp_sleep(state,200))
+		if (msp_sleep(state, 200))
 			goto restart;
 
 		/* carrier detect pass #1 -- main carrier */
@@ -506,7 +486,7 @@
 		}
 
 		for (this = 0; this < count; this++) {
-			msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);
+			msp3400c_set_carrier(client, cd[this].cdo, cd[this].cdo);
 			if (msp_sleep(state,100))
 				goto restart;
 			val = msp_read_dsp(client, 0x1b);
@@ -542,7 +522,7 @@
 			max2 = 0;
 		}
 		for (this = 0; this < count; this++) {
-			msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);
+			msp3400c_set_carrier(client, cd[this].cdo, cd[this].cdo);
 			if (msp_sleep(state,100))
 				goto restart;
 			val = msp_read_dsp(client, 0x1b);
@@ -554,22 +534,20 @@
 		}
 
 		/* program the msp3400 according to the results */
-		state->main   = msp3400c_carrier_detect_main[max1].cdo;
+		state->main = msp3400c_carrier_detect_main[max1].cdo;
 		switch (max1) {
 		case 1: /* 5.5 */
 			if (max2 == 0) {
 				/* B/G FM-stereo */
 				state->second = msp3400c_carrier_detect_55[max2].cdo;
-				msp3400c_setmode(client, MSP_MODE_FM_TERRA);
-				state->nicam_on = 0;
-				msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
+				msp3400c_set_mode(client, MSP_MODE_FM_TERRA);
 				state->watch_stereo = 1;
 			} else if (max2 == 1 && state->has_nicam) {
 				/* B/G NICAM */
 				state->second = msp3400c_carrier_detect_55[max2].cdo;
-				msp3400c_setmode(client, MSP_MODE_FM_NICAM1);
+				msp3400c_set_mode(client, MSP_MODE_FM_NICAM1);
+				msp3400c_set_carrier(client, state->second, state->main);
 				state->nicam_on = 1;
-				msp3400c_setcarrier(client, state->second, state->main);
 				state->watch_stereo = 1;
 			} else {
 				goto no_second;
@@ -578,35 +556,31 @@
 		case 2: /* 6.0 */
 			/* PAL I NICAM */
 			state->second = MSP_CARRIER(6.552);
-			msp3400c_setmode(client, MSP_MODE_FM_NICAM2);
+			msp3400c_set_mode(client, MSP_MODE_FM_NICAM2);
+			msp3400c_set_carrier(client, state->second, state->main);
 			state->nicam_on = 1;
-			msp3400c_setcarrier(client, state->second, state->main);
 			state->watch_stereo = 1;
 			break;
 		case 3: /* 6.5 */
 			if (max2 == 1 || max2 == 2) {
 				/* D/K FM-stereo */
 				state->second = msp3400c_carrier_detect_65[max2].cdo;
-				msp3400c_setmode(client, MSP_MODE_FM_TERRA);
-				state->nicam_on = 0;
-				msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
+				msp3400c_set_mode(client, MSP_MODE_FM_TERRA);
 				state->watch_stereo = 1;
 			} else if (max2 == 0 && (state->v4l2_std & V4L2_STD_SECAM)) {
 				/* L NICAM or AM-mono */
 				state->second = msp3400c_carrier_detect_65[max2].cdo;
-				msp3400c_setmode(client, MSP_MODE_AM_NICAM);
-				state->nicam_on = 0;
-				msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
-				msp3400c_setcarrier(client, state->second, state->main);
+				msp3400c_set_mode(client, MSP_MODE_AM_NICAM);
+				msp3400c_set_carrier(client, state->second, state->main);
 				/* volume prescale for SCART (AM mono input) */
 				msp_write_dsp(client, 0x000d, 0x1900);
 				state->watch_stereo = 1;
 			} else if (max2 == 0 && state->has_nicam) {
 				/* D/K NICAM */
 				state->second = msp3400c_carrier_detect_65[max2].cdo;
-				msp3400c_setmode(client, MSP_MODE_FM_NICAM1);
+				msp3400c_set_mode(client, MSP_MODE_FM_NICAM1);
+				msp3400c_set_carrier(client, state->second, state->main);
 				state->nicam_on = 1;
-				msp3400c_setcarrier(client, state->second, state->main);
 				state->watch_stereo = 1;
 			} else {
 				goto no_second;
@@ -616,23 +590,25 @@
 		default:
 		no_second:
 			state->second = msp3400c_carrier_detect_main[max1].cdo;
-			msp3400c_setmode(client, MSP_MODE_FM_TERRA);
-			state->nicam_on = 0;
-			msp3400c_setcarrier(client, state->second, state->main);
+			msp3400c_set_mode(client, MSP_MODE_FM_TERRA);
+			msp3400c_set_carrier(client, state->second, state->main);
 			state->rxsubchans = V4L2_TUNER_SUB_MONO;
-			msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
 			break;
 		}
 
 		/* unmute */
 		msp_set_audio(client);
+		msp3400c_set_audmode(client);
 
 		if (msp_debug)
 			msp3400c_print_mode(client);
 
-		/* monitor tv audio mode */
+		/* monitor tv audio mode, the first time don't wait
+		   so long to get a quick stereo/bilingual result */
+		if (msp_sleep(state, 1000))
+			goto restart;
 		while (state->watch_stereo) {
-			if (msp_sleep(state,5000))
+			if (msp_sleep(state, 5000))
 				goto restart;
 			watch_stereo(client);
 		}
@@ -656,7 +632,7 @@
 		v4l_dbg(2, msp_debug, client, "msp3410 thread: wakeup\n");
 
 	restart:
-		v4l_dbg(1, msp_debug, client, "thread: restart scan\n");
+		v4l_dbg(2, msp_debug, client, "thread: restart scan\n");
 		state->restart = 0;
 		if (kthread_should_stop())
 			break;
@@ -681,9 +657,10 @@
 		else
 			std = (state->v4l2_std & V4L2_STD_NTSC) ? 0x20 : 1;
 		state->watch_stereo = 0;
+		state->nicam_on = 0;
 
 		if (msp_debug)
-			v4l_dbg(1, msp_debug, client, "setting standard: %s (0x%04x)\n",
+			v4l_dbg(2, msp_debug, client, "setting standard: %s (0x%04x)\n",
 			       msp_standard_std_name(std), std);
 
 		if (std != 1) {
@@ -700,7 +677,7 @@
 				val = msp_read_dem(client, 0x7e);
 				if (val < 0x07ff)
 					break;
-				v4l_dbg(1, msp_debug, client, "detection still in progress\n");
+				v4l_dbg(2, msp_debug, client, "detection still in progress\n");
 			}
 		}
 		for (i = 0; msp_stdlist[i].name != NULL; i++)
@@ -739,48 +716,34 @@
 			state->rxsubchans = V4L2_TUNER_SUB_STEREO;
 			state->nicam_on = 1;
 			state->watch_stereo = 1;
-			msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);
 			break;
 		case 0x0009:
 			state->mode = MSP_MODE_AM_NICAM;
 			state->rxsubchans = V4L2_TUNER_SUB_MONO;
 			state->nicam_on = 1;
-			msp3400c_setstereo(client,V4L2_TUNER_MODE_MONO);
 			state->watch_stereo = 1;
 			break;
 		case 0x0020: /* BTSC */
-			/* just turn on stereo */
+			/* The pre-'G' models only have BTSC-mono */
 			state->mode = MSP_MODE_BTSC;
-			state->rxsubchans = V4L2_TUNER_SUB_STEREO;
-			state->nicam_on = 0;
-			state->watch_stereo = 1;
-			msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);
+			state->rxsubchans = V4L2_TUNER_SUB_MONO;
 			break;
 		case 0x0040: /* FM radio */
 			state->mode = MSP_MODE_FM_RADIO;
 			state->rxsubchans = V4L2_TUNER_SUB_STEREO;
-			state->audmode = V4L2_TUNER_MODE_STEREO;
-			state->nicam_on = 0;
-			state->watch_stereo = 0;
 			/* not needed in theory if we have radio, but
 			   short programming enables carrier mute */
-			msp3400c_setmode(client, MSP_MODE_FM_RADIO);
-			msp3400c_setcarrier(client, MSP_CARRIER(10.7),
+			msp3400c_set_mode(client, MSP_MODE_FM_RADIO);
+			msp3400c_set_carrier(client, MSP_CARRIER(10.7),
 					    MSP_CARRIER(10.7));
-			/* scart routing */
+			/* scart routing (this doesn't belong here I think) */
 			msp_set_scart(client,SCART_IN2,0);
-			/* msp34xx does radio decoding */
-			msp_write_dsp(client, 0x08, 0x0020);
-			msp_write_dsp(client, 0x09, 0x0020);
-			msp_write_dsp(client, 0x0b, 0x0020);
 			break;
 		case 0x0003:
 		case 0x0004:
 		case 0x0005:
 			state->mode = MSP_MODE_FM_TERRA;
 			state->rxsubchans = V4L2_TUNER_SUB_MONO;
-			state->audmode = V4L2_TUNER_MODE_MONO;
-			state->nicam_on = 0;
 			state->watch_stereo = 1;
 			break;
 		}
@@ -791,11 +754,16 @@
 		if (state->has_i2s_conf)
 			msp_write_dem(client, 0x40, state->i2s_mode);
 
-		/* monitor tv audio mode */
+		msp3400c_set_audmode(client);
+
+		/* monitor tv audio mode, the first time don't wait
+		   so long to get a quick stereo/bilingual result */
+		if (msp_sleep(state, 1000))
+			goto restart;
 		while (state->watch_stereo) {
-			if (msp_sleep(state,5000))
-				goto restart;
 			watch_stereo(client);
+			if (msp_sleep(state, 5000))
+				goto restart;
 		}
 	}
 	v4l_dbg(1, msp_debug, client, "thread: exit\n");
@@ -813,7 +781,7 @@
  * the value for source is the same as bit 15:8 of DSP registers 0x08,
  * 0x0a and 0x0c: 0=mono, 1=stereo or A|B, 2=SCART, 3=stereo or A, 4=stereo or B
  *
- * this function replaces msp3400c_setstereo
+ * this function replaces msp3400c_set_audmode
  */
 static void msp34xxg_set_source(struct i2c_client *client, int source)
 {
@@ -826,12 +794,7 @@
 	int value = (source & 0x07) << 8 | (source == 0 ? 0x30 : 0x20);
 
 	v4l_dbg(1, msp_debug, client, "set source to %d (0x%x)\n", source, value);
-	/* Loudspeaker Output */
-	msp_write_dsp(client, 0x08, value);
-	/* SCART1 DA Output */
-	msp_write_dsp(client, 0x0a, value);
-	/* Quasi-peak detector */
-	msp_write_dsp(client, 0x0c, value);
+	msp_set_source(client, value);
 	/*
 	 * set identification threshold. Personally, I
 	 * I set it to a higher value that the default
@@ -948,13 +911,14 @@
 		if (msp_write_dsp(client, 0x13, state->acb))
 			return -1;
 
-		msp_write_dem(client, 0x40, state->i2s_mode);
+		if (state->has_i2s_conf)
+			msp_write_dem(client, 0x40, state->i2s_mode);
 	}
 	v4l_dbg(1, msp_debug, client, "thread: exit\n");
 	return 0;
 }
 
-void msp34xxg_detect_stereo(struct i2c_client *client)
+static void msp34xxg_detect_stereo(struct i2c_client *client)
 {
 	struct msp_state *state = i2c_get_clientdata(client);
 
@@ -964,11 +928,11 @@
 
 	state->rxsubchans = 0;
 	if (is_stereo)
-		state->rxsubchans |= V4L2_TUNER_SUB_STEREO;
+		state->rxsubchans = V4L2_TUNER_SUB_STEREO;
 	else
-		state->rxsubchans |= V4L2_TUNER_SUB_MONO;
+		state->rxsubchans = V4L2_TUNER_SUB_MONO;
 	if (is_bilingual) {
-		state->rxsubchans |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+		state->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
 		/* I'm supposed to check whether it's SAP or not
 		 * and set only LANG2/SAP in this case. Yet, the MSP
 		 * does a lot of work to hide this and handle everything
@@ -980,12 +944,12 @@
 		status, is_stereo, is_bilingual, state->rxsubchans);
 }
 
-void msp34xxg_set_audmode(struct i2c_client *client, int audmode)
+static void msp34xxg_set_audmode(struct i2c_client *client)
 {
 	struct msp_state *state = i2c_get_clientdata(client);
 	int source;
 
-	switch (audmode) {
+	switch (state->audmode) {
 	case V4L2_TUNER_MODE_MONO:
 		source = 0; /* mono only */
 		break;
@@ -1000,11 +964,40 @@
 		source = 4; /* stereo or B */
 		break;
 	default:
-		audmode = 0;
 		source  = 1;
 		break;
 	}
-	state->audmode = audmode;
 	msp34xxg_set_source(client, source);
 }
 
+void msp_set_audmode(struct i2c_client *client)
+{
+	struct msp_state *state = i2c_get_clientdata(client);
+
+	switch (state->opmode) {
+	case OPMODE_MANUAL:
+	case OPMODE_AUTODETECT:
+		state->watch_stereo = 0;
+		msp3400c_set_audmode(client);
+		break;
+	case OPMODE_AUTOSELECT:
+		msp34xxg_set_audmode(client);
+		break;
+	}
+}
+
+void msp_detect_stereo(struct i2c_client *client)
+{
+	struct msp_state *state  = i2c_get_clientdata(client);
+
+	switch (state->opmode) {
+	case OPMODE_MANUAL:
+	case OPMODE_AUTODETECT:
+		msp3400c_detect_stereo(client);
+		break;
+	case OPMODE_AUTOSELECT:
+		msp34xxg_detect_stereo(client);
+		break;
+	}
+}
+
diff --git a/drivers/media/video/msp3400.h b/drivers/media/video/msp3400.h
index a9ac57d..6fb5c8c 100644
--- a/drivers/media/video/msp3400.h
+++ b/drivers/media/video/msp3400.h
@@ -104,14 +104,12 @@
 
 /* msp3400-kthreads.c */
 const char *msp_standard_std_name(int std);
-void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2);
-void msp3400c_setmode(struct i2c_client *client, int type);
-void msp3400c_setstereo(struct i2c_client *client, int mode);
-int autodetect_stereo(struct i2c_client *client);
+void msp_set_audmode(struct i2c_client *client);
+void msp_detect_stereo(struct i2c_client *client);
 int msp3400c_thread(void *data);
 int msp3410d_thread(void *data);
 int msp34xxg_thread(void *data);
-void msp34xxg_detect_stereo(struct i2c_client *client);
-void msp34xxg_set_audmode(struct i2c_client *client, int audmode);
+void msp3400c_set_mode(struct i2c_client *client, int mode);
+void msp3400c_set_carrier(struct i2c_client *client, int cdo1, int cdo2);
 
 #endif /* MSP3400_H */
diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
index 41715ca..eb3b318 100644
--- a/drivers/media/video/mxb.c
+++ b/drivers/media/video/mxb.c
@@ -1,11 +1,11 @@
 /*
     mxb - v4l2 driver for the Multimedia eXtension Board
-    
+
     Copyright (C) 1998-2006 Michael Hunold <michael@mihu.de>
 
     Visit http://www.mihu.de/linux/saa7146/mxb/
     for further details about this card.
-    
+
     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
@@ -35,12 +35,12 @@
 
 #define I2C_SAA7111 0x24
 
-#define MXB_BOARD_CAN_DO_VBI(dev)   (dev->revision != 0) 
+#define MXB_BOARD_CAN_DO_VBI(dev)   (dev->revision != 0)
 
 /* global variable */
 static int mxb_num = 0;
 
-/* initial frequence the tuner will be tuned to. 
+/* initial frequence the tuner will be tuned to.
    in verden (lower saxony, germany) 4148 is a
    channel called "phoenix" */
 static int freq = 4148;
@@ -55,7 +55,7 @@
 enum { TUNER, AUX1, AUX3, AUX3_YC };
 
 static struct v4l2_input mxb_inputs[MXB_INPUTS] = {
-	{ TUNER,	"Tuner",		V4L2_INPUT_TYPE_TUNER,	1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, 
+	{ TUNER,	"Tuner",		V4L2_INPUT_TYPE_TUNER,	1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
 	{ AUX1,		"AUX1",			V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
 	{ AUX3,		"AUX3 Composite",	V4L2_INPUT_TYPE_CAMERA,	4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
 	{ AUX3_YC,	"AUX3 S-Video",		V4L2_INPUT_TYPE_CAMERA,	4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
@@ -66,7 +66,7 @@
 static struct {
 	int hps_source;
 	int hps_sync;
-} input_port_selection[MXB_INPUTS] = { 	
+} input_port_selection[MXB_INPUTS] = {
 	{ SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
 	{ SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
 	{ SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
@@ -81,7 +81,7 @@
 /* these are the necessary input-output-pins for bringing one audio source
 (see above) to the CD-output */
 static struct tea6420_multiplex TEA6420_cd[MXB_AUDIOS+1][2] =
-		{ 
+		{
 		{{1,1,0},{1,1,0}},	/* Tuner */
 		{{5,1,0},{6,1,0}},	/* AUX 1 */
 		{{4,1,0},{6,1,0}},	/* AUX 2 */
@@ -122,8 +122,8 @@
 	{ VIDIOC_S_FREQUENCY, 	SAA7146_EXCLUSIVE },
 	{ VIDIOC_G_AUDIO, 	SAA7146_EXCLUSIVE },
 	{ VIDIOC_S_AUDIO, 	SAA7146_EXCLUSIVE },
-	{ MXB_S_AUDIO_CD, 	SAA7146_EXCLUSIVE },	/* custom control */	
-	{ MXB_S_AUDIO_LINE, 	SAA7146_EXCLUSIVE },	/* custom control */	
+	{ MXB_S_AUDIO_CD, 	SAA7146_EXCLUSIVE },	/* custom control */
+	{ MXB_S_AUDIO_LINE, 	SAA7146_EXCLUSIVE },	/* custom control */
 	{ 0,			0 }
 };
 
@@ -132,7 +132,7 @@
 	struct video_device	*video_dev;
 	struct video_device	*vbi_dev;
 
-	struct i2c_adapter	i2c_adapter;	
+	struct i2c_adapter	i2c_adapter;
 
 	struct i2c_client*	saa7111a;
 	struct i2c_client*	tda9840;
@@ -200,15 +200,15 @@
 		client = list_entry(item, struct i2c_client, list);
 		if( I2C_TEA6420_1 == client->addr )
 			mxb->tea6420_1 = client;
-		if( I2C_TEA6420_2 == client->addr ) 
+		if( I2C_TEA6420_2 == client->addr )
 			mxb->tea6420_2 = client;
-		if( I2C_TEA6415C_2 == client->addr ) 
+		if( I2C_TEA6415C_2 == client->addr )
 			mxb->tea6415c = client;
-		if( I2C_TDA9840 == client->addr ) 
+		if( I2C_TDA9840 == client->addr )
 			mxb->tda9840 = client;
 		if( I2C_SAA7111 == client->addr )
 			mxb->saa7111a = client;
-		if( 0x60 == client->addr ) 
+		if( 0x60 == client->addr )
 			mxb->tuner = client;
 	}
 
@@ -222,7 +222,7 @@
 		return -ENODEV;
 	}
 
-	/* all devices are present, probe was successful */	
+	/* all devices are present, probe was successful */
 
 	/* we store the pointer in our private data field */
 	dev->ext_priv = mxb;
@@ -230,7 +230,7 @@
 	return 0;
 }
 
-/* some init data for the saa7740, the so-called 'sound arena module'. 
+/* some init data for the saa7740, the so-called 'sound arena module'.
    there are no specs available, so we simply use some init values */
 static struct {
 	int	length;
@@ -330,7 +330,7 @@
 	v4l2_std_id std = V4L2_STD_PAL_BG;
 
 	int i = 0, err = 0;
-	struct	tea6415c_multiplex vm;	
+	struct	tea6415c_multiplex vm;
 
 	/* select video mode in saa7111a */
 	i = VIDEO_MODE_PAL;
@@ -380,16 +380,16 @@
 	vm.in  = 3;
 	vm.out = 13;
 	mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm);
-				
+
 	/* the rest for mxb */
 	mxb->cur_input = 0;
 	mxb->cur_mute = 1;
 
 	mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
 	mxb->tda9840->driver->command(mxb->tda9840, TDA9840_SWITCH, &mxb->cur_mode);
-			
+
 	/* check if the saa7740 (aka 'sound arena module') is present
-	   on the mxb. if so, we must initialize it. due to lack of 
+	   on the mxb. if so, we must initialize it. due to lack of
 	   informations about the saa7740, the values were reverse
 	   engineered. */
 	msg.addr = 0x1b;
@@ -409,7 +409,7 @@
 				break;
 			}
 
-			msg.len = mxb_saa7740_init[i].length;		
+			msg.len = mxb_saa7740_init[i].length;
 			msg.buf = &mxb_saa7740_init[i].data[0];
 			if( 1 != (err = i2c_transfer(&mxb->i2c_adapter, &msg, 1))) {
 				DEB_D(("failed to initialize 'sound arena module'.\n"));
@@ -418,12 +418,12 @@
 		}
 		INFO(("'sound arena module' detected.\n"));
 	}
-err:	
+err:
 	/* the rest for saa7146: you should definitely set some basic values
 	   for the input-port handling of the saa7146. */
 
 	/* ext->saa has been filled by the core driver */
-	   
+
 	/* some stuff is done via variables */
 	saa7146_set_hps_source_and_sync(dev, input_port_selection[mxb->cur_input].hps_source, input_port_selection[mxb->cur_input].hps_sync);
 
@@ -431,7 +431,7 @@
 
 	/* this is ugly, but because of the fact that this is completely
 	   hardware dependend, it should be done directly... */
-      	saa7146_write(dev, DD1_STREAM_B,	0x00000000);
+	saa7146_write(dev, DD1_STREAM_B,	0x00000000);
 	saa7146_write(dev, DD1_INIT,		0x02000200);
 	saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
 
@@ -453,7 +453,7 @@
 static int mxb_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
 {
 	struct mxb* mxb = (struct mxb*)dev->ext_priv;
-	
+
 	DEB_EE(("dev:%p\n",dev));
 
 	/* checking for i2c-devices can be omitted here, because we
@@ -464,7 +464,7 @@
 		ERR(("cannot register capture v4l2 device. skipping.\n"));
 		return -1;
 	}
-	
+
 	/* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
 	if( 0 != MXB_BOARD_CAN_DO_VBI(dev)) {
 		if( 0 != saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) {
@@ -513,17 +513,17 @@
 	return 0;
 }
 
-static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) 
+static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
 {
 	struct saa7146_dev *dev = fh->dev;
 	struct mxb* mxb = (struct mxb*)dev->ext_priv;
-	struct saa7146_vv *vv = dev->vv_data; 
-	
+	struct saa7146_vv *vv = dev->vv_data;
+
 	switch(cmd) {
 	case VIDIOC_ENUMINPUT:
 	{
 		struct v4l2_input *i = arg;
-		
+
 		DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index));
 		if( i->index < 0 || i->index >= MXB_INPUTS) {
 			return -EINVAL;
@@ -559,11 +559,11 @@
 				break;
 			}
 		}
-		
+
 		if( i < 0 ) {
 			return -EAGAIN;
 		}
-			
+
 		switch (vc->id ) {
 			case V4L2_CID_AUDIO_MUTE: {
 				vc->value = mxb->cur_mute;
@@ -571,7 +571,7 @@
 				return 0;
 			}
 		}
-		
+
 		DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n",vc->value));
 		return 0;
 	}
@@ -580,17 +580,17 @@
 	{
 		struct	v4l2_control	*vc = arg;
 		int i = 0;
-		
+
 		for (i = MAXCONTROLS - 1; i >= 0; i--) {
 			if (mxb_controls[i].id == vc->id) {
 				break;
 			}
 		}
-		
+
 		if( i < 0 ) {
 			return -EAGAIN;
 		}
-		
+
 		switch (vc->id ) {
 			case V4L2_CID_AUDIO_MUTE: {
 				mxb->cur_mute = vc->value;
@@ -614,12 +614,12 @@
 		*input = mxb->cur_input;
 
 		DEB_EE(("VIDIOC_G_INPUT %d.\n",*input));
-		return 0;		
-	}	
+		return 0;
+	}
 	case VIDIOC_S_INPUT:
 	{
 		int input = *(int *)arg;
-		struct	tea6415c_multiplex vm;	
+		struct	tea6415c_multiplex vm;
 		int i = 0;
 
 		DEB_EE(("VIDIOC_S_INPUT %d.\n",input));
@@ -627,34 +627,34 @@
 		if (input < 0 || input >= MXB_INPUTS) {
 			return -EINVAL;
 		}
-		
+
 		/* fixme: locke das setzen des inputs mit hilfe des mutexes
-		down(&dev->lock);
+		mutex_lock(&dev->lock);
 		video_mux(dev,*i);
-		up(&dev->lock);
+		mutex_unlock(&dev->lock);
 		*/
-				
+
 		/* fixme: check if streaming capture
 		if ( 0 != dev->streaming ) {
 			DEB_D(("VIDIOC_S_INPUT illegal while streaming.\n"));
 			return -EPERM;
 		}
 		*/
-		
+
 		mxb->cur_input = input;
-	
+
 		saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, input_port_selection[input].hps_sync);
-		
+
 		/* prepare switching of tea6415c and saa7111a;
 		   have a look at the 'background'-file for further informations  */
 		switch( input ) {
-			
+
 			case TUNER:
 			{
 				i = 0;
 				vm.in  = 3;
 				vm.out = 17;
-								
+
 			if ( 0 != mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm)) {
 					printk("VIDIOC_S_INPUT: could not address tea6415c #1\n");
 					return -EFAULT;
@@ -662,7 +662,7 @@
 				/* connect tuner-output always to multicable */
 				vm.in  = 3;
 				vm.out = 13;
-				break;				
+				break;
 			}
 			case AUX3_YC:
 			{
@@ -703,11 +703,11 @@
 				break;
 			}
 		}
-				
+
 		/* switch video in saa7111a */
 		if ( 0 != mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_INPUT, &i)) {
 			printk("VIDIOC_S_INPUT: could not address saa7111a #1.\n");
-		}			
+		}
 
 		/* switch the audio-source only if necessary */
 		if( 0 == mxb->cur_mute ) {
@@ -738,11 +738,11 @@
 		t->rangehigh = 13684;	/* 855.25 MHz / 62.5 kHz = 13684 */
 		/* FIXME: add the real signal strength here */
 		t->signal = 0xffff;
-		t->afc = 0;		
+		t->afc = 0;
 
 		mxb->tda9840->driver->command(mxb->tda9840,TDA9840_DETECT, &byte);
 		t->audmode = mxb->cur_mode;
-		
+
 		if( byte < 0 ) {
 			t->rxsubchans  = V4L2_TUNER_SUB_MONO;
 		} else {
@@ -777,12 +777,12 @@
 		struct v4l2_tuner *t = arg;
 		int result = 0;
 		int byte = 0;
-		
+
 		if( 0 != t->index ) {
 			DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n",t->index));
 			return -EINVAL;
 		}
-	
+
 		switch(t->audmode) {
 			case V4L2_TUNER_MODE_STEREO: {
 				mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
@@ -813,7 +813,7 @@
 		if( 0 != (result = mxb->tda9840->driver->command(mxb->tda9840, TDA9840_SWITCH, &byte))) {
 			printk("VIDIOC_S_TUNER error. result:%d, byte:%d\n",result,byte);
 		}
-				
+
 		return 0;
 	}
 	case VIDIOC_G_FREQUENCY:
@@ -839,7 +839,7 @@
 
 		if (V4L2_TUNER_ANALOG_TV != f->type)
 			return -EINVAL;
-		
+
 		if(0 != mxb->cur_input) {
 			DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n",mxb->cur_input));
 			return -EINVAL;
@@ -848,7 +848,7 @@
 		mxb->cur_freq = *f;
 		DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency));
 
-		/* tune in desired frequency */			
+		/* tune in desired frequency */
 		mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY, &mxb->cur_freq);
 
 		/* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */
@@ -861,12 +861,12 @@
 	case MXB_S_AUDIO_CD:
 	{
 		int i = *(int*)arg;
-				
+
 		if( i < 0 || i >= MXB_AUDIOS ) {
 			DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n",i));
 			return -EINVAL;
 		}
-		
+
 		DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n",i));
 
 		mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[i][0]);
@@ -877,12 +877,12 @@
 	case MXB_S_AUDIO_LINE:
 	{
 		int i = *(int*)arg;
-				
+
 		if( i < 0 || i >= MXB_AUDIOS ) {
 			DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n",i));
 			return -EINVAL;
 		}
-		
+
 		DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n",i));
 		mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[i][0]);
 		mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[i][1]);
@@ -894,13 +894,13 @@
 		struct v4l2_audio *a = arg;
 
 		if( a->index < 0 || a->index > MXB_INPUTS ) {
-	 		DEB_D(("VIDIOC_G_AUDIO %d out of range.\n",a->index));
+			DEB_D(("VIDIOC_G_AUDIO %d out of range.\n",a->index));
 			return -EINVAL;
 		}
-		
- 		DEB_EE(("VIDIOC_G_AUDIO %d.\n",a->index));
+
+		DEB_EE(("VIDIOC_G_AUDIO %d.\n",a->index));
 		memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio));
-		
+
 		return 0;
 	}
 	case VIDIOC_S_AUDIO:
@@ -908,7 +908,7 @@
 		struct v4l2_audio *a = arg;
 		DEB_D(("VIDIOC_S_AUDIO %d.\n",a->index));
 		return 0;
-	}	
+	}
 	default:
 /*
 		DEB2(printk("does not handle this ioctl.\n"));
@@ -928,7 +928,7 @@
 		v4l2_std_id std = V4L2_STD_PAL_I;
 		DEB_D(("VIDIOC_S_STD: setting mxb for PAL_I.\n"));
 		/* set the 7146 gpio register -- I don't know what this does exactly */
-      		saa7146_write(dev, GPIO_CTRL, 0x00404050);
+		saa7146_write(dev, GPIO_CTRL, 0x00404050);
 		/* unset the 7111 gpio register -- I don't know what this does exactly */
 		mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &zero);
 		mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
@@ -936,7 +936,7 @@
 		v4l2_std_id std = V4L2_STD_PAL_BG;
 		DEB_D(("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM.\n"));
 		/* set the 7146 gpio register -- I don't know what this does exactly */
-      		saa7146_write(dev, GPIO_CTRL, 0x00404050);
+		saa7146_write(dev, GPIO_CTRL, 0x00404050);
 		/* set the 7111 gpio register -- I don't know what this does exactly */
 		mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &one);
 		mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
@@ -969,8 +969,8 @@
 };
 
 static struct saa7146_pci_extension_data mxb = {
-        .ext_priv = "Multimedia eXtension Board",
-        .ext = &extension,
+	.ext_priv = "Multimedia eXtension Board",
+	.ext = &extension,
 };
 
 static struct pci_device_id pci_tbl[] = {
@@ -992,7 +992,7 @@
 	.capabilities	= V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE,
 	.stds		= &standard[0],
 	.num_stds	= sizeof(standard)/sizeof(struct saa7146_standard),
-	.std_callback	= &std_callback, 
+	.std_callback	= &std_callback,
 	.ioctls		= &ioctls[0],
 	.ioctl		= mxb_ioctl,
 };
@@ -1000,7 +1000,7 @@
 static struct saa7146_extension extension = {
 	.name		= MXB_IDENTIFIER,
 	.flags		= SAA7146_USE_I2C_IRQ,
-	
+
 	.pci_tbl	= &pci_tbl[0],
 	.module		= THIS_MODULE,
 
@@ -1010,7 +1010,7 @@
 
 	.irq_mask	= 0,
 	.irq_func	= NULL,
-};	
+};
 
 static int __init mxb_init_module(void)
 {
@@ -1018,7 +1018,7 @@
 		DEB_S(("failed to register extension.\n"));
 		return -ENODEV;
 	}
-	
+
 	return 0;
 }
 
diff --git a/drivers/media/video/mxb.h b/drivers/media/video/mxb.h
index 2332ed5..400a57b 100644
--- a/drivers/media/video/mxb.h
+++ b/drivers/media/video/mxb.h
@@ -38,5 +38,5 @@
 		.name	= "CD-ROM (X10)",
 		.capability = V4L2_AUDCAP_STEREO,
 	}
-};	
+};
 #endif
diff --git a/drivers/media/video/planb.c b/drivers/media/video/planb.c
index f3fc361..15fd85a 100644
--- a/drivers/media/video/planb.c
+++ b/drivers/media/video/planb.c
@@ -48,7 +48,7 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <asm/irq.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #include "planb.h"
 #include "saa7196.h"
@@ -329,12 +329,12 @@
 
 static inline void planb_lock(struct planb *pb)
 {
-	down(&pb->lock);
+	mutex_lock(&pb->lock);
 }
 
 static inline void planb_unlock(struct planb *pb)
 {
-	up(&pb->lock);
+	mutex_unlock(&pb->lock);
 }
 
 /***************/
@@ -2067,7 +2067,7 @@
 #endif
 	pb->tab_size = PLANB_MAXLINES + 40;
 	pb->suspend = 0;
-	init_MUTEX(&pb->lock);
+	mutex_init(&pb->lock);
 	pb->ch1_cmd = 0;
 	pb->ch2_cmd = 0;
 	pb->mask = 0;
diff --git a/drivers/media/video/planb.h b/drivers/media/video/planb.h
index 8a0faad..79b6b56 100644
--- a/drivers/media/video/planb.h
+++ b/drivers/media/video/planb.h
@@ -174,7 +174,7 @@
 	int	user;
 	unsigned int tab_size;
 	int     maxlines;
-	struct semaphore lock;
+	struct mutex lock;
 	unsigned int	irq;			/* interrupt number */
 	volatile unsigned int intr_mask;
 
diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c
index 9e64486..05ca559 100644
--- a/drivers/media/video/pms.c
+++ b/drivers/media/video/pms.c
@@ -30,6 +30,8 @@
 #include <asm/io.h>
 #include <linux/sched.h>
 #include <linux/videodev.h>
+#include <linux/mutex.h>
+
 #include <asm/uaccess.h>
 
 
@@ -44,7 +46,7 @@
 	struct video_picture picture;
 	int height;
 	int width;
-	struct semaphore lock;
+	struct mutex lock;
 };
 
 struct i2c_info
@@ -724,10 +726,10 @@
 			struct video_channel *v = arg;
 			if(v->channel<0 || v->channel>3)
 				return -EINVAL;
-			down(&pd->lock);
+			mutex_lock(&pd->lock);
 			pms_videosource(v->channel&1);
 			pms_vcrinput(v->channel>>1);
-			up(&pd->lock);
+			mutex_unlock(&pd->lock);
 			return 0;
 		}
 		case VIDIOCGTUNER:
@@ -761,7 +763,7 @@
 			struct video_tuner *v = arg;
 			if(v->tuner)
 				return -EINVAL;
-			down(&pd->lock);
+			mutex_lock(&pd->lock);
 			switch(v->mode)
 			{
 				case VIDEO_MODE_AUTO:
@@ -785,10 +787,10 @@
 					pms_format(2);
 					break;
 				default:
-					up(&pd->lock);
+					mutex_unlock(&pd->lock);
 					return -EINVAL;
 			}
-			up(&pd->lock);
+			mutex_unlock(&pd->lock);
 			return 0;
 		}
 		case VIDIOCGPICT:
@@ -809,12 +811,12 @@
 			 *	Now load the card.
 			 */
 
-			down(&pd->lock);
+			mutex_lock(&pd->lock);
 			pms_brightness(p->brightness>>8);
 			pms_hue(p->hue>>8);
 			pms_colour(p->colour>>8);
 			pms_contrast(p->contrast>>8);	
-			up(&pd->lock);
+			mutex_unlock(&pd->lock);
 			return 0;
 		}
 		case VIDIOCSWIN:
@@ -830,9 +832,9 @@
 				return -EINVAL;
 			pd->width=vw->width;
 			pd->height=vw->height;
-			down(&pd->lock);
+			mutex_lock(&pd->lock);
 			pms_resolution(pd->width, pd->height);
-			up(&pd->lock);			/* Ok we figured out what to use from our wide choice */
+			mutex_unlock(&pd->lock);			/* Ok we figured out what to use from our wide choice */
 			return 0;
 		}
 		case VIDIOCGWIN:
@@ -872,9 +874,9 @@
 	struct pms_device *pd=(struct pms_device *)v;
 	int len;
 	
-	down(&pd->lock);
+	mutex_lock(&pd->lock);
 	len=pms_capture(pd, buf, (pd->picture.depth==16)?0:1,count);
-	up(&pd->lock);
+	mutex_unlock(&pd->lock);
 	return len;
 }
 
@@ -1029,7 +1031,7 @@
 		return -ENODEV;
 	}
 	memcpy(&pms_device, &pms_template, sizeof(pms_template));
-	init_MUTEX(&pms_device.lock);
+	mutex_init(&pms_device.lock);
 	pms_device.height=240;
 	pms_device.width=320;
 	pms_swsense(75);
diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c
index 2ce0102..dd830e0 100644
--- a/drivers/media/video/saa5246a.c
+++ b/drivers/media/video/saa5246a.c
@@ -46,6 +46,8 @@
 #include <linux/i2c.h>
 #include <linux/videotext.h>
 #include <linux/videodev.h>
+#include <linux/mutex.h>
+
 #include "saa5246a.h"
 
 MODULE_AUTHOR("Michael Geng <linux@MichaelGeng.de>");
@@ -57,7 +59,7 @@
 	u8     pgbuf[NUM_DAUS][VTX_VIRTUALSIZE];
 	int    is_searching[NUM_DAUS];
 	struct i2c_client *client;
-	struct semaphore lock;
+	struct mutex lock;
 };
 
 static struct video_device saa_template;	/* Declared near bottom */
@@ -90,7 +92,7 @@
 		return -ENOMEM;
 	}
 	strlcpy(client->name, IF_NAME, I2C_NAME_SIZE);
-	init_MUTEX(&t->lock);
+	mutex_init(&t->lock);
 
 	/*
 	 *	Now create a video4linux device
@@ -719,9 +721,9 @@
 	int err;
 
 	cmd = vtx_fix_command(cmd);
-	down(&t->lock);
+	mutex_lock(&t->lock);
 	err = video_usercopy(inode, file, cmd, arg, do_saa5246a_ioctl);
-	up(&t->lock);
+	mutex_unlock(&t->lock);
 	return err;
 }
 
diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
index 5694eb5..a9f3cf0 100644
--- a/drivers/media/video/saa5249.c
+++ b/drivers/media/video/saa5249.c
@@ -56,6 +56,8 @@
 #include <linux/i2c.h>
 #include <linux/videotext.h>
 #include <linux/videodev.h>
+#include <linux/mutex.h>
+
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -105,7 +107,7 @@
 	int disp_mode;
 	int virtual_mode;
 	struct i2c_client *client;
-	struct semaphore lock;
+	struct mutex lock;
 };
 
 
@@ -158,7 +160,7 @@
 		return -ENOMEM;
 	}
 	strlcpy(client->name, IF_NAME, I2C_NAME_SIZE);
-	init_MUTEX(&t->lock);
+	mutex_init(&t->lock);
 	
 	/*
 	 *	Now create a video4linux device
@@ -619,9 +621,9 @@
 	int err;
 	
 	cmd = vtx_fix_command(cmd);
-	down(&t->lock);
+	mutex_lock(&t->lock);
 	err = video_usercopy(inode,file,cmd,arg,do_saa5249_ioctl);
-	up(&t->lock);
+	mutex_unlock(&t->lock);
 	return err;
 }
 
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index ffd87ce..b184fd0 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -1,4 +1,4 @@
-/* saa7115 - Philips SAA7114/SAA7115 video decoder driver
+/* saa7115 - Philips SAA7113/SAA7114/SAA7115 video decoder driver
  *
  * Based on saa7114 driver by Maxim Yevtyushkin, which is based on
  * the saa7111 driver by Dave Perks.
@@ -16,6 +16,7 @@
  * (2/17/2003)
  *
  * VBI support (2004) and cleanups (2005) by Hans Verkuil <hverkuil@xs4all.nl>
+ * SAA7113 support by Mauro Carvalho Chehab <mchehab@infradead.org>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -42,8 +43,9 @@
 #include <media/audiochip.h>
 #include <asm/div64.h>
 
-MODULE_DESCRIPTION("Philips SAA7114/SAA7115 video decoder driver");
-MODULE_AUTHOR("Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, Hans Verkuil");
+MODULE_DESCRIPTION("Philips SAA7113/SAA7114/SAA7115 video decoder driver");
+MODULE_AUTHOR(  "Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, "
+		"Hans Verkuil, Mauro Carvalho Chehab");
 MODULE_LICENSE("GPL");
 
 static int debug = 0;
@@ -51,7 +53,10 @@
 
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-static unsigned short normal_i2c[] = { 0x42 >> 1, 0x40 >> 1, I2C_CLIENT_END };
+static unsigned short normal_i2c[] = {
+		0x4a >>1, 0x48 >>1,	/* SAA7113 */
+		0x42 >> 1, 0x40 >> 1,	/* SAA7114 and SAA7115 */
+		I2C_CLIENT_END };
 
 
 I2C_CLIENT_INSMOD;
@@ -101,10 +106,12 @@
    Hauppauge driver sets. */
 
 static const unsigned char saa7115_init_auto_input[] = {
+		/* Front-End Part */
 	0x01, 0x48,		/* white peak control disabled */
 	0x03, 0x20,		/* was 0x30. 0x20: long vertical blanking */
 	0x04, 0x90,		/* analog gain set to 0 */
 	0x05, 0x90,		/* analog gain set to 0 */
+		/* Decoder Part */
 	0x06, 0xeb,		/* horiz sync begin = -21 */
 	0x07, 0xe0,		/* horiz sync stop = -17 */
 	0x0a, 0x80,		/* was 0x88. decoder brightness, 0x80 is itu standard */
@@ -123,6 +130,8 @@
 	0x1b, 0x42,		/* misc chroma control 0x42 = recommended */
 	0x1c, 0xa9,		/* combfilter control 0xA9 = recommended */
 	0x1d, 0x01,		/* combfilter control 0x01 = recommended */
+
+		/* Power Device Control */
 	0x88, 0xd0,		/* reset device */
 	0x88, 0xf0,		/* set device programmed, all in operational mode */
 	0x00, 0x00
@@ -338,6 +347,33 @@
 	0x00, 0x00
 };
 
+static const unsigned char saa7113_init_auto_input[] = {
+	0x01, 0x08,	/* PH7113_INCREMENT_DELAY - (1) (1) (1) (1) IDEL3 IDEL2 IDELL1 IDEL0 */
+	0x02, 0xc2,	/* PH7113_ANALOG_INPUT_CONTR_1 - FUSE1 FUSE0 GUDL1 GUDL0 MODE3 MODE2 MODE1 MODE0 */
+	0x03, 0x30,	/* PH7113_ANALOG_INPUT_CONTR_2 - (1) HLNRS VBSL WPOFF HOLDG GAFIX GAI28 GAI18 */
+	0x04, 0x00,	/* PH7113_ANALOG_INPUT_CONTR_3 - GAI17 GAI16 GAI15 GAI14 GAI13 GAI12 GAI11 GAI10 */
+	0x05, 0x00,	/* PH7113_ANALOG_INPUT_CONTR_4 - GAI27 GAI26 GAI25 GAI24 GAI23 GAI22 GAI21 GAI20 */
+	0x06, 0x89,	/* PH7113_HORIZONTAL_SYNC_START - HSB7 HSB6 HSB5 HSB4 HSB3 HSB2 HSB1 HSB0 */
+	0x07, 0x0d,	/* PH7113_HORIZONTAL_SYNC_STOP - HSS7 HSS6 HSS5 HSS4 HSS3 HSS2 HSS1 HSS0 */
+	0x08, 0x88,	/* PH7113_SYNC_CONTROL - AUFD FSEL FOET HTC1 HTC0 HPLL VNOI1 VNOI0 */
+	0x09, 0x01,	/* PH7113_LUMINANCE_CONTROL - BYPS PREF BPSS1 BPSS0 VBLB UPTCV APER1 APER0 */
+	0x0a, 0x80,	/* PH7113_LUMINANCE_BRIGHTNESS - BRIG7 BRIG6 BRIG5 BRIG4 BRIG3 BRIG2 BRIG1 BRIG0 */
+	0x0b, 0x47,	/* PH7113_LUMINANCE_CONTRAST - CONT7 CONT6 CONT5 CONT4 CONT3 CONT2 CONT1 CONT0 */
+	0x0c, 0x40,	/* PH7113_CHROMA_SATURATION - SATN7 SATN6 SATN5 SATN4 SATN3 SATN2 SATN1 SATN0 */
+	0x0d, 0x00,	/* PH7113_CHROMA_HUE_CONTROL - HUEC7 HUEC6 HUEC5 HUEC4 HUEC3 HUEC2 HUEC1 HUEC0 */
+	0x0e, 0x01,	/* PH7113_CHROMA_CONTROL - CDTO CSTD2 CSTD1 CSTD0 DCCF FCTC CHBW1 CHBW0 */
+	0x0f, 0x2a,	/* PH7113_CHROMA_GAIN_CONTROL - ACGC CGAIN6 CGAIN5 CGAIN4 CGAIN3 CGAIN2 CGAIN1 CGAIN0 */
+	0x10, 0x08,	/* PH7113_FORMAT_DELAY_CONTROL - OFTS1 OFTS0 HDEL1 HDEL0 VRLN YDEL2 YDEL1 YDEL0 */
+	0x11, 0x0c,	/* PH7113_OUTPUT_CONTROL_1 - GPSW1 CM99 GPSW0 HLSEL OEYC OERT VIPB COLO */
+	0x12, 0x07,	/* PH7113_OUTPUT_CONTROL_2 - RTSE13 RTSE12 RTSE11 RTSE10 RTSE03 RTSE02 RTSE01 RTSE00 */
+	0x13, 0x00,	/* PH7113_OUTPUT_CONTROL_3 - ADLSB (1) (1) OLDSB FIDP (1) AOSL1 AOSL0 */
+	0x14, 0x00,	/* RESERVED 14 - (1) (1) (1) (1) (1) (1) (1) (1) */
+	0x15, 0x00,	/* PH7113_V_GATE1_START - VSTA7 VSTA6 VSTA5 VSTA4 VSTA3 VSTA2 VSTA1 VSTA0 */
+	0x16, 0x00,	/* PH7113_V_GATE1_STOP - VSTO7 VSTO6 VSTO5 VSTO4 VSTO3 VSTO2 VSTO1 VSTO0 */
+	0x17, 0x00,	/* PH7113_V_GATE1_MSB - (1) (1) (1) (1) (1) (1) VSTO8 VSTA8 */
+	0x00, 0x00
+};
+
 static const unsigned char saa7115_init_misc[] = {
 	0x38, 0x03,		/* audio stuff */
 	0x39, 0x10,
@@ -677,10 +713,35 @@
 		saa7115_writeregs(client, saa7115_cfg_50hz_video);
 	}
 
+	/* Register 0E - Bits D6-D4 on NO-AUTO mode
+		(SAA7113 doesn't have auto mode)
+	    50 Hz / 625 lines           60 Hz / 525 lines
+	000 PAL BGDHI (4.43Mhz)         NTSC M (3.58MHz)
+	001 NTSC 4.43 (50 Hz)           PAL 4.43 (60 Hz)
+	010 Combination-PAL N (3.58MHz) NTSC 4.43 (60 Hz)
+	011 NTSC N (3.58MHz)            PAL M (3.58MHz)
+	100 reserved                    NTSC-Japan (3.58MHz)
+	*/
+	if (state->ident == V4L2_IDENT_SAA7113) {
+		u8 reg =  saa7115_read(client, 0x0e) & 0x8f;
+
+		if (std == V4L2_STD_PAL_M) {
+			reg|=0x30;
+		} else if (std == V4L2_STD_PAL_N) {
+			reg|=0x20;
+		} else if (std == V4L2_STD_PAL_60) {
+			reg|=0x10;
+		} else if (std == V4L2_STD_NTSC_M_JP) {
+			reg|=0x40;
+		}
+		saa7115_write(client, 0x0e, reg);
+	}
+
+
 	state->std = std;
 
 	/* restart task B if needed */
-	if (taskb && state->ident == V4L2_IDENT_SAA7114) {
+	if (taskb && state->ident != V4L2_IDENT_SAA7115) {
 		saa7115_writeregs(client, saa7115_cfg_vbi_on);
 	}
 
@@ -703,7 +764,7 @@
 	int vcr;
 
 	v4l_info(client, "Audio frequency: %d Hz\n", state->audclk_freq);
-	if (client->name[6] == '4') {
+	if (state->ident != V4L2_IDENT_SAA7115) {
 		/* status for the saa7114 */
 		reg1f = saa7115_read(client, 0x1f);
 		signalOk = (reg1f & 0xc1) == 0x81;
@@ -751,8 +812,8 @@
 	u8 lcr[24];
 	int i, x;
 
-	/* saa7114 doesn't yet support VBI */
-	if (state->ident == V4L2_IDENT_SAA7114)
+	/* saa7113/71144 doesn't yet support VBI */
+	if (state->ident != V4L2_IDENT_SAA7115)
 		return;
 
 	for (i = 0; i <= 23; i++)
@@ -791,7 +852,7 @@
 					case 0:
 						lcr[i] |= 0xf << (4 * x);
 						break;
-					case V4L2_SLICED_TELETEXT_B:
+					case V4L2_SLICED_TELETEXT_PAL_B:
 						lcr[i] |= 1 << (4 * x);
 						break;
 					case V4L2_SLICED_CAPTION_525:
@@ -820,7 +881,7 @@
 static int saa7115_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
 {
 	static u16 lcr2vbi[] = {
-		0, V4L2_SLICED_TELETEXT_B, 0,	/* 1 */
+		0, V4L2_SLICED_TELETEXT_PAL_B, 0,	/* 1 */
 		0, V4L2_SLICED_CAPTION_525,	/* 4 */
 		V4L2_SLICED_WSS_625, 0,		/* 5 */
 		V4L2_SLICED_VPS, 0, 0, 0, 0,	/* 7 */
@@ -985,7 +1046,7 @@
 	/* decode payloads */
 	switch (id2) {
 	case 1:
-		vbi->type = V4L2_SLICED_TELETEXT_B;
+		vbi->type = V4L2_SLICED_TELETEXT_PAL_B;
 		break;
 	case 4:
 		if (!saa7115_odd_parity(p[0]) || !saa7115_odd_parity(p[1]))
@@ -1261,14 +1322,12 @@
 
 	saa7115_write(client, 0, 5);
 	chip_id = saa7115_read(client, 0) & 0x0f;
-	if (chip_id != 4 && chip_id != 5) {
+	if (chip_id <3 && chip_id > 5) {
 		v4l_dbg(1, debug, client, "saa7115 not found\n");
 		kfree(client);
 		return 0;
 	}
-	if (chip_id == 4) {
-		snprintf(client->name, sizeof(client->name) - 1, "saa7114");
-	}
+	snprintf(client->name, sizeof(client->name) - 1, "saa711%d",chip_id);
 	v4l_info(client, "saa711%d found @ 0x%x (%s)\n", chip_id, address << 1, adapter->name);
 
 	state = kzalloc(sizeof(struct saa7115_state), GFP_KERNEL);
@@ -1285,13 +1344,27 @@
 	state->contrast = 64;
 	state->hue = 0;
 	state->sat = 64;
-	state->ident = (chip_id == 4) ? V4L2_IDENT_SAA7114 : V4L2_IDENT_SAA7115;
+	switch (chip_id) {
+	case 3:
+		state->ident = V4L2_IDENT_SAA7113;
+		break;
+	case 4:
+		state->ident = V4L2_IDENT_SAA7114;
+		break;
+	default:
+		state->ident = V4L2_IDENT_SAA7115;
+		break;
+	}
+
 	state->audclk_freq = 48000;
 
 	v4l_dbg(1, debug, client, "writing init values\n");
 
 	/* init to 60hz/48khz */
-	saa7115_writeregs(client, saa7115_init_auto_input);
+	if (state->ident==V4L2_IDENT_SAA7113)
+		saa7115_writeregs(client, saa7113_init_auto_input);
+	else
+		saa7115_writeregs(client, saa7115_init_auto_input);
 	saa7115_writeregs(client, saa7115_init_misc);
 	saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
 	saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index 7df5e08..64e2c10 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -308,8 +308,7 @@
 
 static int dsp_buffer_free(struct saa7134_dev *dev)
 {
-	if (!dev->dmasound.blksize)
-		BUG();
+	BUG_ON(!dev->dmasound.blksize);
 
 	videobuf_dma_free(&dev->dmasound.dma);
 
@@ -611,12 +610,12 @@
 	struct saa7134_dev *dev = saa7134->dev;
 	int err;
 
-	down(&dev->dmasound.lock);
+	mutex_lock(&dev->dmasound.lock);
 
 	dev->dmasound.read_count  = 0;
 	dev->dmasound.read_offset = 0;
 
-	up(&dev->dmasound.lock);
+	mutex_unlock(&dev->dmasound.lock);
 
 	pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
 	if (pcm == NULL)
@@ -934,7 +933,7 @@
 
 	chip->irq = dev->pci->irq;
 
-	init_MUTEX(&dev->dmasound.lock);
+	mutex_init(&dev->dmasound.lock);
 
 	if ((err = snd_card_saa7134_new_mixer(chip)) < 0)
 		goto __nodev;
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 6bc63a4..fdd7f48 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -536,7 +536,7 @@
 		.radio = {
 			.name = name_radio,
 			.amux = LINE2,
-	},
+		},
 	},
 	[SAA7134_BOARD_MD7134] = {
 		.name           = "Medion 7134",
@@ -640,6 +640,32 @@
 			.tv   = 1,
 		}},
 	},
+	[SAA7134_BOARD_ELSA_700TV] = {
+		.name           = "ELSA EX-VISION 700TV",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_HITACHI_NTSC,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 4,
+			.amux = LINE2,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 6,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 7,
+			.amux = LINE1,
+		}},
+		.mute           = {
+			.name = name_mute,
+			.amux = TV,
+		},
+	},
 	[SAA7134_BOARD_ASUSTeK_TVFM7134] = {
 		.name           = "ASUS TV-FM 7134",
 		.audio_clock    = 0x00187de7,
@@ -2002,7 +2028,7 @@
 	[SAA7134_BOARD_FLYTV_DIGIMATRIX] = {
 		.name		= "FlyTV mini Asus Digimatrix",
 		.audio_clock	= 0x00200000,
-		.tuner_type	= TUNER_LG_NTSC_TALN_MINI,
+		.tuner_type	= TUNER_LG_TALN,
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
@@ -2598,6 +2624,7 @@
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
 		.gpiomask	= 0x00200000,
+		.mpeg           = SAA7134_MPEG_DVB,
 		.inputs         = {{
 			.name = name_tv,	/* Analog broadcast/cable TV */
 			.vmux = 1,
@@ -2623,6 +2650,164 @@
 			.gpio = 0x000000,	/* GPIO21=Low for FM radio antenna */
 		},
 	},
+	[SAA7134_BOARD_AVERMEDIA_777] = {
+		.name           = "AverTV DVB-T 777",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs = {{
+			.name   = name_comp1,
+			.vmux   = 0,
+			.amux   = LINE1,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE1,
+		}},
+	},
+	[SAA7134_BOARD_FLYDVBT_LR301] = {
+		/* LifeView FlyDVB-T */
+		/* Giampiero Giancipoli <gianci@libero.it> */
+		.name           = "LifeView FlyDVB-T",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs         = {{
+			.name = name_comp1,	/* Composite input */
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,	/* S-Video signal on S-Video input */
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+	},
+	[SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331] = {
+		.name           = "ADS Instant TV Duo Cardbus PTV331",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.gpiomask       = 0x00600000, /* Bit 21 0=Radio, Bit 22 0=TV */
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+			.gpio   = 0x00200000,
+		}},
+	},
+	[SAA7134_BOARD_TEVION_DVBT_220RF] = {
+		.name           = "Tevion/KWorld DVB-T 220RF",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 3,
+			.amux   = LINE1,
+		},{
+			.name   = name_svideo,
+			.vmux   = 0,
+			.amux   = LINE1,
+		}},
+		.radio = {
+			.name   = name_radio,
+			.amux   = LINE1,
+		},
+	},
+	[SAA7134_BOARD_KWORLD_ATSC110] = {
+		.name           = "Kworld ATSC110",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TUV1236D,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+	},
+	[SAA7134_BOARD_AVERMEDIA_A169_B] = {
+		/* AVerMedia A169  */
+		/* Rickard Osser <ricky@osser.se>  */
+		/* This card has two saa7134 chips on it,
+		   but only one of them is currently working. */
+		.name		= "AVerMedia A169 B",
+		.audio_clock    = 0x02187de7,
+		.tuner_type	= TUNER_LG_TALN,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask       = 0x0a60000,
+	},
+	[SAA7134_BOARD_AVERMEDIA_A169_B1] = {
+		/* AVerMedia A169 */
+		/* Rickard Osser <ricky@osser.se> */
+		.name		= "AVerMedia A169 B1",
+		.audio_clock    = 0x02187de7,
+		.tuner_type	= TUNER_LG_TALN,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask       = 0xca60000,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 4,
+			.amux = TV,
+			.tv   = 1,
+			.gpio = 0x04a61000,
+		},{
+			.name = name_comp2,  /*  Composite SVIDEO (B/W if signal is carried with SVIDEO) */
+			.vmux = 1,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 9,           /* 9 is correct as S-VIDEO1 according to a169.inf! */
+			.amux = LINE1,
+		}},
+	},
+	[SAA7134_BOARD_MD7134_BRIDGE_2] = {
+		/* This card has two saa7134 chips on it,
+		   but only one of them is currently working.
+		   The programming for the primary decoder is
+		   in SAA7134_BOARD_MD7134 */
+		.name           = "Medion 7134 Bridge #2",
+		.audio_clock    = 0x00187de7,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+	},
 };
 
 const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -2753,6 +2938,12 @@
 		.driver_data  = SAA7134_BOARD_ELSA_500TV,
 	},{
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x1048,
+		.subdevice    = 0x226c,
+		.driver_data  = SAA7134_BOARD_ELSA_700TV,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
 		.subvendor    = PCI_VENDOR_ID_ASUSTEK,
 		.subdevice    = 0x4842,
@@ -3094,6 +3285,54 @@
 		.subdevice    = 0x0319,
 		.driver_data  = SAA7134_BOARD_FLYDVB_TRIO,
 	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,	/* SAA 7131E */
+		.subvendor    = 0x1461,
+		.subdevice    = 0x2c05,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_777,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x5168,
+		.subdevice    = 0x0301,
+		.driver_data  = SAA7134_BOARD_FLYDVBT_LR301,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x0331,
+		.subdevice    = 0x1421,
+		.driver_data  = SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x17de,
+		.subdevice    = 0x7201,
+		.driver_data  = SAA7134_BOARD_TEVION_DVBT_220RF,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */
+		.subvendor    = 0x17de,
+		.subdevice    = 0x7350,
+		.driver_data  = SAA7134_BOARD_KWORLD_ATSC110,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x1461,
+		.subdevice    = 0x7360,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_A169_B,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x1461,
+		.subdevice    = 0x6360,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_A169_B1,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x16be,
+		.subdevice    = 0x0005,
+		.driver_data  = SAA7134_BOARD_MD7134_BRIDGE_2,
+	},{
 		/* --- boards without eeprom + subsystem ID --- */
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -3193,13 +3432,15 @@
 	case SAA7134_BOARD_GOTVIEW_7135:
 	case SAA7134_BOARD_KWORLD_TERMINATOR:
 	case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
+	case SAA7134_BOARD_FLYDVBT_LR301:
+	case SAA7134_BOARD_FLYDVBTDUO:
 		dev->has_remote = SAA7134_REMOTE_GPIO;
 		break;
 	case SAA7134_BOARD_MD5044:
 		printk("%s: seems there are two different versions of the MD5044\n"
-		"%s: (with the same ID) out there.  If sound doesn't work for\n"
-		"%s: you try the audio_clock_override=0x200000 insmod option.\n",
-		dev->name,dev->name,dev->name);
+		       "%s: (with the same ID) out there.  If sound doesn't work for\n"
+		       "%s: you try the audio_clock_override=0x200000 insmod option.\n",
+		       dev->name,dev->name,dev->name);
 		break;
 	case SAA7134_BOARD_CINERGY400_CARDBUS:
 		/* power-up tuner chip */
@@ -3220,6 +3461,10 @@
 		saa_writeb(SAA7134_GPIO_GPMODE3, 0x08);
 		saa_writeb(SAA7134_GPIO_GPSTATUS3, 0x06);
 		break;
+	case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
+		saa_writeb(SAA7134_GPIO_GPMODE3, 0x08);
+		saa_writeb(SAA7134_GPIO_GPSTATUS3, 0x00);
+		break;
 	case SAA7134_BOARD_AVERMEDIA_CARDBUS:
 		/* power-up tuner chip */
 		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0xffffffff, 0xffffffff);
@@ -3242,6 +3487,13 @@
 	case SAA7134_BOARD_UPMOST_PURPLE_TV:
 		dev->has_remote = SAA7134_REMOTE_I2C;
 		break;
+	case SAA7134_BOARD_AVERMEDIA_A169_B:
+	case SAA7134_BOARD_MD7134_BRIDGE_2:
+		printk("%s: %s: dual saa713x broadcast decoders\n"
+		       "%s: Sorry, none of the inputs to this chip are supported yet.\n"
+		       "%s: Dual decoder functionality is disabled for now, use the other chip.\n",
+		       dev->name,card(dev).name,dev->name,dev->name);
+		break;
 	}
 	return 0;
 }
@@ -3362,14 +3614,44 @@
 		}
 		break;
 	case SAA7134_BOARD_PHILIPS_TIGER:
+	case SAA7134_BOARD_TEVION_DVBT_220RF:
 	case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
-		/* this is a hybrid board, initialize to analog mode */
+		/* this is a hybrid board, initialize to analog mode
+		 * and configure firmware eeprom address
+		 */
 		{
 		u8 data[] = { 0x3c, 0x33, 0x68};
 		struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
 		i2c_transfer(&dev->i2c_adap, &msg, 1);
 		}
 		break;
+	case SAA7134_BOARD_FLYDVB_TRIO:
+		{
+		u8 data[] = { 0x3c, 0x33, 0x62};
+		struct i2c_msg msg = {.addr=0x09, .flags=0, .buf=data, .len = sizeof(data)};
+		i2c_transfer(&dev->i2c_adap, &msg, 1);
+		}
+		break;
+	case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
+		/* make the tda10046 find its eeprom */
+		{
+		u8 data[] = { 0x3c, 0x33, 0x62};
+		struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+		i2c_transfer(&dev->i2c_adap, &msg, 1);
+		}
+		break;
+	case SAA7134_BOARD_KWORLD_ATSC110:
+		{
+			/* enable tuner */
+			int i;
+			static const u8 buffer [] = { 0x10,0x12,0x13,0x04,0x16,0x00,0x14,0x04,0x017,0x00 };
+			dev->i2c_client.addr = 0x0a;
+			for (i = 0; i < 5; i++)
+				if (2 != i2c_master_send(&dev->i2c_client,&buffer[i*2],2))
+					printk(KERN_WARNING "%s: Unable to enable tuner(%i).\n",
+					       dev->name, i);
+		}
+		break;
 	}
 	return 0;
 }
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index 028904b..58e568d 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -66,6 +66,11 @@
 module_param(latency, int, 0444);
 MODULE_PARM_DESC(latency,"pci latency timer");
 
+int saa7134_no_overlay=-1;
+module_param_named(no_overlay, saa7134_no_overlay, int, 0444);
+MODULE_PARM_DESC(no_overlay,"allow override overlay default (0 disables, 1 enables)"
+		" [some VIA/SIS chipsets are known to have problem with overlay]");
+
 static unsigned int video_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
 static unsigned int vbi_nr[]   = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
 static unsigned int radio_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
@@ -251,8 +256,7 @@
 
 void saa7134_dma_free(struct saa7134_dev *dev,struct saa7134_buf *buf)
 {
-	if (in_interrupt())
-		BUG();
+	BUG_ON(in_interrupt());
 
 	videobuf_waiton(&buf->vb,0,0);
 	videobuf_dma_pci_unmap(dev->pci, &buf->vb.dma);
@@ -613,7 +617,7 @@
 
 	saa_writel(SAA7134_IRQ1, 0);
 	saa_writel(SAA7134_IRQ2, 0);
-	init_MUTEX(&dev->lock);
+	mutex_init(&dev->lock);
 	spin_lock_init(&dev->slock);
 
 	saa7134_track_gpio(dev,"pre-init");
@@ -835,6 +839,22 @@
 			latency = 0x0A;
 		}
 #endif
+		if (pci_pci_problems & PCIPCI_FAIL) {
+			printk(KERN_INFO "%s: quirk: this driver and your "
+					"chipset may not work together"
+					" in overlay mode.\n",dev->name);
+			if (!saa7134_no_overlay) {
+				printk(KERN_INFO "%s: quirk: overlay "
+						"mode will be disabled.\n",
+						dev->name);
+				saa7134_no_overlay = 1;
+			} else {
+				printk(KERN_INFO "%s: quirk: overlay "
+						"mode will be forced. Use this"
+						" option at your own risk.\n",
+						dev->name);
+			}
+		}
 	}
 	if (UNSET != latency) {
 		printk(KERN_INFO "%s: setting pci latency timer to %d\n",
@@ -937,6 +957,11 @@
 	v4l2_prio_init(&dev->prio);
 
 	/* register v4l devices */
+	if (saa7134_no_overlay <= 0) {
+		saa7134_video_template.type |= VID_TYPE_OVERLAY;
+	} else {
+		printk("bttv: Overlay support disabled.\n");
+	}
 	dev->video_dev = vdev_init(dev,&saa7134_video_template,"video");
 	err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER,
 				    video_nr[dev->nr]);
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index 9db8e13..86cfdb8 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -32,6 +32,7 @@
 #include "saa7134-reg.h"
 #include "saa7134.h"
 #include <media/v4l2-common.h>
+#include "dvb-pll.h"
 
 #ifdef HAVE_MT352
 # include "mt352.h"
@@ -42,7 +43,6 @@
 #endif
 #ifdef HAVE_NXT200X
 # include "nxt200x.h"
-# include "dvb-pll.h"
 #endif
 
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
@@ -114,6 +114,24 @@
 	return 0;
 }
 
+static int mt352_aver777_init(struct dvb_frontend* fe)
+{
+	static u8 clock_config []  = { CLOCK_CTL,  0x38, 0x2d };
+	static u8 reset []         = { RESET,      0x80 };
+	static u8 adc_ctl_1_cfg [] = { ADC_CTL_1,  0x40 };
+	static u8 agc_cfg []       = { AGC_TARGET, 0x28, 0xa0 };
+	static u8 capt_range_cfg[] = { CAPT_RANGE, 0x33 };
+
+	mt352_write(fe, clock_config,   sizeof(clock_config));
+	udelay(200);
+	mt352_write(fe, reset,          sizeof(reset));
+	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
+	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
+	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+
+	return 0;
+}
+
 static int mt352_pinnacle_pll_set(struct dvb_frontend* fe,
 				  struct dvb_frontend_parameters* params,
 				  u8* pllbuf)
@@ -146,6 +164,15 @@
 	return 0;
 }
 
+static int mt352_aver777_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8* pllbuf)
+{
+	pllbuf[0] = 0xc2;
+	dvb_pll_configure(&dvb_pll_philips_td1316, pllbuf+1,
+			  params->frequency,
+			  params->u.ofdm.bandwidth);
+	return 0;
+}
+
 static struct mt352_config pinnacle_300i = {
 	.demod_address = 0x3c >> 1,
 	.adc_clock     = 20333,
@@ -154,6 +181,12 @@
 	.demod_init    = mt352_pinnacle_init,
 	.pll_set       = mt352_pinnacle_pll_set,
 };
+
+static struct mt352_config avermedia_777 = {
+	.demod_address = 0xf,
+	.demod_init    = mt352_aver777_init,
+	.pll_set       = mt352_aver777_pll_set,
+};
 #endif
 
 /* ------------------------------------------------------------------ */
@@ -781,7 +814,7 @@
 	tda8290_msg.buf = tda8290_open;
 	i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1);
 	return ret;
-};
+}
 
 static int philips_tiger_dvb_mode(struct dvb_frontend *fe)
 {
@@ -817,6 +850,110 @@
 	.request_firmware = NULL,
 };
 
+/* ------------------------------------------------------------------ */
+
+static int lifeview_trio_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+	int ret;
+
+	ret = philips_tda827xa_pll_set(0x60, fe, params);
+	return ret;
+}
+
+static int lifeview_trio_dvb_mode(struct dvb_frontend *fe)
+{
+	return 0;
+}
+
+static void lifeview_trio_analog_mode(struct dvb_frontend *fe)
+{
+	philips_tda827xa_pll_sleep(0x60, fe);
+}
+
+static struct tda1004x_config lifeview_trio_config = {
+	.demod_address = 0x09,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X_GPL,
+	.if_freq       = TDA10046_FREQ_045,
+	.pll_init      = lifeview_trio_dvb_mode,
+	.pll_set       = lifeview_trio_pll_set,
+	.pll_sleep     = lifeview_trio_analog_mode,
+	.request_firmware = NULL,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int ads_duo_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+	int ret;
+
+	ret = philips_tda827xa_pll_set(0x61, fe, params);
+	return ret;
+}
+
+static int ads_duo_dvb_mode(struct dvb_frontend *fe)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	/* route TDA8275a AGC input to the channel decoder */
+	saa_writeb(SAA7134_GPIO_GPSTATUS2, 0x60);
+	return 0;
+}
+
+static void ads_duo_analog_mode(struct dvb_frontend *fe)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	/* route TDA8275a AGC input to the analog IF chip*/
+	saa_writeb(SAA7134_GPIO_GPSTATUS2, 0x20);
+	philips_tda827xa_pll_sleep( 0x61, fe);
+}
+
+static struct tda1004x_config ads_tech_duo_config = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X_GPL,
+	.if_freq       = TDA10046_FREQ_045,
+	.pll_init      = ads_duo_dvb_mode,
+	.pll_set       = ads_duo_pll_set,
+	.pll_sleep     = ads_duo_analog_mode,
+	.request_firmware = NULL,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int tevion_dvb220rf_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+	int ret;
+	ret = philips_tda827xa_pll_set(0x60, fe, params);
+	return ret;
+}
+
+static int tevion_dvb220rf_pll_init(struct dvb_frontend *fe)
+{
+	return 0;
+}
+
+static void tevion_dvb220rf_pll_sleep(struct dvb_frontend *fe)
+{
+	philips_tda827xa_pll_sleep( 0x61, fe);
+}
+
+static struct tda1004x_config tevion_dvbt220rf_config = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.if_freq       = TDA10046_FREQ_045,
+	.pll_init      = tevion_dvb220rf_pll_init,
+	.pll_set       = tevion_dvb220rf_pll_set,
+	.pll_sleep     = tevion_dvb220rf_pll_sleep,
+	.request_firmware = NULL,
+};
+
 #endif
 
 /* ------------------------------------------------------------------ */
@@ -827,6 +964,22 @@
 	.pll_address      = 0x61,
 	.pll_desc         = &dvb_pll_tdhu2,
 };
+
+static int nxt200x_set_pll_input(u8 *buf, int input)
+{
+	if (input)
+		buf[3] |= 0x08;
+	else
+		buf[3] &= ~0x08;
+	return 0;
+}
+
+static struct nxt200x_config kworldatsc110 = {
+	.demod_address    = 0x0a,
+	.pll_address      = 0x61,
+	.pll_desc         = &dvb_pll_tuv1236d,
+	.set_pll_input    = nxt200x_set_pll_input,
+};
 #endif
 
 /* ------------------------------------------------------------------ */
@@ -851,6 +1004,12 @@
 		dev->dvb.frontend = mt352_attach(&pinnacle_300i,
 						 &dev->i2c_adap);
 		break;
+
+	case SAA7134_BOARD_AVERMEDIA_777:
+		printk("%s: avertv 777 dvb setup\n",dev->name);
+		dev->dvb.frontend = mt352_attach(&avermedia_777,
+						 &dev->i2c_adap);
+		break;
 #endif
 #ifdef HAVE_TDA1004X
 	case SAA7134_BOARD_MD7134:
@@ -889,11 +1048,30 @@
 		dev->dvb.frontend = tda10046_attach(&philips_tiger_config,
 						    &dev->i2c_adap);
 		break;
+	case SAA7134_BOARD_FLYDVBT_LR301:
+		dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
+						    &dev->i2c_adap);
+		break;
+	case SAA7134_BOARD_FLYDVB_TRIO:
+		dev->dvb.frontend = tda10046_attach(&lifeview_trio_config,
+						    &dev->i2c_adap);
+		break;
+	case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
+		dev->dvb.frontend = tda10046_attach(&ads_tech_duo_config,
+						    &dev->i2c_adap);
+		break;
+	case SAA7134_BOARD_TEVION_DVBT_220RF:
+		dev->dvb.frontend = tda10046_attach(&tevion_dvbt220rf_config,
+						    &dev->i2c_adap);
+		break;
 #endif
 #ifdef HAVE_NXT200X
 	case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
 		dev->dvb.frontend = nxt200x_attach(&avertvhda180, &dev->i2c_adap);
 		break;
+	case SAA7134_BOARD_KWORLD_ATSC110:
+		dev->dvb.frontend = nxt200x_attach(&kworldatsc110, &dev->i2c_adap);
+		break;
 #endif
 	default:
 		printk("%s: Huh? unknown DVB card?\n",dev->name);
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
index bd4c389..1d972ed 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -89,7 +89,7 @@
 
 	dprintk("open minor=%d\n",minor);
 	err = -EBUSY;
-	if (down_trylock(&dev->empress_tsq.lock))
+	if (!mutex_trylock(&dev->empress_tsq.lock))
 		goto done;
 	if (dev->empress_users)
 		goto done_up;
@@ -99,7 +99,7 @@
 	err = 0;
 
 done_up:
-	up(&dev->empress_tsq.lock);
+	mutex_unlock(&dev->empress_tsq.lock);
 done:
 	return err;
 }
@@ -110,7 +110,7 @@
 
 	if (dev->empress_tsq.streaming)
 		videobuf_streamoff(&dev->empress_tsq);
-	down(&dev->empress_tsq.lock);
+	mutex_lock(&dev->empress_tsq.lock);
 	if (dev->empress_tsq.reading)
 		videobuf_read_stop(&dev->empress_tsq);
 	videobuf_mmap_free(&dev->empress_tsq);
@@ -119,7 +119,7 @@
 	/* stop the encoder */
 	ts_reset_encoder(dev);
 
-	up(&dev->empress_tsq.lock);
+	mutex_unlock(&dev->empress_tsq.lock);
 	return 0;
 }
 
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 82d28cb..1426e4c 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -42,485 +42,6 @@
 #define i2cdprintk(fmt, arg...)    if (ir_debug) \
 	printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg)
 
-/* ---------------------------------------------------------------------- */
-
-static IR_KEYTAB_TYPE flyvideo_codes[IR_KEYTAB_SIZE] = {
-	[   15 ] = KEY_KP0,
-	[    3 ] = KEY_KP1,
-	[    4 ] = KEY_KP2,
-	[    5 ] = KEY_KP3,
-	[    7 ] = KEY_KP4,
-	[    8 ] = KEY_KP5,
-	[    9 ] = KEY_KP6,
-	[   11 ] = KEY_KP7,
-	[   12 ] = KEY_KP8,
-	[   13 ] = KEY_KP9,
-
-	[   14 ] = KEY_MODE,         // Air/Cable
-	[   17 ] = KEY_VIDEO,        // Video
-	[   21 ] = KEY_AUDIO,        // Audio
-	[    0 ] = KEY_POWER,        // Power
-	[   24 ] = KEY_TUNER,        // AV Source
-	[    2 ] = KEY_ZOOM,         // Fullscreen
-	[   26 ] = KEY_LANGUAGE,     // Stereo
-	[   27 ] = KEY_MUTE,         // Mute
-	[   20 ] = KEY_VOLUMEUP,     // Volume +
-	[   23 ] = KEY_VOLUMEDOWN,   // Volume -
-	[   18 ] = KEY_CHANNELUP,    // Channel +
-	[   19 ] = KEY_CHANNELDOWN,  // Channel -
-	[    6 ] = KEY_AGAIN,        // Recall
-	[   16 ] = KEY_ENTER,      // Enter
-};
-
-
-static IR_KEYTAB_TYPE cinergy_codes[IR_KEYTAB_SIZE] = {
-	[    0 ] = KEY_KP0,
-	[    1 ] = KEY_KP1,
-	[    2 ] = KEY_KP2,
-	[    3 ] = KEY_KP3,
-	[    4 ] = KEY_KP4,
-	[    5 ] = KEY_KP5,
-	[    6 ] = KEY_KP6,
-	[    7 ] = KEY_KP7,
-	[    8 ] = KEY_KP8,
-	[    9 ] = KEY_KP9,
-
-	[ 0x0a ] = KEY_POWER,
-	[ 0x0b ] = KEY_PROG1,           // app
-	[ 0x0c ] = KEY_ZOOM,            // zoom/fullscreen
-	[ 0x0d ] = KEY_CHANNELUP,       // channel
-	[ 0x0e ] = KEY_CHANNELDOWN,     // channel-
-	[ 0x0f ] = KEY_VOLUMEUP,
-	[ 0x10 ] = KEY_VOLUMEDOWN,
-	[ 0x11 ] = KEY_TUNER,           // AV
-	[ 0x12 ] = KEY_NUMLOCK,         // -/--
-	[ 0x13 ] = KEY_AUDIO,           // audio
-	[ 0x14 ] = KEY_MUTE,
-	[ 0x15 ] = KEY_UP,
-	[ 0x16 ] = KEY_DOWN,
-	[ 0x17 ] = KEY_LEFT,
-	[ 0x18 ] = KEY_RIGHT,
-	[ 0x19 ] = BTN_LEFT,
-	[ 0x1a ] = BTN_RIGHT,
-	[ 0x1b ] = KEY_WWW,             // text
-	[ 0x1c ] = KEY_REWIND,
-	[ 0x1d ] = KEY_FORWARD,
-	[ 0x1e ] = KEY_RECORD,
-	[ 0x1f ] = KEY_PLAY,
-	[ 0x20 ] = KEY_PREVIOUSSONG,
-	[ 0x21 ] = KEY_NEXTSONG,
-	[ 0x22 ] = KEY_PAUSE,
-	[ 0x23 ] = KEY_STOP,
-};
-
-/* Alfons Geser <a.geser@cox.net>
- * updates from Job D. R. Borges <jobdrb@ig.com.br> */
-static IR_KEYTAB_TYPE eztv_codes[IR_KEYTAB_SIZE] = {
-	[ 18 ] = KEY_POWER,
-	[  1 ] = KEY_TV,             // DVR
-	[ 21 ] = KEY_DVD,            // DVD
-	[ 23 ] = KEY_AUDIO,          // music
-				     // DVR mode / DVD mode / music mode
-
-	[ 27 ] = KEY_MUTE,           // mute
-	[  2 ] = KEY_LANGUAGE,       // MTS/SAP / audio / autoseek
-	[ 30 ] = KEY_SUBTITLE,       // closed captioning / subtitle / seek
-	[ 22 ] = KEY_ZOOM,           // full screen
-	[ 28 ] = KEY_VIDEO,          // video source / eject / delall
-	[ 29 ] = KEY_RESTART,        // playback / angle / del
-	[ 47 ] = KEY_SEARCH,         // scan / menu / playlist
-	[ 48 ] = KEY_CHANNEL,        // CH surfing / bookmark / memo
-
-	[ 49 ] = KEY_HELP,           // help
-	[ 50 ] = KEY_MODE,           // num/memo
-	[ 51 ] = KEY_ESC,            // cancel
-
-	[ 12 ] = KEY_UP,             // up
-	[ 16 ] = KEY_DOWN,           // down
-	[  8 ] = KEY_LEFT,           // left
-	[  4 ] = KEY_RIGHT,          // right
-	[  3 ] = KEY_SELECT,         // select
-
-	[ 31 ] = KEY_REWIND,         // rewind
-	[ 32 ] = KEY_PLAYPAUSE,      // play/pause
-	[ 41 ] = KEY_FORWARD,        // forward
-	[ 20 ] = KEY_AGAIN,          // repeat
-	[ 43 ] = KEY_RECORD,         // recording
-	[ 44 ] = KEY_STOP,           // stop
-	[ 45 ] = KEY_PLAY,           // play
-	[ 46 ] = KEY_SHUFFLE,        // snapshot / shuffle
-
-	[  0 ] = KEY_KP0,
-	[  5 ] = KEY_KP1,
-	[  6 ] = KEY_KP2,
-	[  7 ] = KEY_KP3,
-	[  9 ] = KEY_KP4,
-	[ 10 ] = KEY_KP5,
-	[ 11 ] = KEY_KP6,
-	[ 13 ] = KEY_KP7,
-	[ 14 ] = KEY_KP8,
-	[ 15 ] = KEY_KP9,
-
-	[ 42 ] = KEY_VOLUMEUP,
-	[ 17 ] = KEY_VOLUMEDOWN,
-	[ 24 ] = KEY_CHANNELUP,      // CH.tracking up
-	[ 25 ] = KEY_CHANNELDOWN,    // CH.tracking down
-
-	[ 19 ] = KEY_KPENTER,        // enter
-	[ 33 ] = KEY_KPDOT,          // . (decimal dot)
-};
-
-static IR_KEYTAB_TYPE avacssmart_codes[IR_KEYTAB_SIZE] = {
-	[ 30 ] = KEY_POWER,		// power
-	[ 28 ] = KEY_SEARCH,		// scan
-	[  7 ] = KEY_SELECT,		// source
-
-	[ 22 ] = KEY_VOLUMEUP,
-	[ 20 ] = KEY_VOLUMEDOWN,
-	[ 31 ] = KEY_CHANNELUP,
-	[ 23 ] = KEY_CHANNELDOWN,
-	[ 24 ] = KEY_MUTE,
-
-	[  2 ] = KEY_KP0,
-	[  1 ] = KEY_KP1,
-	[ 11 ] = KEY_KP2,
-	[ 27 ] = KEY_KP3,
-	[  5 ] = KEY_KP4,
-	[  9 ] = KEY_KP5,
-	[ 21 ] = KEY_KP6,
-	[  6 ] = KEY_KP7,
-	[ 10 ] = KEY_KP8,
-	[ 18 ] = KEY_KP9,
-	[ 16 ] = KEY_KPDOT,
-
-	[  3 ] = KEY_TUNER,		// tv/fm
-	[  4 ] = KEY_REWIND,		// fm tuning left or function left
-	[ 12 ] = KEY_FORWARD,		// fm tuning right or function right
-
-	[  0 ] = KEY_RECORD,
-	[  8 ] = KEY_STOP,
-	[ 17 ] = KEY_PLAY,
-
-	[ 25 ] = KEY_ZOOM,
-	[ 14 ] = KEY_MENU,		// function
-	[ 19 ] = KEY_AGAIN,		// recall
-	[ 29 ] = KEY_RESTART,		// reset
-	[ 26 ] = KEY_SHUFFLE,		// snapshot/shuffle
-
-// FIXME
-	[ 13 ] = KEY_F21,		// mts
-	[ 15 ] = KEY_F22,		// min
-};
-
-/* Alex Hermann <gaaf@gmx.net> */
-static IR_KEYTAB_TYPE md2819_codes[IR_KEYTAB_SIZE] = {
-	[ 40 ] = KEY_KP1,
-	[ 24 ] = KEY_KP2,
-	[ 56 ] = KEY_KP3,
-	[ 36 ] = KEY_KP4,
-	[ 20 ] = KEY_KP5,
-	[ 52 ] = KEY_KP6,
-	[ 44 ] = KEY_KP7,
-	[ 28 ] = KEY_KP8,
-	[ 60 ] = KEY_KP9,
-	[ 34 ] = KEY_KP0,
-
-	[ 32 ] = KEY_TV,		// TV/FM
-	[ 16 ] = KEY_CD,		// CD
-	[ 48 ] = KEY_TEXT,		// TELETEXT
-	[  0 ] = KEY_POWER,		// POWER
-
-	[  8 ] = KEY_VIDEO,		// VIDEO
-	[  4 ] = KEY_AUDIO,		// AUDIO
-	[ 12 ] = KEY_ZOOM,		// FULL SCREEN
-
-	[ 18 ] = KEY_SUBTITLE,		// DISPLAY	- ???
-	[ 50 ] = KEY_REWIND,		// LOOP		- ???
-	[  2 ] = KEY_PRINT,		// PREVIEW	- ???
-
-	[ 42 ] = KEY_SEARCH,		// AUTOSCAN
-	[ 26 ] = KEY_SLEEP,		// FREEZE	- ???
-	[ 58 ] = KEY_SHUFFLE,		// SNAPSHOT	- ???
-	[ 10 ] = KEY_MUTE,		// MUTE
-
-	[ 38 ] = KEY_RECORD,		// RECORD
-	[ 22 ] = KEY_PAUSE,		// PAUSE
-	[ 54 ] = KEY_STOP,		// STOP
-	[  6 ] = KEY_PLAY,		// PLAY
-
-	[ 46 ] = KEY_RED,		// <RED>
-	[ 33 ] = KEY_GREEN,		// <GREEN>
-	[ 14 ] = KEY_YELLOW,		// <YELLOW>
-	[  1 ] = KEY_BLUE,		// <BLUE>
-
-	[ 30 ] = KEY_VOLUMEDOWN,	// VOLUME-
-	[ 62 ] = KEY_VOLUMEUP,		// VOLUME+
-	[ 17 ] = KEY_CHANNELDOWN,	// CHANNEL/PAGE-
-	[ 49 ] = KEY_CHANNELUP		// CHANNEL/PAGE+
-};
-
-static IR_KEYTAB_TYPE videomate_tv_pvr_codes[IR_KEYTAB_SIZE] = {
-	[ 20 ] = KEY_MUTE,
-	[ 36 ] = KEY_ZOOM,
-
-	[  1 ] = KEY_DVD,
-	[ 35 ] = KEY_RADIO,
-	[  0 ] = KEY_TV,
-
-	[ 10 ] = KEY_REWIND,
-	[  8 ] = KEY_PLAYPAUSE,
-	[ 15 ] = KEY_FORWARD,
-
-	[  2 ] = KEY_PREVIOUS,
-	[  7 ] = KEY_STOP,
-	[  6 ] = KEY_NEXT,
-
-	[ 12 ] = KEY_UP,
-	[ 14 ] = KEY_DOWN,
-	[ 11 ] = KEY_LEFT,
-	[ 13 ] = KEY_RIGHT,
-	[ 17 ] = KEY_OK,
-
-	[  3 ] = KEY_MENU,
-	[  9 ] = KEY_SETUP,
-	[  5 ] = KEY_VIDEO,
-	[ 34 ] = KEY_CHANNEL,
-
-	[ 18 ] = KEY_VOLUMEUP,
-	[ 21 ] = KEY_VOLUMEDOWN,
-	[ 16 ] = KEY_CHANNELUP,
-	[ 19 ] = KEY_CHANNELDOWN,
-
-	[  4 ] = KEY_RECORD,
-
-	[ 22 ] = KEY_KP1,
-	[ 23 ] = KEY_KP2,
-	[ 24 ] = KEY_KP3,
-	[ 25 ] = KEY_KP4,
-	[ 26 ] = KEY_KP5,
-	[ 27 ] = KEY_KP6,
-	[ 28 ] = KEY_KP7,
-	[ 29 ] = KEY_KP8,
-	[ 30 ] = KEY_KP9,
-	[ 31 ] = KEY_KP0,
-
-	[ 32 ] = KEY_LANGUAGE,
-	[ 33 ] = KEY_SLEEP,
-};
-
-/* Michael Tokarev <mjt@tls.msk.ru>
-   http://www.corpit.ru/mjt/beholdTV/remote_control.jpg
-   keytable is used by MANLI MTV00[12] and BeholdTV 40[13] at
-   least, and probably other cards too.
-   The "ascii-art picture" below (in comments, first row
-   is the keycode in hex, and subsequent row(s) shows
-   the button labels (several variants when appropriate)
-   helps to descide which keycodes to assign to the buttons.
- */
-static IR_KEYTAB_TYPE manli_codes[IR_KEYTAB_SIZE] = {
-
-	/*  0x1c            0x12  *
-	 * FUNCTION         POWER *
-	 *   FM              (|)  *
-	 *                        */
-	[ 0x1c ] = KEY_RADIO,	/*XXX*/
-	[ 0x12 ] = KEY_POWER,
-
-	/*  0x01    0x02    0x03  *
-	 *   1       2       3    *
-	 *                        *
-	 *  0x04    0x05    0x06  *
-	 *   4       5       6    *
-	 *                        *
-	 *  0x07    0x08    0x09  *
-	 *   7       8       9    *
-	 *                        */
-	[ 0x01 ] = KEY_KP1,
-	[ 0x02 ] = KEY_KP2,
-	[ 0x03 ] = KEY_KP3,
-	[ 0x04 ] = KEY_KP4,
-	[ 0x05 ] = KEY_KP5,
-	[ 0x06 ] = KEY_KP6,
-	[ 0x07 ] = KEY_KP7,
-	[ 0x08 ] = KEY_KP8,
-	[ 0x09 ] = KEY_KP9,
-
-	/*  0x0a    0x00    0x17  *
-	 * RECALL    0      +100  *
-	 *                  PLUS  *
-	 *                        */
-	[ 0x0a ] = KEY_AGAIN,	/*XXX KEY_REWIND? */
-	[ 0x00 ] = KEY_KP0,
-	[ 0x17 ] = KEY_DIGITS,	/*XXX*/
-
-	/*  0x14            0x10  *
-	 *  MENU            INFO  *
-	 *  OSD                   */
-	[ 0x14 ] = KEY_MENU,
-	[ 0x10 ] = KEY_INFO,
-
-	/*          0x0b          *
-	 *           Up           *
-	 *                        *
-	 *  0x18    0x16    0x0c  *
-	 *  Left     Ok     Right *
-	 *                        *
-	 *         0x015          *
-	 *         Down           *
-	 *                        */
-	[ 0x0b ] = KEY_UP,	/*XXX KEY_SCROLLUP? */
-	[ 0x18 ] = KEY_LEFT,	/*XXX KEY_BACK? */
-	[ 0x16 ] = KEY_OK,	/*XXX KEY_SELECT? KEY_ENTER? */
-	[ 0x0c ] = KEY_RIGHT,	/*XXX KEY_FORWARD? */
-	[ 0x15 ] = KEY_DOWN,	/*XXX KEY_SCROLLDOWN? */
-
-	/*  0x11            0x0d  *
-	 *  TV/AV           MODE  *
-	 *  SOURCE         STEREO *
-	 *                        */
-	[ 0x11 ] = KEY_TV,	/*XXX*/
-	[ 0x0d ] = KEY_MODE,	/*XXX there's no KEY_STEREO */
-
-	/*  0x0f    0x1b    0x1a  *
-	 *  AUDIO   Vol+    Chan+ *
-	 *        TIMESHIFT???    *
-	 *                        *
-	 *  0x0e    0x1f    0x1e  *
-	 *  SLEEP   Vol-    Chan- *
-	 *                        */
-	[ 0x0f ] = KEY_AUDIO,
-	[ 0x1b ] = KEY_VOLUMEUP,
-	[ 0x1a ] = KEY_CHANNELUP,
-	[ 0x0e ] = KEY_SLEEP,	/*XXX maybe KEY_PAUSE */
-	[ 0x1f ] = KEY_VOLUMEDOWN,
-	[ 0x1e ] = KEY_CHANNELDOWN,
-
-	/*         0x13     0x19  *
-	 *         MUTE   SNAPSHOT*
-	 *                        */
-	[ 0x13 ] = KEY_MUTE,
-	[ 0x19 ] = KEY_RECORD,	/*XXX*/
-
-	// 0x1d unused ?
-};
-
-
-/* Mike Baikov <mike@baikov.com> */
-static IR_KEYTAB_TYPE gotview7135_codes[IR_KEYTAB_SIZE] = {
-
-	[ 33 ] = KEY_POWER,
-	[ 105] = KEY_TV,
-	[ 51 ] = KEY_KP0,
-	[ 81 ] = KEY_KP1,
-	[ 49 ] = KEY_KP2,
-	[ 113] = KEY_KP3,
-	[ 59 ] = KEY_KP4,
-	[ 88 ] = KEY_KP5,
-	[ 65 ] = KEY_KP6,
-	[ 72 ] = KEY_KP7,
-	[ 48 ] = KEY_KP8,
-	[ 83 ] = KEY_KP9,
-	[ 115] = KEY_AGAIN, /* LOOP */
-	[ 10 ] = KEY_AUDIO,
-	[ 97 ] = KEY_PRINT, /* PREVIEW */
-	[ 122] = KEY_VIDEO,
-	[ 32 ] = KEY_CHANNELUP,
-	[ 64 ] = KEY_CHANNELDOWN,
-	[ 24 ] = KEY_VOLUMEDOWN,
-	[ 80 ] = KEY_VOLUMEUP,
-	[ 16 ] = KEY_MUTE,
-	[ 74 ] = KEY_SEARCH,
-	[ 123] = KEY_SHUFFLE, /* SNAPSHOT */
-	[ 34 ] = KEY_RECORD,
-	[ 98 ] = KEY_STOP,
-	[ 120] = KEY_PLAY,
-	[ 57 ] = KEY_REWIND,
-	[ 89 ] = KEY_PAUSE,
-	[ 25 ] = KEY_FORWARD,
-	[  9 ] = KEY_ZOOM,
-
-	[ 82 ] = KEY_F21, /* LIVE TIMESHIFT */
-	[ 26 ] = KEY_F22, /* MIN TIMESHIFT */
-	[ 58 ] = KEY_F23, /* TIMESHIFT */
-	[ 112] = KEY_F24, /* NORMAL TIMESHIFT */
-};
-
-static IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = {
-	[ 0x3  ] = KEY_POWER,
-	[ 0x6f ] = KEY_MUTE,
-	[ 0x10 ] = KEY_BACKSPACE,       /* Recall */
-
-	[ 0x11 ] = KEY_KP0,
-	[ 0x4  ] = KEY_KP1,
-	[ 0x5  ] = KEY_KP2,
-	[ 0x6  ] = KEY_KP3,
-	[ 0x8  ] = KEY_KP4,
-	[ 0x9  ] = KEY_KP5,
-	[ 0xa  ] = KEY_KP6,
-	[ 0xc  ] = KEY_KP7,
-	[ 0xd  ] = KEY_KP8,
-	[ 0xe  ] = KEY_KP9,
-	[ 0x12 ] = KEY_KPDOT,           /* 100+ */
-
-	[ 0x7  ] = KEY_VOLUMEUP,
-	[ 0xb  ] = KEY_VOLUMEDOWN,
-	[ 0x1a ] = KEY_KPPLUS,
-	[ 0x18 ] = KEY_KPMINUS,
-	[ 0x15 ] = KEY_UP,
-	[ 0x1d ] = KEY_DOWN,
-	[ 0xf  ] = KEY_CHANNELUP,
-	[ 0x13 ] = KEY_CHANNELDOWN,
-	[ 0x48 ] = KEY_ZOOM,
-
-	[ 0x1b ] = KEY_VIDEO,           /* Video source */
-	[ 0x49 ] = KEY_LANGUAGE,        /* MTS Select */
-	[ 0x19 ] = KEY_SEARCH,          /* Auto Scan */
-
-	[ 0x4b ] = KEY_RECORD,
-	[ 0x46 ] = KEY_PLAY,
-	[ 0x45 ] = KEY_PAUSE,           /* Pause */
-	[ 0x44 ] = KEY_STOP,
-	[ 0x40 ] = KEY_FORWARD,         /* Forward ? */
-	[ 0x42 ] = KEY_REWIND,          /* Backward ? */
-
-};
-
-/* Mapping for the 28 key remote control as seen at
-   http://www.sednacomputer.com/photo/cardbus-tv.jpg
-   Pavel Mihaylov <bin@bash.info> */
-static IR_KEYTAB_TYPE pctv_sedna_codes[IR_KEYTAB_SIZE] = {
-	[    0 ] = KEY_KP0,
-	[    1 ] = KEY_KP1,
-	[    2 ] = KEY_KP2,
-	[    3 ] = KEY_KP3,
-	[    4 ] = KEY_KP4,
-	[    5 ] = KEY_KP5,
-	[    6 ] = KEY_KP6,
-	[    7 ] = KEY_KP7,
-	[    8 ] = KEY_KP8,
-	[    9 ] = KEY_KP9,
-
-	[ 0x0a ] = KEY_AGAIN,          /* Recall */
-	[ 0x0b ] = KEY_CHANNELUP,
-	[ 0x0c ] = KEY_VOLUMEUP,
-	[ 0x0d ] = KEY_MODE,           /* Stereo */
-	[ 0x0e ] = KEY_STOP,
-	[ 0x0f ] = KEY_PREVIOUSSONG,
-	[ 0x10 ] = KEY_ZOOM,
-	[ 0x11 ] = KEY_TUNER,          /* Source */
-	[ 0x12 ] = KEY_POWER,
-	[ 0x13 ] = KEY_MUTE,
-	[ 0x15 ] = KEY_CHANNELDOWN,
-	[ 0x18 ] = KEY_VOLUMEDOWN,
-	[ 0x19 ] = KEY_SHUFFLE,        /* Snapshot */
-	[ 0x1a ] = KEY_NEXTSONG,
-	[ 0x1b ] = KEY_TEXT,           /* Time Shift */
-	[ 0x1c ] = KEY_RADIO,          /* FM Radio */
-	[ 0x1d ] = KEY_RECORD,
-	[ 0x1e ] = KEY_PAUSE,
-};
-
-
 /* -------------------- GPIO generic keycode builder -------------------- */
 
 static int build_key(struct saa7134_dev *dev)
@@ -628,27 +149,27 @@
 	case SAA7134_BOARD_FLYVIDEO3000:
 	case SAA7134_BOARD_FLYTVPLATINUM_FM:
 	case SAA7134_BOARD_FLYTVPLATINUM_MINI2:
-		ir_codes     = flyvideo_codes;
+		ir_codes     = ir_codes_flyvideo;
 		mask_keycode = 0xEC00000;
 		mask_keydown = 0x0040000;
 		break;
 	case SAA7134_BOARD_CINERGY400:
 	case SAA7134_BOARD_CINERGY600:
 	case SAA7134_BOARD_CINERGY600_MK3:
-		ir_codes     = cinergy_codes;
+		ir_codes     = ir_codes_cinergy;
 		mask_keycode = 0x00003f;
 		mask_keyup   = 0x040000;
 		break;
 	case SAA7134_BOARD_ECS_TVP3XP:
 	case SAA7134_BOARD_ECS_TVP3XP_4CB5:
-		ir_codes     = eztv_codes;
+		ir_codes     = ir_codes_eztv;
 		mask_keycode = 0x00017c;
 		mask_keyup   = 0x000002;
 		polling      = 50; // ms
 		break;
 	case SAA7134_BOARD_KWORLD_XPERT:
 	case SAA7134_BOARD_AVACSSMARTTV:
-		ir_codes     = avacssmart_codes;
+		ir_codes     = ir_codes_pixelview;
 		mask_keycode = 0x00001F;
 		mask_keyup   = 0x000020;
 		polling      = 50; // ms
@@ -660,7 +181,7 @@
 	case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
 	case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
 	case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
-		ir_codes     = md2819_codes;
+		ir_codes     = ir_codes_avermedia;
 		mask_keycode = 0x0007C8;
 		mask_keydown = 0x000010;
 		polling      = 50; // ms
@@ -669,7 +190,7 @@
 		saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4);
 		break;
 	case SAA7134_BOARD_KWORLD_TERMINATOR:
-		ir_codes     = avacssmart_codes;
+		ir_codes     = ir_codes_pixelview;
 		mask_keycode = 0x00001f;
 		mask_keyup   = 0x000060;
 		polling      = 50; // ms
@@ -677,19 +198,19 @@
 	case SAA7134_BOARD_MANLI_MTV001:
 	case SAA7134_BOARD_MANLI_MTV002:
 	case SAA7134_BOARD_BEHOLD_409FM:
-		ir_codes     = manli_codes;
+		ir_codes     = ir_codes_manli;
 		mask_keycode = 0x001f00;
 		mask_keyup   = 0x004000;
 		polling      = 50; // ms
 		break;
 	case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
-		ir_codes     = pctv_sedna_codes;
+		ir_codes     = ir_codes_pctv_sedna;
 		mask_keycode = 0x001f00;
 		mask_keyup   = 0x004000;
 		polling      = 50; // ms
 		break;
 	case SAA7134_BOARD_GOTVIEW_7135:
-		ir_codes     = gotview7135_codes;
+		ir_codes     = ir_codes_gotview7135;
 		mask_keycode = 0x0003EC;
 		mask_keyup   = 0x008000;
 		mask_keydown = 0x000010;
@@ -698,17 +219,23 @@
 	case SAA7134_BOARD_VIDEOMATE_TV_PVR:
 	case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS:
 	case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
-		ir_codes     = videomate_tv_pvr_codes;
+		ir_codes     = ir_codes_videomate_tv_pvr;
 		mask_keycode = 0x00003F;
 		mask_keyup   = 0x400000;
 		polling      = 50; // ms
 		break;
 	case SAA7134_BOARD_VIDEOMATE_DVBT_300:
 	case SAA7134_BOARD_VIDEOMATE_DVBT_200:
-		ir_codes     = videomate_tv_pvr_codes;
+		ir_codes     = ir_codes_videomate_tv_pvr;
 		mask_keycode = 0x003F00;
 		mask_keyup   = 0x040000;
 		break;
+	case SAA7134_BOARD_FLYDVBT_LR301:
+	case SAA7134_BOARD_FLYDVBTDUO:
+		ir_codes     = ir_codes_flydvb;
+		mask_keycode = 0x0001F00;
+		mask_keydown = 0x0040000;
+		break;
 	}
 	if (NULL == ir_codes) {
 		printk("%s: Oops: IR config error [card=%d]\n",
diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c
index 7448e38..d79d05f 100644
--- a/drivers/media/video/saa7134/saa7134-oss.c
+++ b/drivers/media/video/saa7134/saa7134-oss.c
@@ -84,8 +84,7 @@
 {
 	int err;
 
-	if (!dev->dmasound.bufsize)
-		BUG();
+	BUG_ON(!dev->dmasound.bufsize);
 	videobuf_dma_init(&dev->dmasound.dma);
 	err = videobuf_dma_init_kernel(&dev->dmasound.dma, PCI_DMA_FROMDEVICE,
 				       (dev->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT);
@@ -96,8 +95,7 @@
 
 static int dsp_buffer_free(struct saa7134_dev *dev)
 {
-	if (!dev->dmasound.blksize)
-		BUG();
+	BUG_ON(!dev->dmasound.blksize);
 	videobuf_dma_free(&dev->dmasound.dma);
 	dev->dmasound.blocks  = 0;
 	dev->dmasound.blksize = 0;
@@ -254,7 +252,7 @@
 	if (NULL == dev)
 		return -ENODEV;
 
-	down(&dev->dmasound.lock);
+	mutex_lock(&dev->dmasound.lock);
 	err = -EBUSY;
 	if (dev->dmasound.users_dsp)
 		goto fail1;
@@ -270,13 +268,13 @@
 	if (0 != err)
 		goto fail2;
 
-	up(&dev->dmasound.lock);
+	mutex_unlock(&dev->dmasound.lock);
 	return 0;
 
  fail2:
 	dev->dmasound.users_dsp--;
  fail1:
-	up(&dev->dmasound.lock);
+	mutex_unlock(&dev->dmasound.lock);
 	return err;
 }
 
@@ -284,13 +282,13 @@
 {
 	struct saa7134_dev *dev = file->private_data;
 
-	down(&dev->dmasound.lock);
+	mutex_lock(&dev->dmasound.lock);
 	if (dev->dmasound.recording_on)
 		dsp_rec_stop(dev);
 	dsp_buffer_free(dev);
 	dev->dmasound.users_dsp--;
 	file->private_data = NULL;
-	up(&dev->dmasound.lock);
+	mutex_unlock(&dev->dmasound.lock);
 	return 0;
 }
 
@@ -304,7 +302,7 @@
 	int err,ret = 0;
 
 	add_wait_queue(&dev->dmasound.wq, &wait);
-	down(&dev->dmasound.lock);
+	mutex_lock(&dev->dmasound.lock);
 	while (count > 0) {
 		/* wait for data if needed */
 		if (0 == dev->dmasound.read_count) {
@@ -328,12 +326,12 @@
 					ret = -EAGAIN;
 				break;
 			}
-			up(&dev->dmasound.lock);
+			mutex_unlock(&dev->dmasound.lock);
 			set_current_state(TASK_INTERRUPTIBLE);
 			if (0 == dev->dmasound.read_count)
 				schedule();
 			set_current_state(TASK_RUNNING);
-			down(&dev->dmasound.lock);
+			mutex_lock(&dev->dmasound.lock);
 			if (signal_pending(current)) {
 				if (0 == ret)
 					ret = -EINTR;
@@ -362,7 +360,7 @@
 		if (dev->dmasound.read_offset == dev->dmasound.bufsize)
 			dev->dmasound.read_offset = 0;
 	}
-	up(&dev->dmasound.lock);
+	mutex_unlock(&dev->dmasound.lock);
 	remove_wait_queue(&dev->dmasound.wq, &wait);
 	return ret;
 }
@@ -435,13 +433,13 @@
 	case SNDCTL_DSP_STEREO:
 		if (get_user(val, p))
 			return -EFAULT;
-		down(&dev->dmasound.lock);
+		mutex_lock(&dev->dmasound.lock);
 		dev->dmasound.channels = val ? 2 : 1;
 		if (dev->dmasound.recording_on) {
 			dsp_rec_stop(dev);
 			dsp_rec_start(dev);
 		}
-		up(&dev->dmasound.lock);
+		mutex_unlock(&dev->dmasound.lock);
 		return put_user(dev->dmasound.channels-1, p);
 
 	case SNDCTL_DSP_CHANNELS:
@@ -449,13 +447,13 @@
 			return -EFAULT;
 		if (val != 1 && val != 2)
 			return -EINVAL;
-		down(&dev->dmasound.lock);
+		mutex_lock(&dev->dmasound.lock);
 		dev->dmasound.channels = val;
 		if (dev->dmasound.recording_on) {
 			dsp_rec_stop(dev);
 			dsp_rec_start(dev);
 		}
-		up(&dev->dmasound.lock);
+		mutex_unlock(&dev->dmasound.lock);
 		/* fall through */
 	case SOUND_PCM_READ_CHANNELS:
 		return put_user(dev->dmasound.channels, p);
@@ -478,13 +476,13 @@
 		case AFMT_U16_BE:
 		case AFMT_S16_LE:
 		case AFMT_S16_BE:
-			down(&dev->dmasound.lock);
+			mutex_lock(&dev->dmasound.lock);
 			dev->dmasound.afmt = val;
 			if (dev->dmasound.recording_on) {
 				dsp_rec_stop(dev);
 				dsp_rec_start(dev);
 			}
-			up(&dev->dmasound.lock);
+			mutex_unlock(&dev->dmasound.lock);
 			return put_user(dev->dmasound.afmt, p);
 		default:
 			return -EINVAL;
@@ -509,10 +507,10 @@
 		return 0;
 
 	case SNDCTL_DSP_RESET:
-		down(&dev->dmasound.lock);
+		mutex_lock(&dev->dmasound.lock);
 		if (dev->dmasound.recording_on)
 			dsp_rec_stop(dev);
-		up(&dev->dmasound.lock);
+		mutex_unlock(&dev->dmasound.lock);
 		return 0;
 	case SNDCTL_DSP_GETBLKSIZE:
 		return put_user(dev->dmasound.blksize, p);
@@ -556,10 +554,10 @@
 	poll_wait(file, &dev->dmasound.wq, wait);
 
 	if (0 == dev->dmasound.read_count) {
-		down(&dev->dmasound.lock);
+		mutex_lock(&dev->dmasound.lock);
 		if (!dev->dmasound.recording_on)
 			dsp_rec_start(dev);
-		up(&dev->dmasound.lock);
+		mutex_unlock(&dev->dmasound.lock);
 	} else
 		mask |= (POLLIN | POLLRDNORM);
 	return mask;
@@ -852,7 +850,7 @@
 		return -1;
 
 	/* general */
-	init_MUTEX(&dev->dmasound.lock);
+	mutex_init(&dev->dmasound.lock);
 	init_waitqueue_head(&dev->dmasound.wq);
 
 	switch (dev->pci->device) {
diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c
index afa4dcb..3043233 100644
--- a/drivers/media/video/saa7134/saa7134-tvaudio.c
+++ b/drivers/media/video/saa7134/saa7134-tvaudio.c
@@ -140,6 +140,12 @@
 		.carr2         = 5850,
 		.mode          = TVAUDIO_NICAM_AM,
 	},{
+		.name          = "SECAM-L MONO",
+		.std           = V4L2_STD_SECAM,
+		.carr1         = 6500,
+		.carr2         = -1,
+		.mode          = TVAUDIO_AM_MONO,
+	},{
 		.name          = "SECAM-D/K",
 		.std           = V4L2_STD_SECAM,
 		.carr1         = 6500,
@@ -334,6 +340,12 @@
 		saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT,  0xa1);
 		saa_writeb(SAA7134_NICAM_CONFIG,              0x00);
 		break;
+	case TVAUDIO_AM_MONO:
+		saa_writeb(SAA7134_DEMODULATOR,               0x12);
+		saa_writeb(SAA7134_DCXO_IDENT_CTRL,           0x00);
+		saa_writeb(SAA7134_FM_DEEMPHASIS,             0x44);
+		saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT,  0xa0);
+		break;
 	case TVAUDIO_FM_SAT_STEREO:
 		/* not implemented (yet) */
 		break;
@@ -414,6 +426,7 @@
 
 	switch (audio->mode) {
 	case TVAUDIO_FM_MONO:
+	case TVAUDIO_AM_MONO:
 		return V4L2_TUNER_SUB_MONO;
 	case TVAUDIO_FM_K_STEREO:
 	case TVAUDIO_FM_BG_STEREO:
@@ -480,6 +493,7 @@
 
 	switch (audio->mode) {
 	case TVAUDIO_FM_MONO:
+	case TVAUDIO_AM_MONO:
 		/* nothing to do ... */
 		break;
 	case TVAUDIO_FM_K_STEREO:
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index e97426b..57a11e7 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -460,17 +460,17 @@
 		return 1;
 
 	/* is it free? */
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 	if (dev->resources & bit) {
 		/* no, someone else uses it */
-		up(&dev->lock);
+		mutex_unlock(&dev->lock);
 		return 0;
 	}
 	/* it's free, grab it */
 	fh->resources  |= bit;
 	dev->resources |= bit;
 	dprintk("res: get %d\n",bit);
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 	return 1;
 }
 
@@ -489,14 +489,13 @@
 static
 void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits)
 {
-	if ((fh->resources & bits) != bits)
-		BUG();
+	BUG_ON((fh->resources & bits) != bits);
 
-	down(&dev->lock);
+	mutex_lock(&dev->lock);
 	fh->resources  &= ~bits;
 	dev->resources &= ~bits;
 	dprintk("res: put %d\n",bits);
-	up(&dev->lock);
+	mutex_unlock(&dev->lock);
 }
 
 /* ------------------------------------------------------------------ */
@@ -1340,21 +1339,21 @@
 		if (!list_empty(&fh->cap.stream))
 			buf = list_entry(fh->cap.stream.next, struct videobuf_buffer, stream);
 	} else {
-		down(&fh->cap.lock);
+		mutex_lock(&fh->cap.lock);
 		if (UNSET == fh->cap.read_off) {
 			/* need to capture a new frame */
 			if (res_locked(fh->dev,RESOURCE_VIDEO)) {
-				up(&fh->cap.lock);
+				mutex_unlock(&fh->cap.lock);
 				return POLLERR;
 			}
 			if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) {
-				up(&fh->cap.lock);
+				mutex_unlock(&fh->cap.lock);
 				return POLLERR;
 			}
 			fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
 			fh->cap.read_off = 0;
 		}
-		up(&fh->cap.lock);
+		mutex_unlock(&fh->cap.lock);
 		buf = fh->cap.read_buf;
 	}
 
@@ -1463,6 +1462,10 @@
 			f->fmt.pix.height * f->fmt.pix.bytesperline;
 		return 0;
 	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+		if (saa7134_no_overlay > 0) {
+			printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+			return -EINVAL;
+		}
 		f->fmt.win = fh->win;
 		return 0;
 	case V4L2_BUF_TYPE_VBI_CAPTURE:
@@ -1527,6 +1530,10 @@
 		return 0;
 	}
 	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+		if (saa7134_no_overlay > 0) {
+			printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+			return -EINVAL;
+		}
 		err = verify_preview(dev,&f->fmt.win);
 		if (0 != err)
 			return err;
@@ -1557,18 +1564,22 @@
 		fh->cap.field = f->fmt.pix.field;
 		return 0;
 	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+		if (saa7134_no_overlay > 0) {
+			printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+			return -EINVAL;
+		}
 		err = verify_preview(dev,&f->fmt.win);
 		if (0 != err)
 			return err;
 
-		down(&dev->lock);
+		mutex_lock(&dev->lock);
 		fh->win    = f->fmt.win;
 		fh->nclips = f->fmt.win.clipcount;
 		if (fh->nclips > 8)
 			fh->nclips = 8;
 		if (copy_from_user(fh->clips,f->fmt.win.clips,
 				   sizeof(struct v4l2_clip)*fh->nclips)) {
-			up(&dev->lock);
+			mutex_unlock(&dev->lock);
 			return -EFAULT;
 		}
 
@@ -1578,7 +1589,7 @@
 			start_preview(dev,fh);
 			spin_unlock_irqrestore(&dev->slock,flags);
 		}
-		up(&dev->lock);
+		mutex_unlock(&dev->lock);
 		return 0;
 	case V4L2_BUF_TYPE_VBI_CAPTURE:
 		saa7134_vbi_fmt(dev,f);
@@ -1612,9 +1623,9 @@
 		return get_control(dev,arg);
 	case VIDIOC_S_CTRL:
 	{
-		down(&dev->lock);
+		mutex_lock(&dev->lock);
 		err = set_control(dev,NULL,arg);
-		up(&dev->lock);
+		mutex_unlock(&dev->lock);
 		return err;
 	}
 	/* --- input switching --------------------------------------- */
@@ -1664,9 +1675,9 @@
 			return -EINVAL;
 		if (NULL == card_in(dev,*i).name)
 			return -EINVAL;
-		down(&dev->lock);
+		mutex_lock(&dev->lock);
 		video_mux(dev,*i);
-		up(&dev->lock);
+		mutex_unlock(&dev->lock);
 		return 0;
 	}
 
@@ -1716,11 +1727,13 @@
 		cap->version = SAA7134_VERSION_CODE;
 		cap->capabilities =
 			V4L2_CAP_VIDEO_CAPTURE |
-			V4L2_CAP_VIDEO_OVERLAY |
 			V4L2_CAP_VBI_CAPTURE |
 			V4L2_CAP_READWRITE |
 			V4L2_CAP_STREAMING |
 			V4L2_CAP_TUNER;
+		if (saa7134_no_overlay <= 0) {
+			cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
+		}
 
 		if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET))
 			cap->capabilities &= ~V4L2_CAP_TUNER;
@@ -1766,7 +1779,7 @@
 		if (i == TVNORMS)
 			return -EINVAL;
 
-		down(&dev->lock);
+		mutex_lock(&dev->lock);
 		if (res_check(fh, RESOURCE_OVERLAY)) {
 			spin_lock_irqsave(&dev->slock,flags);
 			stop_preview(dev,fh);
@@ -1776,7 +1789,7 @@
 		} else
 			set_tvnorm(dev,&tvnorms[i]);
 		saa7134_tvaudio_do_scan(dev);
-		up(&dev->lock);
+		mutex_unlock(&dev->lock);
 		return 0;
 	}
 
@@ -1909,13 +1922,13 @@
 			return -EINVAL;
 		if (1 == fh->radio && V4L2_TUNER_RADIO != f->type)
 			return -EINVAL;
-		down(&dev->lock);
+		mutex_lock(&dev->lock);
 		dev->ctl_freq = f->frequency;
 
 		saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,f);
 
 		saa7134_tvaudio_do_scan(dev);
-		up(&dev->lock);
+		mutex_unlock(&dev->lock);
 		return 0;
 	}
 
@@ -1971,6 +1984,10 @@
 		switch (type) {
 		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+			if (saa7134_no_overlay > 0) {
+				printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+				return -EINVAL;
+			}
 			if (index >= FORMATS)
 				return -EINVAL;
 			if (f->type == V4L2_BUF_TYPE_VIDEO_OVERLAY &&
@@ -2031,6 +2048,11 @@
 		int *on = arg;
 
 		if (*on) {
+			if (saa7134_no_overlay > 0) {
+				printk ("no_overlay\n");
+				return -EINVAL;
+			}
+
 			if (!res_get(dev,fh,RESOURCE_OVERLAY))
 				return -EBUSY;
 			spin_lock_irqsave(&dev->slock,flags);
@@ -2282,7 +2304,7 @@
 struct video_device saa7134_video_template =
 {
 	.name          = "saa7134-video",
-	.type          = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_OVERLAY|
+	.type          = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
 			 VID_TYPE_CLIPPING|VID_TYPE_SCALES,
 	.hardware      = 0,
 	.fops          = &video_fops,
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 3261d8b..17ba34f 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -29,6 +29,7 @@
 #include <linux/input.h>
 #include <linux/notifier.h>
 #include <linux/delay.h>
+#include <linux/mutex.h>
 
 #include <asm/io.h>
 
@@ -60,6 +61,7 @@
 	TVAUDIO_FM_K_STEREO   = 4,
 	TVAUDIO_NICAM_AM      = 5,
 	TVAUDIO_NICAM_FM      = 6,
+	TVAUDIO_AM_MONO	      = 7
 };
 
 enum saa7134_audio_in {
@@ -210,6 +212,15 @@
 #define SAA7134_BOARD_MSI_TVATANYWHERE_PLUS  82
 #define SAA7134_BOARD_CINERGY250PCI 83
 #define SAA7134_BOARD_FLYDVB_TRIO 84
+#define SAA7134_BOARD_AVERMEDIA_777 85
+#define SAA7134_BOARD_FLYDVBT_LR301 86
+#define SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331 87
+#define SAA7134_BOARD_TEVION_DVBT_220RF 88
+#define SAA7134_BOARD_ELSA_700TV       89
+#define SAA7134_BOARD_KWORLD_ATSC110   90
+#define SAA7134_BOARD_AVERMEDIA_A169_B 91
+#define SAA7134_BOARD_AVERMEDIA_A169_B1 92
+#define SAA7134_BOARD_MD7134_BRIDGE_2     93
 
 #define SAA7134_MAXBOARDS 8
 #define SAA7134_INPUT_MAX 8
@@ -359,7 +370,7 @@
 
 /* dmasound dsp status */
 struct saa7134_dmasound {
-	struct semaphore           lock;
+	struct mutex               lock;
 	int                        minor_mixer;
 	int                        minor_dsp;
 	unsigned int               users_dsp;
@@ -423,7 +434,7 @@
 /* global device status */
 struct saa7134_dev {
 	struct list_head           devlist;
-	struct semaphore           lock;
+	struct mutex               lock;
 	spinlock_t                 slock;
 #ifdef VIDIOC_G_PRIORITY
 	struct v4l2_prio_state     prio;
@@ -546,6 +557,7 @@
 /* saa7134-core.c                                              */
 
 extern struct list_head  saa7134_devlist;
+extern int saa7134_no_overlay;
 
 void saa7134_track_gpio(struct saa7134_dev *dev, char *msg);
 
diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c
index a796a4e..027c8a0 100644
--- a/drivers/media/video/tda8290.c
+++ b/drivers/media/video/tda8290.c
@@ -281,7 +281,7 @@
 static void tda8290_i2c_bridge(struct i2c_client *c, int close)
 {
 	unsigned char  enable[2] = { 0x21, 0xC0 };
-	unsigned char disable[2] = { 0x21, 0x80 };
+	unsigned char disable[2] = { 0x21, 0x00 };
 	unsigned char *msg;
 	if(close) {
 		msg = enable;
@@ -302,6 +302,7 @@
 	unsigned char soft_reset[]  = { 0x00, 0x00 };
 	unsigned char easy_mode[]   = { 0x01, t->tda8290_easy_mode };
 	unsigned char expert_mode[] = { 0x01, 0x80 };
+	unsigned char agc_out_on[]  = { 0x02, 0x00 };
 	unsigned char gainset_off[] = { 0x28, 0x14 };
 	unsigned char if_agc_spd[]  = { 0x0f, 0x88 };
 	unsigned char adc_head_6[]  = { 0x05, 0x04 };
@@ -320,6 +321,7 @@
 		      pll_stat;
 
 	i2c_master_send(c, easy_mode, 2);
+	i2c_master_send(c, agc_out_on, 2);
 	i2c_master_send(c, soft_reset, 2);
 	msleep(1);
 
@@ -470,6 +472,7 @@
 	struct tuner *t = i2c_get_clientdata(c);
 	unsigned char cb1[] = { 0x30, 0xD0 };
 	unsigned char tda8290_standby[] = { 0x00, 0x02 };
+	unsigned char tda8290_agc_tri[] = { 0x02, 0x20 };
 	struct i2c_msg msg = {.addr = t->tda827x_addr, .flags=0, .buf=cb1, .len = 2};
 
 	tda8290_i2c_bridge(c, 1);
@@ -477,6 +480,7 @@
 		cb1[1] = 0x90;
 	i2c_transfer(c->adapter, &msg, 1);
 	tda8290_i2c_bridge(c, 0);
+	i2c_master_send(c, tda8290_agc_tri, 2);
 	i2c_master_send(c, tda8290_standby, 2);
 }
 
@@ -565,7 +569,7 @@
 		strlcpy(c->name, "tda8290+75a", sizeof(c->name));
 		t->tda827x_ver = 2;
 	}
-	tuner_info("tuner: type set to %s\n", c->name);
+	tuner_info("type set to %s\n", c->name);
 
 	t->set_tv_freq    = set_tv_freq;
 	t->set_radio_freq = set_radio_freq;
diff --git a/drivers/media/video/tda9840.c b/drivers/media/video/tda9840.c
index ed4c0411..0243700 100644
--- a/drivers/media/video/tda9840.c
+++ b/drivers/media/video/tda9840.c
@@ -24,6 +24,7 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   */
 
+
 #include <linux/module.h>
 #include <linux/ioctl.h>
 #include <linux/i2c.h>
@@ -222,7 +223,7 @@
 
 static struct i2c_driver driver = {
 	.driver = {
-		.name	= "tda9840",
+		.name = "tda9840",
 	},
 	.id	= I2C_DRIVERID_TDA9840,
 	.attach_adapter	= attach,
diff --git a/drivers/media/video/tea6415c.c b/drivers/media/video/tea6415c.c
index bb35844..774ed0d 100644
--- a/drivers/media/video/tea6415c.c
+++ b/drivers/media/video/tea6415c.c
@@ -26,6 +26,7 @@
     Foundation, Inc., 675 Mvss Ave, Cambridge, MA 02139, USA.
   */
 
+
 #include <linux/module.h>
 #include <linux/ioctl.h>
 #include <linux/i2c.h>
@@ -107,7 +108,7 @@
 {
 	u8 byte = 0;
 	int ret;
-	
+
 	dprintk("adr:0x%02x, i:%d, o:%d\n", client->addr, i, o);
 
 	/* check if the pins are valid */
@@ -191,7 +192,7 @@
 
 static struct i2c_driver driver = {
 	.driver = {
-		.name 	= "tea6415c",
+		.name = "tea6415c",
 	},
 	.id 	= I2C_DRIVERID_TEA6415C,
 	.attach_adapter	= attach,
diff --git a/drivers/media/video/tea6420.c b/drivers/media/video/tea6420.c
index 4dcba5a..ad7d287 100644
--- a/drivers/media/video/tea6420.c
+++ b/drivers/media/video/tea6420.c
@@ -26,6 +26,7 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   */
 
+
 #include <linux/module.h>
 #include <linux/ioctl.h>
 #include <linux/i2c.h>
@@ -83,7 +84,7 @@
 		dprintk("i2c_smbus_write_byte() failed, ret:%d\n", ret);
 		return -EIO;
 	}
-	
+
 	return 0;
 }
 
@@ -167,7 +168,7 @@
 
 static struct i2c_driver driver = {
 	.driver = {
-		.name	= "tea6420",
+		.name = "tea6420",
 	},
 	.id	= I2C_DRIVERID_TEA6420,
 	.attach_adapter	= attach,
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index b6101bf..32e1849 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -173,7 +173,6 @@
 	}
 
 	t->type = type;
-
 	switch (t->type) {
 	case TUNER_MT2032:
 		microtune_init(c);
@@ -404,15 +403,16 @@
 	tuner_info("Tuner mode:      %s\n", p);
 	tuner_info("Frequency:       %lu.%02lu MHz\n", freq, freq_fraction);
 	tuner_info("Standard:        0x%08llx\n", t->std);
-	if (t->mode == V4L2_TUNER_RADIO) {
-		if (t->has_signal) {
-			tuner_info("Signal strength: %d\n", t->has_signal(client));
-		}
-		if (t->is_stereo) {
-			tuner_info("Stereo:          %s\n", t->is_stereo(client) ? "yes" : "no");
-		}
+	if (t->mode != V4L2_TUNER_RADIO)
+	       return;
+	if (t->has_signal) {
+		tuner_info("Signal strength: %d\n", t->has_signal(client));
+	}
+	if (t->is_stereo) {
+		tuner_info("Stereo:          %s\n", t->is_stereo(client) ? "yes" : "no");
 	}
 }
+
 /* ---------------------------------------------------------------------- */
 
 /* static var Used only in tuner_attach and tuner_probe */
@@ -744,33 +744,29 @@
 				return 0;
 			switch_v4l2();
 
-			if (V4L2_TUNER_RADIO == t->mode) {
-
-				if (t->has_signal)
-					tuner->signal = t->has_signal(client);
-
-				if (t->is_stereo) {
-					if (t->is_stereo(client)) {
-						tuner->rxsubchans =
-						    V4L2_TUNER_SUB_STEREO |
-						    V4L2_TUNER_SUB_MONO;
-					} else {
-						tuner->rxsubchans =
-						    V4L2_TUNER_SUB_MONO;
-					}
-				}
-
-				tuner->capability |=
-				    V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
-
-				tuner->audmode = t->audmode;
-
-				tuner->rangelow = radio_range[0] * 16000;
-				tuner->rangehigh = radio_range[1] * 16000;
-			} else {
+			tuner->type = t->mode;
+			if (t->mode != V4L2_TUNER_RADIO) {
 				tuner->rangelow = tv_range[0] * 16;
 				tuner->rangehigh = tv_range[1] * 16;
+				break;
 			}
+
+			/* radio mode */
+			if (t->has_signal)
+				tuner->signal = t->has_signal(client);
+
+			tuner->rxsubchans =
+				V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+			if (t->is_stereo) {
+				tuner->rxsubchans = t->is_stereo(client) ?
+					V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
+			}
+
+			tuner->capability |=
+			    V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+			tuner->audmode = t->audmode;
+			tuner->rangelow = radio_range[0] * 16000;
+			tuner->rangehigh = radio_range[1] * 16000;
 			break;
 		}
 	case VIDIOC_S_TUNER:
@@ -782,10 +778,11 @@
 
 			switch_v4l2();
 
-			if (V4L2_TUNER_RADIO == t->mode) {
-				t->audmode = tuner->audmode;
-				set_radio_freq(client, t->radio_freq);
-			}
+			/* do nothing unless we're a radio tuner */
+			if (t->mode != V4L2_TUNER_RADIO)
+				break;
+			t->audmode = tuner->audmode;
+			set_radio_freq(client, t->radio_freq);
 			break;
 		}
 	case VIDIOC_LOG_STATUS:
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
index 37977ff..5d7abed 100644
--- a/drivers/media/video/tuner-simple.c
+++ b/drivers/media/video/tuner-simple.c
@@ -79,17 +79,6 @@
 #define TUNER_PLL_LOCKED   0x40
 #define TUNER_STEREO_MK3   0x04
 
-#define TUNER_PARAM_ANALOG 0  /* to be removed */
-/* FIXME:
- * Right now, all tuners are using the first tuner_params[] array element
- * for analog mode. In the future, we will be merging similar tuner
- * definitions together, such that each tuner definition will have a
- * tuner_params struct for each available video standard. At that point,
- * TUNER_PARAM_ANALOG will be removed, and the tuner_params[] array
- * element will be chosen based on the video standard in use.
- *
- */
-
 /* ---------------------------------------------------------------------- */
 
 static int tuner_getstatus(struct i2c_client *c)
@@ -133,116 +122,14 @@
 static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
 {
 	struct tuner *t = i2c_get_clientdata(c);
-	u8 config, tuneraddr;
+	u8 config, cb, tuneraddr;
 	u16 div;
 	struct tunertype *tun;
 	u8 buffer[4];
 	int rc, IFPCoff, i, j;
+	enum param_type desired_type;
 
 	tun = &tuners[t->type];
-	j = TUNER_PARAM_ANALOG;
-
-	for (i = 0; i < tun->params[j].count; i++) {
-		if (freq > tun->params[j].ranges[i].limit)
-			continue;
-		break;
-	}
-	if (i == tun->params[j].count) {
-		tuner_dbg("TV frequency out of range (%d > %d)",
-				freq, tun->params[j].ranges[i - 1].limit);
-		freq = tun->params[j].ranges[--i].limit;
-	}
-	config = tun->params[j].ranges[i].cb;
-	/*  i == 0 -> VHF_LO  */
-	/*  i == 1 -> VHF_HI  */
-	/*  i == 2 -> UHF     */
-	tuner_dbg("tv: range %d\n",i);
-
-	/* tv norm specific stuff for multi-norm tuners */
-	switch (t->type) {
-	case TUNER_PHILIPS_SECAM: // FI1216MF
-		/* 0x01 -> ??? no change ??? */
-		/* 0x02 -> PAL BDGHI / SECAM L */
-		/* 0x04 -> ??? PAL others / SECAM others ??? */
-		config &= ~0x02;
-		if (t->std & V4L2_STD_SECAM)
-			config |= 0x02;
-		break;
-
-	case TUNER_TEMIC_4046FM5:
-		config &= ~0x0f;
-
-		if (t->std & V4L2_STD_PAL_BG) {
-			config |= TEMIC_SET_PAL_BG;
-
-		} else if (t->std & V4L2_STD_PAL_I) {
-			config |= TEMIC_SET_PAL_I;
-
-		} else if (t->std & V4L2_STD_PAL_DK) {
-			config |= TEMIC_SET_PAL_DK;
-
-		} else if (t->std & V4L2_STD_SECAM_L) {
-			config |= TEMIC_SET_PAL_L;
-
-		}
-		break;
-
-	case TUNER_PHILIPS_FQ1216ME:
-		config &= ~0x0f;
-
-		if (t->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) {
-			config |= PHILIPS_SET_PAL_BGDK;
-
-		} else if (t->std & V4L2_STD_PAL_I) {
-			config |= PHILIPS_SET_PAL_I;
-
-		} else if (t->std & V4L2_STD_SECAM_L) {
-			config |= PHILIPS_SET_PAL_L;
-
-		}
-		break;
-
-	case TUNER_PHILIPS_ATSC:
-		/* 0x00 -> ATSC antenna input 1 */
-		/* 0x01 -> ATSC antenna input 2 */
-		/* 0x02 -> NTSC antenna input 1 */
-		/* 0x03 -> NTSC antenna input 2 */
-		config &= ~0x03;
-		if (!(t->std & V4L2_STD_ATSC))
-			config |= 2;
-		/* FIXME: input */
-		break;
-
-	case TUNER_MICROTUNE_4042FI5:
-		/* Set the charge pump for fast tuning */
-		tun->params[j].config |= TUNER_CHARGE_PUMP;
-		break;
-
-	case TUNER_PHILIPS_TUV1236D:
-		/* 0x40 -> ATSC antenna input 1 */
-		/* 0x48 -> ATSC antenna input 2 */
-		/* 0x00 -> NTSC antenna input 1 */
-		/* 0x08 -> NTSC antenna input 2 */
-		buffer[0] = 0x14;
-		buffer[1] = 0x00;
-		buffer[2] = 0x17;
-		buffer[3] = 0x00;
-		config &= ~0x40;
-		if (t->std & V4L2_STD_ATSC) {
-			config |= 0x40;
-			buffer[1] = 0x04;
-		}
-		/* set to the correct mode (analog or digital) */
-		tuneraddr = c->addr;
-		c->addr = 0x0a;
-		if (2 != (rc = i2c_master_send(c,&buffer[0],2)))
-			tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
-		if (2 != (rc = i2c_master_send(c,&buffer[2],2)))
-			tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
-		c->addr = tuneraddr;
-		/* FIXME: input */
-		break;
-	}
 
 	/* IFPCoff = Video Intermediate Frequency - Vif:
 		940  =16*58.75  NTSC/J (Japan)
@@ -257,16 +144,49 @@
 	*/
 
 	if (t->std == V4L2_STD_NTSC_M_JP) {
-		IFPCoff = 940;
+		IFPCoff      = 940;
+		desired_type = TUNER_PARAM_TYPE_NTSC;
 	} else if ((t->std & V4L2_STD_MN) &&
 		  !(t->std & ~V4L2_STD_MN)) {
-		IFPCoff = 732;
+		IFPCoff      = 732;
+		desired_type = TUNER_PARAM_TYPE_NTSC;
 	} else if (t->std == V4L2_STD_SECAM_LC) {
-		IFPCoff = 543;
+		IFPCoff      = 543;
+		desired_type = TUNER_PARAM_TYPE_SECAM;
 	} else {
-		IFPCoff = 623;
+		IFPCoff      = 623;
+		desired_type = TUNER_PARAM_TYPE_PAL;
 	}
 
+	for (j = 0; j < tun->count-1; j++) {
+		if (desired_type != tun->params[j].type)
+			continue;
+		break;
+	}
+	/* use default tuner_params if desired_type not available */
+	if (desired_type != tun->params[j].type) {
+		tuner_dbg("IFPCoff = %d: tuner_params undefined for tuner %d\n",
+			  IFPCoff,t->type);
+		j = 0;
+	}
+
+	for (i = 0; i < tun->params[j].count; i++) {
+		if (freq > tun->params[j].ranges[i].limit)
+			continue;
+		break;
+	}
+	if (i == tun->params[j].count) {
+		tuner_dbg("TV frequency out of range (%d > %d)",
+				freq, tun->params[j].ranges[i - 1].limit);
+		freq = tun->params[j].ranges[--i].limit;
+	}
+	config = tun->params[j].ranges[i].config;
+	cb     = tun->params[j].ranges[i].cb;
+	/*  i == 0 -> VHF_LO
+	 *  i == 1 -> VHF_HI
+	 *  i == 2 -> UHF     */
+	tuner_dbg("tv: param %d, range %d\n",j,i);
+
 	div=freq + IFPCoff + offset;
 
 	tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, Offset=%d.%02d MHz, div=%0d\n",
@@ -275,16 +195,102 @@
 					offset / 16, offset % 16 * 100 / 16,
 					div);
 
+	/* tv norm specific stuff for multi-norm tuners */
+	switch (t->type) {
+	case TUNER_PHILIPS_SECAM: // FI1216MF
+		/* 0x01 -> ??? no change ??? */
+		/* 0x02 -> PAL BDGHI / SECAM L */
+		/* 0x04 -> ??? PAL others / SECAM others ??? */
+		cb &= ~0x02;
+		if (t->std & V4L2_STD_SECAM)
+			cb |= 0x02;
+		break;
+
+	case TUNER_TEMIC_4046FM5:
+		cb &= ~0x0f;
+
+		if (t->std & V4L2_STD_PAL_BG) {
+			cb |= TEMIC_SET_PAL_BG;
+
+		} else if (t->std & V4L2_STD_PAL_I) {
+			cb |= TEMIC_SET_PAL_I;
+
+		} else if (t->std & V4L2_STD_PAL_DK) {
+			cb |= TEMIC_SET_PAL_DK;
+
+		} else if (t->std & V4L2_STD_SECAM_L) {
+			cb |= TEMIC_SET_PAL_L;
+
+		}
+		break;
+
+	case TUNER_PHILIPS_FQ1216ME:
+		cb &= ~0x0f;
+
+		if (t->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) {
+			cb |= PHILIPS_SET_PAL_BGDK;
+
+		} else if (t->std & V4L2_STD_PAL_I) {
+			cb |= PHILIPS_SET_PAL_I;
+
+		} else if (t->std & V4L2_STD_SECAM_L) {
+			cb |= PHILIPS_SET_PAL_L;
+
+		}
+		break;
+
+	case TUNER_PHILIPS_ATSC:
+		/* 0x00 -> ATSC antenna input 1 */
+		/* 0x01 -> ATSC antenna input 2 */
+		/* 0x02 -> NTSC antenna input 1 */
+		/* 0x03 -> NTSC antenna input 2 */
+		cb &= ~0x03;
+		if (!(t->std & V4L2_STD_ATSC))
+			cb |= 2;
+		/* FIXME: input */
+		break;
+
+	case TUNER_MICROTUNE_4042FI5:
+		/* Set the charge pump for fast tuning */
+		config |= TUNER_CHARGE_PUMP;
+		break;
+
+	case TUNER_PHILIPS_TUV1236D:
+		/* 0x40 -> ATSC antenna input 1 */
+		/* 0x48 -> ATSC antenna input 2 */
+		/* 0x00 -> NTSC antenna input 1 */
+		/* 0x08 -> NTSC antenna input 2 */
+		buffer[0] = 0x14;
+		buffer[1] = 0x00;
+		buffer[2] = 0x17;
+		buffer[3] = 0x00;
+		cb &= ~0x40;
+		if (t->std & V4L2_STD_ATSC) {
+			cb |= 0x40;
+			buffer[1] = 0x04;
+		}
+		/* set to the correct mode (analog or digital) */
+		tuneraddr = c->addr;
+		c->addr = 0x0a;
+		if (2 != (rc = i2c_master_send(c,&buffer[0],2)))
+			tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
+		if (2 != (rc = i2c_master_send(c,&buffer[2],2)))
+			tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
+		c->addr = tuneraddr;
+		/* FIXME: input */
+		break;
+	}
+
 	if (tuners[t->type].params->cb_first_if_lower_freq && div < t->last_div) {
-		buffer[0] = tun->params[j].config;
-		buffer[1] = config;
+		buffer[0] = config;
+		buffer[1] = cb;
 		buffer[2] = (div>>8) & 0x7f;
 		buffer[3] = div      & 0xff;
 	} else {
 		buffer[0] = (div>>8) & 0x7f;
 		buffer[1] = div      & 0xff;
-		buffer[2] = tun->params[j].config;
-		buffer[3] = config;
+		buffer[2] = config;
+		buffer[3] = cb;
 	}
 	t->last_div = div;
 	tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
@@ -312,11 +318,11 @@
 		}
 
 		/* Set the charge pump for optimized phase noise figure */
-		tun->params[j].config &= ~TUNER_CHARGE_PUMP;
+		config &= ~TUNER_CHARGE_PUMP;
 		buffer[0] = (div>>8) & 0x7f;
 		buffer[1] = div      & 0xff;
-		buffer[2] = tun->params[j].config;
-		buffer[3] = config;
+		buffer[2] = config;
+		buffer[3] = cb;
 		tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
 		       buffer[0],buffer[1],buffer[2],buffer[3]);
 
@@ -332,12 +338,21 @@
 	u8 buffer[4];
 	u16 div;
 	int rc, j;
+	enum param_type desired_type = TUNER_PARAM_TYPE_RADIO;
 
 	tun = &tuners[t->type];
-	j = TUNER_PARAM_ANALOG;
+
+	for (j = 0; j < tun->count-1; j++) {
+		if (desired_type != tun->params[j].type)
+			continue;
+		break;
+	}
+	/* use default tuner_params if desired_type not available */
+	if (desired_type != tun->params[j].type)
+		j = 0;
 
 	div = (20 * freq / 16000) + (int)(20*10.7); /* IF 10.7 MHz */
-	buffer[2] = (tun->params[j].config & ~TUNER_RATIO_MASK) | TUNER_RATIO_SELECT_50; /* 50 kHz step */
+	buffer[2] = (tun->params[j].ranges[0].config & ~TUNER_RATIO_MASK) | TUNER_RATIO_SELECT_50; /* 50 kHz step */
 
 	switch (t->type) {
 	case TUNER_TENA_9533_DI:
@@ -349,6 +364,9 @@
 	case TUNER_PHILIPS_FMD1216ME_MK3:
 		buffer[3] = 0x19;
 		break;
+	case TUNER_TNF_5335MF:
+		buffer[3] = 0x11;
+		break;
 	case TUNER_PHILIPS_FM1256_IH3:
 		div = (20 * freq) / 16000 + (int)(33.3 * 20);  /* IF 33.3 MHz */
 		buffer[3] = 0x19;
diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c
index 6fe7817..72e0f01d 100644
--- a/drivers/media/video/tuner-types.c
+++ b/drivers/media/video/tuner-types.c
@@ -23,22 +23,25 @@
  *	Each tuner_params array may contain one or more elements, one
  *	for each video standard.
  *
- *	FIXME: Some tuner_range definitions are duplicated, and
- *	should be eliminated.
+ *	FIXME: tuner_params struct contains an element, tda988x. We must
+ *	set this for all tuners that contain a tda988x chip, and then we
+ *	can remove this setting from the various card structs.
  *
- *	FIXME: tunertype struct contains an element, has_tda988x.
- *	We must set this for all tunertypes that contain a tda988x
- *	chip, and then we can remove this setting from the various
- *	card structs.
+ *	FIXME: Right now, all tuners are using the first tuner_params[]
+ *	array element for analog mode. In the future, we will be merging
+ *	similar tuner definitions together, such that each tuner definition
+ *	will have a tuner_params struct for each available video standard.
+ *	At that point, the tuner_params[] array element will be chosen
+ *	based on the video standard in use.
  */
 
 /* 0-9 */
 /* ------------ TUNER_TEMIC_PAL - TEMIC PAL ------------ */
 
 static struct tuner_range tuner_temic_pal_ranges[] = {
-	{ 16 * 140.25 /*MHz*/, 0x02, },
-	{ 16 * 463.25 /*MHz*/, 0x04, },
-	{ 16 * 999.99        , 0x01, },
+	{ 16 * 140.25 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 463.25 /*MHz*/, 0x8e, 0x04, },
+	{ 16 * 999.99        , 0x8e, 0x01, },
 };
 
 static struct tuner_params tuner_temic_pal_params[] = {
@@ -46,16 +49,15 @@
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_temic_pal_ranges,
 		.count  = ARRAY_SIZE(tuner_temic_pal_ranges),
-		.config = 0x8e,
 	},
 };
 
 /* ------------ TUNER_PHILIPS_PAL_I - Philips PAL_I ------------ */
 
 static struct tuner_range tuner_philips_pal_i_ranges[] = {
-	{ 16 * 140.25 /*MHz*/, 0xa0, },
-	{ 16 * 463.25 /*MHz*/, 0x90, },
-	{ 16 * 999.99        , 0x30, },
+	{ 16 * 140.25 /*MHz*/, 0x8e, 0xa0, },
+	{ 16 * 463.25 /*MHz*/, 0x8e, 0x90, },
+	{ 16 * 999.99        , 0x8e, 0x30, },
 };
 
 static struct tuner_params tuner_philips_pal_i_params[] = {
@@ -63,16 +65,15 @@
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_philips_pal_i_ranges,
 		.count  = ARRAY_SIZE(tuner_philips_pal_i_ranges),
-		.config = 0x8e,
 	},
 };
 
 /* ------------ TUNER_PHILIPS_NTSC - Philips NTSC ------------ */
 
 static struct tuner_range tuner_philips_ntsc_ranges[] = {
-	{ 16 * 157.25 /*MHz*/, 0xa0, },
-	{ 16 * 451.25 /*MHz*/, 0x90, },
-	{ 16 * 999.99        , 0x30, },
+	{ 16 * 157.25 /*MHz*/, 0x8e, 0xa0, },
+	{ 16 * 451.25 /*MHz*/, 0x8e, 0x90, },
+	{ 16 * 999.99        , 0x8e, 0x30, },
 };
 
 static struct tuner_params tuner_philips_ntsc_params[] = {
@@ -80,7 +81,6 @@
 		.type   = TUNER_PARAM_TYPE_NTSC,
 		.ranges = tuner_philips_ntsc_ranges,
 		.count  = ARRAY_SIZE(tuner_philips_ntsc_ranges),
-		.config = 0x8e,
 		.cb_first_if_lower_freq = 1,
 	},
 };
@@ -88,9 +88,9 @@
 /* ------------ TUNER_PHILIPS_SECAM - Philips SECAM ------------ */
 
 static struct tuner_range tuner_philips_secam_ranges[] = {
-	{ 16 * 168.25 /*MHz*/, 0xa7, },
-	{ 16 * 447.25 /*MHz*/, 0x97, },
-	{ 16 * 999.99        , 0x37, },
+	{ 16 * 168.25 /*MHz*/, 0x8e, 0xa7, },
+	{ 16 * 447.25 /*MHz*/, 0x8e, 0x97, },
+	{ 16 * 999.99        , 0x8e, 0x37, },
 };
 
 static struct tuner_params tuner_philips_secam_params[] = {
@@ -98,7 +98,6 @@
 		.type   = TUNER_PARAM_TYPE_SECAM,
 		.ranges = tuner_philips_secam_ranges,
 		.count  = ARRAY_SIZE(tuner_philips_secam_ranges),
-		.config = 0x8e,
 		.cb_first_if_lower_freq = 1,
 	},
 };
@@ -106,9 +105,9 @@
 /* ------------ TUNER_PHILIPS_PAL - Philips PAL ------------ */
 
 static struct tuner_range tuner_philips_pal_ranges[] = {
-	{ 16 * 168.25 /*MHz*/, 0xa0, },
-	{ 16 * 447.25 /*MHz*/, 0x90, },
-	{ 16 * 999.99        , 0x30, },
+	{ 16 * 168.25 /*MHz*/, 0x8e, 0xa0, },
+	{ 16 * 447.25 /*MHz*/, 0x8e, 0x90, },
+	{ 16 * 999.99        , 0x8e, 0x30, },
 };
 
 static struct tuner_params tuner_philips_pal_params[] = {
@@ -116,7 +115,6 @@
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_philips_pal_ranges,
 		.count  = ARRAY_SIZE(tuner_philips_pal_ranges),
-		.config = 0x8e,
 		.cb_first_if_lower_freq = 1,
 	},
 };
@@ -124,9 +122,9 @@
 /* ------------ TUNER_TEMIC_NTSC - TEMIC NTSC ------------ */
 
 static struct tuner_range tuner_temic_ntsc_ranges[] = {
-	{ 16 * 157.25 /*MHz*/, 0x02, },
-	{ 16 * 463.25 /*MHz*/, 0x04, },
-	{ 16 * 999.99        , 0x01, },
+	{ 16 * 157.25 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 463.25 /*MHz*/, 0x8e, 0x04, },
+	{ 16 * 999.99        , 0x8e, 0x01, },
 };
 
 static struct tuner_params tuner_temic_ntsc_params[] = {
@@ -134,16 +132,15 @@
 		.type   = TUNER_PARAM_TYPE_NTSC,
 		.ranges = tuner_temic_ntsc_ranges,
 		.count  = ARRAY_SIZE(tuner_temic_ntsc_ranges),
-		.config = 0x8e,
 	},
 };
 
 /* ------------ TUNER_TEMIC_PAL_I - TEMIC PAL_I ------------ */
 
 static struct tuner_range tuner_temic_pal_i_ranges[] = {
-	{ 16 * 170.00 /*MHz*/, 0x02, },
-	{ 16 * 450.00 /*MHz*/, 0x04, },
-	{ 16 * 999.99        , 0x01, },
+	{ 16 * 170.00 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 450.00 /*MHz*/, 0x8e, 0x04, },
+	{ 16 * 999.99        , 0x8e, 0x01, },
 };
 
 static struct tuner_params tuner_temic_pal_i_params[] = {
@@ -151,16 +148,15 @@
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_temic_pal_i_ranges,
 		.count  = ARRAY_SIZE(tuner_temic_pal_i_ranges),
-		.config = 0x8e,
 	},
 };
 
 /* ------------ TUNER_TEMIC_4036FY5_NTSC - TEMIC NTSC ------------ */
 
 static struct tuner_range tuner_temic_4036fy5_ntsc_ranges[] = {
-	{ 16 * 157.25 /*MHz*/, 0xa0, },
-	{ 16 * 463.25 /*MHz*/, 0x90, },
-	{ 16 * 999.99        , 0x30, },
+	{ 16 * 157.25 /*MHz*/, 0x8e, 0xa0, },
+	{ 16 * 463.25 /*MHz*/, 0x8e, 0x90, },
+	{ 16 * 999.99        , 0x8e, 0x30, },
 };
 
 static struct tuner_params tuner_temic_4036fy5_ntsc_params[] = {
@@ -168,16 +164,15 @@
 		.type   = TUNER_PARAM_TYPE_NTSC,
 		.ranges = tuner_temic_4036fy5_ntsc_ranges,
 		.count  = ARRAY_SIZE(tuner_temic_4036fy5_ntsc_ranges),
-		.config = 0x8e,
 	},
 };
 
 /* ------------ TUNER_ALPS_TSBH1_NTSC - TEMIC NTSC ------------ */
 
 static struct tuner_range tuner_alps_tsb_1_ranges[] = {
-	{ 16 * 137.25 /*MHz*/, 0x01, },
-	{ 16 * 385.25 /*MHz*/, 0x02, },
-	{ 16 * 999.99        , 0x08, },
+	{ 16 * 137.25 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 385.25 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 999.99        , 0x8e, 0x08, },
 };
 
 static struct tuner_params tuner_alps_tsbh1_ntsc_params[] = {
@@ -185,7 +180,6 @@
 		.type   = TUNER_PARAM_TYPE_NTSC,
 		.ranges = tuner_alps_tsb_1_ranges,
 		.count  = ARRAY_SIZE(tuner_alps_tsb_1_ranges),
-		.config = 0x8e,
 	},
 };
 
@@ -197,16 +191,15 @@
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_alps_tsb_1_ranges,
 		.count  = ARRAY_SIZE(tuner_alps_tsb_1_ranges),
-		.config = 0x8e,
 	},
 };
 
 /* ------------ TUNER_ALPS_TSBB5_PAL_I - Alps PAL_I ------------ */
 
 static struct tuner_range tuner_alps_tsb_5_pal_ranges[] = {
-	{ 16 * 133.25 /*MHz*/, 0x01, },
-	{ 16 * 351.25 /*MHz*/, 0x02, },
-	{ 16 * 999.99        , 0x08, },
+	{ 16 * 133.25 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 351.25 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 999.99        , 0x8e, 0x08, },
 };
 
 static struct tuner_params tuner_alps_tsbb5_params[] = {
@@ -214,7 +207,6 @@
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_alps_tsb_5_pal_ranges,
 		.count  = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges),
-		.config = 0x8e,
 	},
 };
 
@@ -225,7 +217,6 @@
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_alps_tsb_5_pal_ranges,
 		.count  = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges),
-		.config = 0x8e,
 	},
 };
 
@@ -236,33 +227,31 @@
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_alps_tsb_5_pal_ranges,
 		.count  = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges),
-		.config = 0x8e,
 	},
 };
 
 /* ------------ TUNER_TEMIC_4006FH5_PAL - TEMIC PAL ------------ */
 
-static struct tuner_range tuner_temic_4006fh5_pal_ranges[] = {
-	{ 16 * 170.00 /*MHz*/, 0xa0, },
-	{ 16 * 450.00 /*MHz*/, 0x90, },
-	{ 16 * 999.99        , 0x30, },
+static struct tuner_range tuner_lg_pal_ranges[] = {
+	{ 16 * 170.00 /*MHz*/, 0x8e, 0xa0, },
+	{ 16 * 450.00 /*MHz*/, 0x8e, 0x90, },
+	{ 16 * 999.99        , 0x8e, 0x30, },
 };
 
 static struct tuner_params tuner_temic_4006fh5_params[] = {
 	{
 		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_temic_4006fh5_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_temic_4006fh5_pal_ranges),
-		.config = 0x8e,
+		.ranges = tuner_lg_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_lg_pal_ranges),
 	},
 };
 
 /* ------------ TUNER_ALPS_TSHC6_NTSC - Alps NTSC ------------ */
 
 static struct tuner_range tuner_alps_tshc6_ntsc_ranges[] = {
-	{ 16 * 137.25 /*MHz*/, 0x14, },
-	{ 16 * 385.25 /*MHz*/, 0x12, },
-	{ 16 * 999.99        , 0x11, },
+	{ 16 * 137.25 /*MHz*/, 0x8e, 0x14, },
+	{ 16 * 385.25 /*MHz*/, 0x8e, 0x12, },
+	{ 16 * 999.99        , 0x8e, 0x11, },
 };
 
 static struct tuner_params tuner_alps_tshc6_params[] = {
@@ -270,16 +259,15 @@
 		.type   = TUNER_PARAM_TYPE_NTSC,
 		.ranges = tuner_alps_tshc6_ntsc_ranges,
 		.count  = ARRAY_SIZE(tuner_alps_tshc6_ntsc_ranges),
-		.config = 0x8e,
 	},
 };
 
 /* ------------ TUNER_TEMIC_PAL_DK - TEMIC PAL ------------ */
 
 static struct tuner_range tuner_temic_pal_dk_ranges[] = {
-	{ 16 * 168.25 /*MHz*/, 0xa0, },
-	{ 16 * 456.25 /*MHz*/, 0x90, },
-	{ 16 * 999.99        , 0x30, },
+	{ 16 * 168.25 /*MHz*/, 0x8e, 0xa0, },
+	{ 16 * 456.25 /*MHz*/, 0x8e, 0x90, },
+	{ 16 * 999.99        , 0x8e, 0x30, },
 };
 
 static struct tuner_params tuner_temic_pal_dk_params[] = {
@@ -287,16 +275,15 @@
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_temic_pal_dk_ranges,
 		.count  = ARRAY_SIZE(tuner_temic_pal_dk_ranges),
-		.config = 0x8e,
 	},
 };
 
 /* ------------ TUNER_PHILIPS_NTSC_M - Philips NTSC ------------ */
 
 static struct tuner_range tuner_philips_ntsc_m_ranges[] = {
-	{ 16 * 160.00 /*MHz*/, 0xa0, },
-	{ 16 * 454.00 /*MHz*/, 0x90, },
-	{ 16 * 999.99        , 0x30, },
+	{ 16 * 160.00 /*MHz*/, 0x8e, 0xa0, },
+	{ 16 * 454.00 /*MHz*/, 0x8e, 0x90, },
+	{ 16 * 999.99        , 0x8e, 0x30, },
 };
 
 static struct tuner_params tuner_philips_ntsc_m_params[] = {
@@ -304,16 +291,15 @@
 		.type   = TUNER_PARAM_TYPE_NTSC,
 		.ranges = tuner_philips_ntsc_m_ranges,
 		.count  = ARRAY_SIZE(tuner_philips_ntsc_m_ranges),
-		.config = 0x8e,
 	},
 };
 
 /* ------------ TUNER_TEMIC_4066FY5_PAL_I - TEMIC PAL_I ------------ */
 
 static struct tuner_range tuner_temic_40x6f_5_pal_ranges[] = {
-	{ 16 * 169.00 /*MHz*/, 0xa0, },
-	{ 16 * 454.00 /*MHz*/, 0x90, },
-	{ 16 * 999.99        , 0x30, },
+	{ 16 * 169.00 /*MHz*/, 0x8e, 0xa0, },
+	{ 16 * 454.00 /*MHz*/, 0x8e, 0x90, },
+	{ 16 * 999.99        , 0x8e, 0x30, },
 };
 
 static struct tuner_params tuner_temic_4066fy5_pal_i_params[] = {
@@ -321,7 +307,6 @@
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_temic_40x6f_5_pal_ranges,
 		.count  = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges),
-		.config = 0x8e,
 	},
 };
 
@@ -332,7 +317,6 @@
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_temic_40x6f_5_pal_ranges,
 		.count  = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges),
-		.config = 0x8e,
 	},
 };
 
@@ -340,9 +324,9 @@
 /* ------------ TUNER_TEMIC_4009FR5_PAL - TEMIC PAL ------------ */
 
 static struct tuner_range tuner_temic_4009f_5_pal_ranges[] = {
-	{ 16 * 141.00 /*MHz*/, 0xa0, },
-	{ 16 * 464.00 /*MHz*/, 0x90, },
-	{ 16 * 999.99        , 0x30, },
+	{ 16 * 141.00 /*MHz*/, 0x8e, 0xa0, },
+	{ 16 * 464.00 /*MHz*/, 0x8e, 0x90, },
+	{ 16 * 999.99        , 0x8e, 0x30, },
 };
 
 static struct tuner_params tuner_temic_4009f_5_params[] = {
@@ -350,58 +334,42 @@
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_temic_4009f_5_pal_ranges,
 		.count  = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges),
-		.config = 0x8e,
 	},
 };
 
 /* ------------ TUNER_TEMIC_4039FR5_NTSC - TEMIC NTSC ------------ */
 
-static struct tuner_range tuner_temic_4039fr5_ntsc_ranges[] = {
-	{ 16 * 158.00 /*MHz*/, 0xa0, },
-	{ 16 * 453.00 /*MHz*/, 0x90, },
-	{ 16 * 999.99        , 0x30, },
+static struct tuner_range tuner_temic_4x3x_f_5_ntsc_ranges[] = {
+	{ 16 * 158.00 /*MHz*/, 0x8e, 0xa0, },
+	{ 16 * 453.00 /*MHz*/, 0x8e, 0x90, },
+	{ 16 * 999.99        , 0x8e, 0x30, },
 };
 
 static struct tuner_params tuner_temic_4039fr5_params[] = {
 	{
 		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_temic_4039fr5_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_temic_4039fr5_ntsc_ranges),
-		.config = 0x8e,
+		.ranges = tuner_temic_4x3x_f_5_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_temic_4x3x_f_5_ntsc_ranges),
 	},
 };
 
 /* ------------ TUNER_TEMIC_4046FM5 - TEMIC PAL ------------ */
 
-static struct tuner_range tuner_temic_4046fm5_pal_ranges[] = {
-	{ 16 * 169.00 /*MHz*/, 0xa0, },
-	{ 16 * 454.00 /*MHz*/, 0x90, },
-	{ 16 * 999.99        , 0x30, },
-};
-
 static struct tuner_params tuner_temic_4046fm5_params[] = {
 	{
 		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_temic_4046fm5_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_temic_4046fm5_pal_ranges),
-		.config = 0x8e,
+		.ranges = tuner_temic_40x6f_5_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges),
 	},
 };
 
 /* ------------ TUNER_PHILIPS_PAL_DK - Philips PAL ------------ */
 
-static struct tuner_range tuner_lg_pal_ranges[] = {
-	{ 16 * 170.00 /*MHz*/, 0xa0, },
-	{ 16 * 450.00 /*MHz*/, 0x90, },
-	{ 16 * 999.99        , 0x30, },
-};
-
 static struct tuner_params tuner_philips_pal_dk_params[] = {
 	{
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_lg_pal_ranges,
 		.count  = ARRAY_SIZE(tuner_lg_pal_ranges),
-		.config = 0x8e,
 	},
 };
 
@@ -412,7 +380,6 @@
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_lg_pal_ranges,
 		.count  = ARRAY_SIZE(tuner_lg_pal_ranges),
-		.config = 0x8e,
 	},
 };
 
@@ -423,7 +390,6 @@
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_lg_pal_ranges,
 		.count  = ARRAY_SIZE(tuner_lg_pal_ranges),
-		.config = 0x8e,
 	},
 };
 
@@ -434,16 +400,15 @@
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_lg_pal_ranges,
 		.count  = ARRAY_SIZE(tuner_lg_pal_ranges),
-		.config = 0x8e,
 	},
 };
 
 /* ------------ TUNER_LG_NTSC_FM - LGINNOTEK NTSC ------------ */
 
 static struct tuner_range tuner_lg_ntsc_fm_ranges[] = {
-	{ 16 * 210.00 /*MHz*/, 0xa0, },
-	{ 16 * 497.00 /*MHz*/, 0x90, },
-	{ 16 * 999.99        , 0x30, },
+	{ 16 * 210.00 /*MHz*/, 0x8e, 0xa0, },
+	{ 16 * 497.00 /*MHz*/, 0x8e, 0x90, },
+	{ 16 * 999.99        , 0x8e, 0x30, },
 };
 
 static struct tuner_params tuner_lg_ntsc_fm_params[] = {
@@ -451,7 +416,6 @@
 		.type   = TUNER_PARAM_TYPE_NTSC,
 		.ranges = tuner_lg_ntsc_fm_ranges,
 		.count  = ARRAY_SIZE(tuner_lg_ntsc_fm_ranges),
-		.config = 0x8e,
 	},
 };
 
@@ -462,7 +426,6 @@
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_lg_pal_ranges,
 		.count  = ARRAY_SIZE(tuner_lg_pal_ranges),
-		.config = 0x8e,
 	},
 };
 
@@ -473,7 +436,6 @@
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_lg_pal_ranges,
 		.count  = ARRAY_SIZE(tuner_lg_pal_ranges),
-		.config = 0x8e,
 	},
 };
 
@@ -485,16 +447,15 @@
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_temic_4009f_5_pal_ranges,
 		.count  = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges),
-		.config = 0x8e,
 	},
 };
 
 /* ------------ TUNER_SHARP_2U5JF5540_NTSC - SHARP NTSC ------------ */
 
 static struct tuner_range tuner_sharp_2u5jf5540_ntsc_ranges[] = {
-	{ 16 * 137.25 /*MHz*/, 0x01, },
-	{ 16 * 317.25 /*MHz*/, 0x02, },
-	{ 16 * 999.99        , 0x08, },
+	{ 16 * 137.25 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 317.25 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 999.99        , 0x8e, 0x08, },
 };
 
 static struct tuner_params tuner_sharp_2u5jf5540_params[] = {
@@ -502,16 +463,15 @@
 		.type   = TUNER_PARAM_TYPE_NTSC,
 		.ranges = tuner_sharp_2u5jf5540_ntsc_ranges,
 		.count  = ARRAY_SIZE(tuner_sharp_2u5jf5540_ntsc_ranges),
-		.config = 0x8e,
 	},
 };
 
 /* ------------ TUNER_Samsung_PAL_TCPM9091PD27 - Samsung PAL ------------ */
 
 static struct tuner_range tuner_samsung_pal_tcpm9091pd27_ranges[] = {
-	{ 16 * 169 /*MHz*/, 0xa0, },
-	{ 16 * 464 /*MHz*/, 0x90, },
-	{ 16 * 999.99     , 0x30, },
+	{ 16 * 169 /*MHz*/, 0x8e, 0xa0, },
+	{ 16 * 464 /*MHz*/, 0x8e, 0x90, },
+	{ 16 * 999.99     , 0x8e, 0x30, },
 };
 
 static struct tuner_params tuner_samsung_pal_tcpm9091pd27_params[] = {
@@ -519,7 +479,6 @@
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_samsung_pal_tcpm9091pd27_ranges,
 		.count  = ARRAY_SIZE(tuner_samsung_pal_tcpm9091pd27_ranges),
-		.config = 0x8e,
 	},
 };
 
@@ -530,50 +489,35 @@
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_temic_4009f_5_pal_ranges,
 		.count  = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges),
-		.config = 0x8e,
 	},
 };
 
 /* ------------ TUNER_TEMIC_4012FY5 - TEMIC PAL ------------ */
 
-static struct tuner_range tuner_temic_4012fy5_pal_ranges[] = {
-	{ 16 * 140.25 /*MHz*/, 0x02, },
-	{ 16 * 463.25 /*MHz*/, 0x04, },
-	{ 16 * 999.99        , 0x01, },
-};
-
 static struct tuner_params tuner_temic_4012fy5_params[] = {
 	{
 		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_temic_4012fy5_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_temic_4012fy5_pal_ranges),
-		.config = 0x8e,
+		.ranges = tuner_temic_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_temic_pal_ranges),
 	},
 };
 
 /* ------------ TUNER_TEMIC_4136FY5 - TEMIC NTSC ------------ */
 
-static struct tuner_range tuner_temic_4136_fy5_ntsc_ranges[] = {
-	{ 16 * 158.00 /*MHz*/, 0xa0, },
-	{ 16 * 453.00 /*MHz*/, 0x90, },
-	{ 16 * 999.99        , 0x30, },
-};
-
 static struct tuner_params tuner_temic_4136_fy5_params[] = {
 	{
 		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_temic_4136_fy5_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_temic_4136_fy5_ntsc_ranges),
-		.config = 0x8e,
+		.ranges = tuner_temic_4x3x_f_5_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_temic_4x3x_f_5_ntsc_ranges),
 	},
 };
 
 /* ------------ TUNER_LG_PAL_NEW_TAPC - LGINNOTEK PAL ------------ */
 
 static struct tuner_range tuner_lg_new_tapc_ranges[] = {
-	{ 16 * 170.00 /*MHz*/, 0x01, },
-	{ 16 * 450.00 /*MHz*/, 0x02, },
-	{ 16 * 999.99        , 0x08, },
+	{ 16 * 170.00 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 450.00 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 999.99        , 0x8e, 0x08, },
 };
 
 static struct tuner_params tuner_lg_pal_new_tapc_params[] = {
@@ -581,16 +525,15 @@
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_lg_new_tapc_ranges,
 		.count  = ARRAY_SIZE(tuner_lg_new_tapc_ranges),
-		.config = 0x8e,
 	},
 };
 
 /* ------------ TUNER_PHILIPS_FM1216ME_MK3 - Philips PAL ------------ */
 
 static struct tuner_range tuner_fm1216me_mk3_pal_ranges[] = {
-	{ 16 * 158.00 /*MHz*/, 0x01, },
-	{ 16 * 442.00 /*MHz*/, 0x02, },
-	{ 16 * 999.99        , 0x04, },
+	{ 16 * 158.00 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 442.00 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 999.99        , 0x8e, 0x04, },
 };
 
 static struct tuner_params tuner_fm1216me_mk3_params[] = {
@@ -598,7 +541,6 @@
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_fm1216me_mk3_pal_ranges,
 		.count  = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges),
-		.config = 0x8e,
 		.cb_first_if_lower_freq = 1,
 	},
 };
@@ -610,7 +552,6 @@
 		.type   = TUNER_PARAM_TYPE_NTSC,
 		.ranges = tuner_lg_new_tapc_ranges,
 		.count  = ARRAY_SIZE(tuner_lg_new_tapc_ranges),
-		.config = 0x8e,
 	},
 };
 
@@ -622,16 +563,15 @@
 		.type   = TUNER_PARAM_TYPE_NTSC,
 		.ranges = tuner_lg_new_tapc_ranges,
 		.count  = ARRAY_SIZE(tuner_lg_new_tapc_ranges),
-		.config = 0x8e,
 	},
 };
 
 /* ------------ TUNER_PHILIPS_PAL_MK - Philips PAL ------------ */
 
 static struct tuner_range tuner_philips_pal_mk_pal_ranges[] = {
-	{ 16 * 140.25 /*MHz*/, 0x01, },
-	{ 16 * 463.25 /*MHz*/, 0xc2, },
-	{ 16 * 999.99        , 0xcf, },
+	{ 16 * 140.25 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 463.25 /*MHz*/, 0x8e, 0xc2, },
+	{ 16 * 999.99        , 0x8e, 0xcf, },
 };
 
 static struct tuner_params tuner_philips_pal_mk_params[] = {
@@ -639,16 +579,15 @@
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_philips_pal_mk_pal_ranges,
 		.count  = ARRAY_SIZE(tuner_philips_pal_mk_pal_ranges),
-		.config = 0x8e,
 	},
 };
 
 /* ------------ TUNER_PHILIPS_ATSC - Philips ATSC ------------ */
 
 static struct tuner_range tuner_philips_atsc_ranges[] = {
-	{ 16 * 157.25 /*MHz*/, 0xa0, },
-	{ 16 * 454.00 /*MHz*/, 0x90, },
-	{ 16 * 999.99        , 0x30, },
+	{ 16 * 157.25 /*MHz*/, 0x8e, 0xa0, },
+	{ 16 * 454.00 /*MHz*/, 0x8e, 0x90, },
+	{ 16 * 999.99        , 0x8e, 0x30, },
 };
 
 static struct tuner_params tuner_philips_atsc_params[] = {
@@ -656,16 +595,15 @@
 		.type   = TUNER_PARAM_TYPE_NTSC,
 		.ranges = tuner_philips_atsc_ranges,
 		.count  = ARRAY_SIZE(tuner_philips_atsc_ranges),
-		.config = 0x8e,
 	},
 };
 
 /* ------------ TUNER_PHILIPS_FM1236_MK3 - Philips NTSC ------------ */
 
 static struct tuner_range tuner_fm1236_mk3_ntsc_ranges[] = {
-	{ 16 * 160.00 /*MHz*/, 0x01, },
-	{ 16 * 442.00 /*MHz*/, 0x02, },
-	{ 16 * 999.99        , 0x04, },
+	{ 16 * 160.00 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 442.00 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 999.99        , 0x8e, 0x04, },
 };
 
 static struct tuner_params tuner_fm1236_mk3_params[] = {
@@ -673,25 +611,17 @@
 		.type   = TUNER_PARAM_TYPE_NTSC,
 		.ranges = tuner_fm1236_mk3_ntsc_ranges,
 		.count  = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
-		.config = 0x8e,
 		.cb_first_if_lower_freq = 1,
 	},
 };
 
 /* ------------ TUNER_PHILIPS_4IN1 - Philips NTSC ------------ */
 
-static struct tuner_range tuner_philips_4in1_ntsc_ranges[] = {
-	{ 16 * 160.00 /*MHz*/, 0x01, },
-	{ 16 * 442.00 /*MHz*/, 0x02, },
-	{ 16 * 999.99        , 0x04, },
-};
-
 static struct tuner_params tuner_philips_4in1_params[] = {
 	{
 		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_philips_4in1_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_philips_4in1_ntsc_ranges),
-		.config = 0x8e,
+		.ranges = tuner_fm1236_mk3_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
 	},
 };
 
@@ -702,16 +632,15 @@
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_temic_4009f_5_pal_ranges,
 		.count  = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges),
-		.config = 0x8e,
 	},
 };
 
 /* ------------ TUNER_PANASONIC_VP27 - Panasonic NTSC ------------ */
 
 static struct tuner_range tuner_panasonic_vp27_ntsc_ranges[] = {
-	{ 16 * 160.00 /*MHz*/, 0x01, },
-	{ 16 * 454.00 /*MHz*/, 0x02, },
-	{ 16 * 999.99        , 0x08, },
+	{ 16 * 160.00 /*MHz*/, 0xce, 0x01, },
+	{ 16 * 454.00 /*MHz*/, 0xce, 0x02, },
+	{ 16 * 999.99        , 0xce, 0x08, },
 };
 
 static struct tuner_params tuner_panasonic_vp27_params[] = {
@@ -719,33 +648,25 @@
 		.type   = TUNER_PARAM_TYPE_NTSC,
 		.ranges = tuner_panasonic_vp27_ntsc_ranges,
 		.count  = ARRAY_SIZE(tuner_panasonic_vp27_ntsc_ranges),
-		.config = 0xce,
 	},
 };
 
 /* ------------ TUNER_LG_NTSC_TAPE - LGINNOTEK NTSC ------------ */
 
-static struct tuner_range tuner_lg_ntsc_tape_ranges[] = {
-	{ 16 * 160.00 /*MHz*/, 0x01, },
-	{ 16 * 442.00 /*MHz*/, 0x02, },
-	{ 16 * 999.99        , 0x04, },
-};
-
 static struct tuner_params tuner_lg_ntsc_tape_params[] = {
 	{
 		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_lg_ntsc_tape_ranges,
-		.count  = ARRAY_SIZE(tuner_lg_ntsc_tape_ranges),
-		.config = 0x8e,
+		.ranges = tuner_fm1236_mk3_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
 	},
 };
 
 /* ------------ TUNER_TNF_8831BGFF - Philips PAL ------------ */
 
 static struct tuner_range tuner_tnf_8831bgff_pal_ranges[] = {
-	{ 16 * 161.25 /*MHz*/, 0xa0, },
-	{ 16 * 463.25 /*MHz*/, 0x90, },
-	{ 16 * 999.99        , 0x30, },
+	{ 16 * 161.25 /*MHz*/, 0x8e, 0xa0, },
+	{ 16 * 463.25 /*MHz*/, 0x8e, 0x90, },
+	{ 16 * 999.99        , 0x8e, 0x30, },
 };
 
 static struct tuner_params tuner_tnf_8831bgff_params[] = {
@@ -753,16 +674,15 @@
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_tnf_8831bgff_pal_ranges,
 		.count  = ARRAY_SIZE(tuner_tnf_8831bgff_pal_ranges),
-		.config = 0x8e,
 	},
 };
 
 /* ------------ TUNER_MICROTUNE_4042FI5 - Microtune NTSC ------------ */
 
 static struct tuner_range tuner_microtune_4042fi5_ntsc_ranges[] = {
-	{ 16 * 162.00 /*MHz*/, 0xa2, },
-	{ 16 * 457.00 /*MHz*/, 0x94, },
-	{ 16 * 999.99        , 0x31, },
+	{ 16 * 162.00 /*MHz*/, 0x8e, 0xa2, },
+	{ 16 * 457.00 /*MHz*/, 0x8e, 0x94, },
+	{ 16 * 999.99        , 0x8e, 0x31, },
 };
 
 static struct tuner_params tuner_microtune_4042fi5_params[] = {
@@ -770,7 +690,6 @@
 		.type   = TUNER_PARAM_TYPE_NTSC,
 		.ranges = tuner_microtune_4042fi5_ntsc_ranges,
 		.count  = ARRAY_SIZE(tuner_microtune_4042fi5_ntsc_ranges),
-		.config = 0x8e,
 	},
 };
 
@@ -778,9 +697,9 @@
 /* ------------ TUNER_TCL_2002N - TCL NTSC ------------ */
 
 static struct tuner_range tuner_tcl_2002n_ntsc_ranges[] = {
-	{ 16 * 172.00 /*MHz*/, 0x01, },
-	{ 16 * 448.00 /*MHz*/, 0x02, },
-	{ 16 * 999.99        , 0x08, },
+	{ 16 * 172.00 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 448.00 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 999.99        , 0x8e, 0x08, },
 };
 
 static struct tuner_params tuner_tcl_2002n_params[] = {
@@ -788,34 +707,26 @@
 		.type   = TUNER_PARAM_TYPE_NTSC,
 		.ranges = tuner_tcl_2002n_ntsc_ranges,
 		.count  = ARRAY_SIZE(tuner_tcl_2002n_ntsc_ranges),
-		.config = 0x8e,
 		.cb_first_if_lower_freq = 1,
 	},
 };
 
 /* ------------ TUNER_PHILIPS_FM1256_IH3 - Philips PAL ------------ */
 
-static struct tuner_range tuner_philips_fm1256_ih3_pal_ranges[] = {
-	{ 16 * 160.00 /*MHz*/, 0x01, },
-	{ 16 * 442.00 /*MHz*/, 0x02, },
-	{ 16 * 999.99        , 0x04, },
-};
-
 static struct tuner_params tuner_philips_fm1256_ih3_params[] = {
 	{
 		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_philips_fm1256_ih3_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_philips_fm1256_ih3_pal_ranges),
-		.config = 0x8e,
+		.ranges = tuner_fm1236_mk3_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
 	},
 };
 
 /* ------------ TUNER_THOMSON_DTT7610 - THOMSON ATSC ------------ */
 
 static struct tuner_range tuner_thomson_dtt7610_ntsc_ranges[] = {
-	{ 16 * 157.25 /*MHz*/, 0x39, },
-	{ 16 * 454.00 /*MHz*/, 0x3a, },
-	{ 16 * 999.99        , 0x3c, },
+	{ 16 * 157.25 /*MHz*/, 0x8e, 0x39, },
+	{ 16 * 454.00 /*MHz*/, 0x8e, 0x3a, },
+	{ 16 * 999.99        , 0x8e, 0x3c, },
 };
 
 static struct tuner_params tuner_thomson_dtt7610_params[] = {
@@ -823,16 +734,15 @@
 		.type   = TUNER_PARAM_TYPE_NTSC,
 		.ranges = tuner_thomson_dtt7610_ntsc_ranges,
 		.count  = ARRAY_SIZE(tuner_thomson_dtt7610_ntsc_ranges),
-		.config = 0x8e,
 	},
 };
 
 /* ------------ TUNER_PHILIPS_FQ1286 - Philips NTSC ------------ */
 
 static struct tuner_range tuner_philips_fq1286_ntsc_ranges[] = {
-	{ 16 * 160.00 /*MHz*/, 0x41, },
-	{ 16 * 454.00 /*MHz*/, 0x42, },
-	{ 16 * 999.99        , 0x04, },
+	{ 16 * 160.00 /*MHz*/, 0x8e, 0x41, },
+	{ 16 * 454.00 /*MHz*/, 0x8e, 0x42, },
+	{ 16 * 999.99        , 0x8e, 0x04, },
 };
 
 static struct tuner_params tuner_philips_fq1286_params[] = {
@@ -840,16 +750,15 @@
 		.type   = TUNER_PARAM_TYPE_NTSC,
 		.ranges = tuner_philips_fq1286_ntsc_ranges,
 		.count  = ARRAY_SIZE(tuner_philips_fq1286_ntsc_ranges),
-		.config = 0x8e,
 	},
 };
 
 /* ------------ TUNER_TCL_2002MB - TCL PAL ------------ */
 
 static struct tuner_range tuner_tcl_2002mb_pal_ranges[] = {
-	{ 16 * 170.00 /*MHz*/, 0x01, },
-	{ 16 * 450.00 /*MHz*/, 0x02, },
-	{ 16 * 999.99        , 0x08, },
+	{ 16 * 170.00 /*MHz*/, 0xce, 0x01, },
+	{ 16 * 450.00 /*MHz*/, 0xce, 0x02, },
+	{ 16 * 999.99        , 0xce, 0x08, },
 };
 
 static struct tuner_params tuner_tcl_2002mb_params[] = {
@@ -857,24 +766,22 @@
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_tcl_2002mb_pal_ranges,
 		.count  = ARRAY_SIZE(tuner_tcl_2002mb_pal_ranges),
-		.config = 0xce,
 	},
 };
 
 /* ------------ TUNER_PHILIPS_FQ1216AME_MK4 - Philips PAL ------------ */
 
-static struct tuner_range tuner_philips_fq12_6a___mk4_ranges[] = {
-	{ 16 * 160.00 /*MHz*/, 0x01, },
-	{ 16 * 442.00 /*MHz*/, 0x02, },
-	{ 16 * 999.99        , 0x04, },
+static struct tuner_range tuner_philips_fq12_6a___mk4_pal_ranges[] = {
+	{ 16 * 160.00 /*MHz*/, 0xce, 0x01, },
+	{ 16 * 442.00 /*MHz*/, 0xce, 0x02, },
+	{ 16 * 999.99        , 0xce, 0x04, },
 };
 
 static struct tuner_params tuner_philips_fq1216ame_mk4_params[] = {
 	{
 		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_philips_fq12_6a___mk4_ranges,
-		.count  = ARRAY_SIZE(tuner_philips_fq12_6a___mk4_ranges),
-		.config = 0xce,
+		.ranges = tuner_philips_fq12_6a___mk4_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_philips_fq12_6a___mk4_pal_ranges),
 	},
 };
 
@@ -883,35 +790,27 @@
 static struct tuner_params tuner_philips_fq1236a_mk4_params[] = {
 	{
 		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_philips_fq12_6a___mk4_ranges,
-		.count  = ARRAY_SIZE(tuner_philips_fq12_6a___mk4_ranges),
-		.config = 0x8e,
+		.ranges = tuner_fm1236_mk3_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
 	},
 };
 
 /* ------------ TUNER_YMEC_TVF_8531MF - Philips NTSC ------------ */
 
-static struct tuner_range tuner_ymec_tvf_8531mf_ntsc_ranges[] = {
-	{ 16 * 160.00 /*MHz*/, 0xa0, },
-	{ 16 * 454.00 /*MHz*/, 0x90, },
-	{ 16 * 999.99        , 0x30, },
-};
-
 static struct tuner_params tuner_ymec_tvf_8531mf_params[] = {
 	{
 		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_ymec_tvf_8531mf_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_ymec_tvf_8531mf_ntsc_ranges),
-		.config = 0x8e,
+		.ranges = tuner_philips_ntsc_m_ranges,
+		.count  = ARRAY_SIZE(tuner_philips_ntsc_m_ranges),
 	},
 };
 
 /* ------------ TUNER_YMEC_TVF_5533MF - Philips NTSC ------------ */
 
 static struct tuner_range tuner_ymec_tvf_5533mf_ntsc_ranges[] = {
-	{ 16 * 160.00 /*MHz*/, 0x01, },
-	{ 16 * 454.00 /*MHz*/, 0x02, },
-	{ 16 * 999.99        , 0x04, },
+	{ 16 * 160.00 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 454.00 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 999.99        , 0x8e, 0x04, },
 };
 
 static struct tuner_params tuner_ymec_tvf_5533mf_params[] = {
@@ -919,7 +818,6 @@
 		.type   = TUNER_PARAM_TYPE_NTSC,
 		.ranges = tuner_ymec_tvf_5533mf_ntsc_ranges,
 		.count  = ARRAY_SIZE(tuner_ymec_tvf_5533mf_ntsc_ranges),
-		.config = 0x8e,
 	},
 };
 
@@ -928,9 +826,9 @@
 /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
 
 static struct tuner_range tuner_thomson_dtt761x_ntsc_ranges[] = {
-	{ 16 * 145.25 /*MHz*/, 0x39, },
-	{ 16 * 415.25 /*MHz*/, 0x3a, },
-	{ 16 * 999.99        , 0x3c, },
+	{ 16 * 145.25 /*MHz*/, 0x8e, 0x39, },
+	{ 16 * 415.25 /*MHz*/, 0x8e, 0x3a, },
+	{ 16 * 999.99        , 0x8e, 0x3c, },
 };
 
 
@@ -939,42 +837,39 @@
 		.type   = TUNER_PARAM_TYPE_NTSC,
 		.ranges = tuner_thomson_dtt761x_ntsc_ranges,
 		.count  = ARRAY_SIZE(tuner_thomson_dtt761x_ntsc_ranges),
-		.config = 0x8e,
 	},
 };
 
 /* ------------ TUNER_TENA_9533_DI - Philips PAL ------------ */
 
-static struct tuner_range tuner_tuner_tena_9533_di_pal_ranges[] = {
-	{ 16 * 160.25 /*MHz*/, 0x01, },
-	{ 16 * 464.25 /*MHz*/, 0x02, },
-	{ 16 * 999.99        , 0x04, },
+static struct tuner_range tuner_tena_9533_di_pal_ranges[] = {
+	{ 16 * 160.25 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 464.25 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 999.99        , 0x8e, 0x04, },
 };
 
 static struct tuner_params tuner_tena_9533_di_params[] = {
 	{
 		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_tuner_tena_9533_di_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_tuner_tena_9533_di_pal_ranges),
-		.config = 0x8e,
+		.ranges = tuner_tena_9533_di_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_tena_9533_di_pal_ranges),
 	},
 };
 
 /* ------------ TUNER_PHILIPS_FMD1216ME_MK3 - Philips PAL ------------ */
 
 static struct tuner_range tuner_philips_fmd1216me_mk3_pal_ranges[] = {
-	{ 16 * 160.00 /*MHz*/, 0x51, },
-	{ 16 * 442.00 /*MHz*/, 0x52, },
-	{ 16 * 999.99        , 0x54, },
+	{ 16 * 160.00 /*MHz*/, 0x86, 0x51, },
+	{ 16 * 442.00 /*MHz*/, 0x86, 0x52, },
+	{ 16 * 999.99        , 0x86, 0x54, },
 };
 
 
-static struct tuner_params tuner_tuner_philips_fmd1216me_mk3_params[] = {
+static struct tuner_params tuner_philips_fmd1216me_mk3_params[] = {
 	{
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_philips_fmd1216me_mk3_pal_ranges,
 		.count  = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_pal_ranges),
-		.config = 0x86,
 	},
 };
 
@@ -982,9 +877,9 @@
 /* ------------ TUNER_LG_TDVS_H062F - INFINEON ATSC ------------ */
 
 static struct tuner_range tuner_tua6034_ntsc_ranges[] = {
-	{ 16 * 160.00 /*MHz*/, 0x01 },
-	{ 16 * 455.00 /*MHz*/, 0x02 },
-	{ 16 * 999.99        , 0x04 },
+	{ 16 * 160.00 /*MHz*/, 0x8e, 0x01 },
+	{ 16 * 455.00 /*MHz*/, 0x8e, 0x02 },
+	{ 16 * 999.99        , 0x8e, 0x04 },
 };
 
 
@@ -993,50 +888,51 @@
 		.type   = TUNER_PARAM_TYPE_NTSC,
 		.ranges = tuner_tua6034_ntsc_ranges,
 		.count  = ARRAY_SIZE(tuner_tua6034_ntsc_ranges),
-		.config = 0x8e,
 	},
 };
 
 /* ------------ TUNER_YMEC_TVF66T5_B_DFF - Philips PAL ------------ */
 
-static struct tuner_range tuner_ymec_tvf66t5_b_dff_pal_ranges[] = {
-	{ 16 * 160.25 /*MHz*/, 0x01, },
-	{ 16 * 464.25 /*MHz*/, 0x02, },
-	{ 16 * 999.99        , 0x08, },
-};
-
 static struct tuner_params tuner_ymec_tvf66t5_b_dff_params[] = {
 	{
 		.type   = TUNER_PARAM_TYPE_PAL,
-		.ranges = tuner_ymec_tvf66t5_b_dff_pal_ranges,
-		.count  = ARRAY_SIZE(tuner_ymec_tvf66t5_b_dff_pal_ranges),
-		.config = 0x8e,
+		.ranges = tuner_tena_9533_di_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_tena_9533_di_pal_ranges),
 	},
 };
 
 /* ------------ TUNER_LG_NTSC_TALN_MINI - LGINNOTEK NTSC ------------ */
 
-static struct tuner_range tuner_lg_taln_mini_ntsc_ranges[] = {
-	{ 16 * 137.25 /*MHz*/, 0x01, },
-	{ 16 * 373.25 /*MHz*/, 0x02, },
-	{ 16 * 999.99        , 0x08, },
+static struct tuner_range tuner_lg_taln_ntsc_ranges[] = {
+	{ 16 * 137.25 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 373.25 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 999.99        , 0x8e, 0x08, },
 };
 
-static struct tuner_params tuner_lg_taln_mini_params[] = {
+static struct tuner_range tuner_lg_taln_pal_secam_ranges[] = {
+	{ 16 * 150.00 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 425.00 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 999.99        , 0x8e, 0x08, },
+};
+
+static struct tuner_params tuner_lg_taln_params[] = {
 	{
 		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_lg_taln_mini_ntsc_ranges,
-		.count  = ARRAY_SIZE(tuner_lg_taln_mini_ntsc_ranges),
-		.config = 0x8e,
+		.ranges = tuner_lg_taln_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_lg_taln_ntsc_ranges),
+	},{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_lg_taln_pal_secam_ranges,
+		.count  = ARRAY_SIZE(tuner_lg_taln_pal_secam_ranges),
 	},
 };
 
 /* ------------ TUNER_PHILIPS_TD1316 - Philips PAL ------------ */
 
 static struct tuner_range tuner_philips_td1316_pal_ranges[] = {
-	{ 16 * 160.00 /*MHz*/, 0xa1, },
-	{ 16 * 442.00 /*MHz*/, 0xa2, },
-	{ 16 * 999.99        , 0xa4, },
+	{ 16 * 160.00 /*MHz*/, 0xc8, 0xa1, },
+	{ 16 * 442.00 /*MHz*/, 0xc8, 0xa2, },
+	{ 16 * 999.99        , 0xc8, 0xa4, },
 };
 
 static struct tuner_params tuner_philips_td1316_params[] = {
@@ -1044,34 +940,42 @@
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_philips_td1316_pal_ranges,
 		.count  = ARRAY_SIZE(tuner_philips_td1316_pal_ranges),
-		.config = 0xc8,
 	},
 };
 
 /* ------------ TUNER_PHILIPS_TUV1236D - Philips ATSC ------------ */
 
 static struct tuner_range tuner_tuv1236d_ntsc_ranges[] = {
-	{ 16 * 157.25 /*MHz*/, 0x01, },
-	{ 16 * 454.00 /*MHz*/, 0x02, },
-	{ 16 * 999.99        , 0x04, },
+	{ 16 * 157.25 /*MHz*/, 0xce, 0x01, },
+	{ 16 * 454.00 /*MHz*/, 0xce, 0x02, },
+	{ 16 * 999.99        , 0xce, 0x04, },
 };
 
 
-static struct tuner_params tuner_tuner_tuv1236d_params[] = {
+static struct tuner_params tuner_tuv1236d_params[] = {
 	{
 		.type   = TUNER_PARAM_TYPE_NTSC,
 		.ranges = tuner_tuv1236d_ntsc_ranges,
 		.count  = ARRAY_SIZE(tuner_tuv1236d_ntsc_ranges),
-		.config = 0xce,
 	},
 };
 
-/* ------------ TUNER_TNF_5335MF - Philips NTSC ------------ */
+/* ------------ TUNER_TNF_xxx5  - Texas Instruments--------- */
+/* This is known to work with Tenna TVF58t5-MFF and TVF5835 MFF
+ *	but it is expected to work also with other Tenna/Ymec
+ *	models based on TI SN 761677 chip on both PAL and NTSC
+ */
+
+static struct tuner_range tuner_tnf_5335_d_if_pal_ranges[] = {
+	{ 16 * 168.25 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 471.25 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 999.99        , 0x8e, 0x08, },
+};
 
 static struct tuner_range tuner_tnf_5335mf_ntsc_ranges[] = {
-	{ 16 * 157.25 /*MHz*/, 0x01, },
-	{ 16 * 454.00 /*MHz*/, 0x02, },
-	{ 16 * 999.99        , 0x04, },
+	{ 16 * 169.25 /*MHz*/, 0x8e, 0x01, },
+	{ 16 * 469.25 /*MHz*/, 0x8e, 0x02, },
+	{ 16 * 999.99        , 0x8e, 0x08, },
 };
 
 static struct tuner_params tuner_tnf_5335mf_params[] = {
@@ -1079,7 +983,11 @@
 		.type   = TUNER_PARAM_TYPE_NTSC,
 		.ranges = tuner_tnf_5335mf_ntsc_ranges,
 		.count  = ARRAY_SIZE(tuner_tnf_5335mf_ntsc_ranges),
-		.config = 0x8e,
+	},
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_tnf_5335_d_if_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_tnf_5335_d_if_pal_ranges),
 	},
 };
 
@@ -1087,9 +995,9 @@
 /* ------------ TUNER_SAMSUNG_TCPN_2121P30A - Samsung NTSC ------------ */
 
 static struct tuner_range tuner_samsung_tcpn_2121p30a_ntsc_ranges[] = {
-	{ 16 * 175.75 /*MHz*/, 0x01, },
-	{ 16 * 410.25 /*MHz*/, 0x02, },
-	{ 16 * 999.99        , 0x08, },
+	{ 16 * 130.00 /*MHz*/, 0xce, 0x01, },
+	{ 16 * 364.50 /*MHz*/, 0xce, 0x02, },
+	{ 16 * 999.99        , 0xce, 0x08, },
 };
 
 static struct tuner_params tuner_samsung_tcpn_2121p30a_params[] = {
@@ -1097,7 +1005,22 @@
 		.type   = TUNER_PARAM_TYPE_NTSC,
 		.ranges = tuner_samsung_tcpn_2121p30a_ntsc_ranges,
 		.count  = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_ntsc_ranges),
-		.config = 0xce,
+	},
+};
+
+/* ------------ TUNER_THOMSON_FE6600 - DViCO Hybrid PAL ------------ */
+
+static struct tuner_range tuner_thomson_fe6600_ranges[] = {
+	{ 16 * 160.00 /*MHz*/, 0xfe, 0x11, },
+	{ 16 * 442.00 /*MHz*/, 0xf6, 0x12, },
+	{ 16 * 999.99        , 0xf6, 0x18, },
+};
+
+static struct tuner_params tuner_thomson_fe6600_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_thomson_fe6600_ranges,
+		.count  = ARRAY_SIZE(tuner_thomson_fe6600_ranges),
 	},
 };
 
@@ -1108,18 +1031,22 @@
 	[TUNER_TEMIC_PAL] = { /* TEMIC PAL */
 		.name   = "Temic PAL (4002 FH5)",
 		.params = tuner_temic_pal_params,
+		.count  = ARRAY_SIZE(tuner_temic_pal_params),
 	},
 	[TUNER_PHILIPS_PAL_I] = { /* Philips PAL_I */
 		.name   = "Philips PAL_I (FI1246 and compatibles)",
 		.params = tuner_philips_pal_i_params,
+		.count  = ARRAY_SIZE(tuner_philips_pal_i_params),
 	},
 	[TUNER_PHILIPS_NTSC] = { /* Philips NTSC */
 		.name   = "Philips NTSC (FI1236,FM1236 and compatibles)",
 		.params = tuner_philips_ntsc_params,
+		.count  = ARRAY_SIZE(tuner_philips_ntsc_params),
 	},
 	[TUNER_PHILIPS_SECAM] = { /* Philips SECAM */
 		.name   = "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)",
 		.params = tuner_philips_secam_params,
+		.count  = ARRAY_SIZE(tuner_philips_secam_params),
 	},
 	[TUNER_ABSENT] = { /* Tuner Absent */
 		.name   = "NoTuner",
@@ -1127,120 +1054,148 @@
 	[TUNER_PHILIPS_PAL] = { /* Philips PAL */
 		.name   = "Philips PAL_BG (FI1216 and compatibles)",
 		.params = tuner_philips_pal_params,
+		.count  = ARRAY_SIZE(tuner_philips_pal_params),
 	},
 	[TUNER_TEMIC_NTSC] = { /* TEMIC NTSC */
 		.name   = "Temic NTSC (4032 FY5)",
 		.params = tuner_temic_ntsc_params,
+		.count  = ARRAY_SIZE(tuner_temic_ntsc_params),
 	},
 	[TUNER_TEMIC_PAL_I] = { /* TEMIC PAL_I */
 		.name   = "Temic PAL_I (4062 FY5)",
 		.params = tuner_temic_pal_i_params,
+		.count  = ARRAY_SIZE(tuner_temic_pal_i_params),
 	},
 	[TUNER_TEMIC_4036FY5_NTSC] = { /* TEMIC NTSC */
 		.name   = "Temic NTSC (4036 FY5)",
 		.params = tuner_temic_4036fy5_ntsc_params,
+		.count  = ARRAY_SIZE(tuner_temic_4036fy5_ntsc_params),
 	},
 	[TUNER_ALPS_TSBH1_NTSC] = { /* TEMIC NTSC */
 		.name   = "Alps HSBH1",
 		.params = tuner_alps_tsbh1_ntsc_params,
+		.count  = ARRAY_SIZE(tuner_alps_tsbh1_ntsc_params),
 	},
 
 	/* 10-19 */
 	[TUNER_ALPS_TSBE1_PAL] = { /* TEMIC PAL */
 		.name   = "Alps TSBE1",
 		.params = tuner_alps_tsb_1_params,
+		.count  = ARRAY_SIZE(tuner_alps_tsb_1_params),
 	},
 	[TUNER_ALPS_TSBB5_PAL_I] = { /* Alps PAL_I */
 		.name   = "Alps TSBB5",
 		.params = tuner_alps_tsbb5_params,
+		.count  = ARRAY_SIZE(tuner_alps_tsbb5_params),
 	},
 	[TUNER_ALPS_TSBE5_PAL] = { /* Alps PAL */
 		.name   = "Alps TSBE5",
 		.params = tuner_alps_tsbe5_params,
+		.count  = ARRAY_SIZE(tuner_alps_tsbe5_params),
 	},
 	[TUNER_ALPS_TSBC5_PAL] = { /* Alps PAL */
 		.name   = "Alps TSBC5",
 		.params = tuner_alps_tsbc5_params,
+		.count  = ARRAY_SIZE(tuner_alps_tsbc5_params),
 	},
 	[TUNER_TEMIC_4006FH5_PAL] = { /* TEMIC PAL */
 		.name   = "Temic PAL_BG (4006FH5)",
 		.params = tuner_temic_4006fh5_params,
+		.count  = ARRAY_SIZE(tuner_temic_4006fh5_params),
 	},
 	[TUNER_ALPS_TSHC6_NTSC] = { /* Alps NTSC */
 		.name   = "Alps TSCH6",
 		.params = tuner_alps_tshc6_params,
+		.count  = ARRAY_SIZE(tuner_alps_tshc6_params),
 	},
 	[TUNER_TEMIC_PAL_DK] = { /* TEMIC PAL */
 		.name   = "Temic PAL_DK (4016 FY5)",
 		.params = tuner_temic_pal_dk_params,
+		.count  = ARRAY_SIZE(tuner_temic_pal_dk_params),
 	},
 	[TUNER_PHILIPS_NTSC_M] = { /* Philips NTSC */
 		.name   = "Philips NTSC_M (MK2)",
 		.params = tuner_philips_ntsc_m_params,
+		.count  = ARRAY_SIZE(tuner_philips_ntsc_m_params),
 	},
 	[TUNER_TEMIC_4066FY5_PAL_I] = { /* TEMIC PAL_I */
 		.name   = "Temic PAL_I (4066 FY5)",
 		.params = tuner_temic_4066fy5_pal_i_params,
+		.count  = ARRAY_SIZE(tuner_temic_4066fy5_pal_i_params),
 	},
 	[TUNER_TEMIC_4006FN5_MULTI_PAL] = { /* TEMIC PAL */
 		.name   = "Temic PAL* auto (4006 FN5)",
 		.params = tuner_temic_4006fn5_multi_params,
+		.count  = ARRAY_SIZE(tuner_temic_4006fn5_multi_params),
 	},
 
 	/* 20-29 */
 	[TUNER_TEMIC_4009FR5_PAL] = { /* TEMIC PAL */
 		.name   = "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)",
 		.params = tuner_temic_4009f_5_params,
+		.count  = ARRAY_SIZE(tuner_temic_4009f_5_params),
 	},
 	[TUNER_TEMIC_4039FR5_NTSC] = { /* TEMIC NTSC */
 		.name   = "Temic NTSC (4039 FR5)",
 		.params = tuner_temic_4039fr5_params,
+		.count  = ARRAY_SIZE(tuner_temic_4039fr5_params),
 	},
 	[TUNER_TEMIC_4046FM5] = { /* TEMIC PAL */
 		.name   = "Temic PAL/SECAM multi (4046 FM5)",
 		.params = tuner_temic_4046fm5_params,
+		.count  = ARRAY_SIZE(tuner_temic_4046fm5_params),
 	},
 	[TUNER_PHILIPS_PAL_DK] = { /* Philips PAL */
 		.name   = "Philips PAL_DK (FI1256 and compatibles)",
 		.params = tuner_philips_pal_dk_params,
+		.count  = ARRAY_SIZE(tuner_philips_pal_dk_params),
 	},
 	[TUNER_PHILIPS_FQ1216ME] = { /* Philips PAL */
 		.name   = "Philips PAL/SECAM multi (FQ1216ME)",
 		.params = tuner_philips_fq1216me_params,
+		.count  = ARRAY_SIZE(tuner_philips_fq1216me_params),
 	},
 	[TUNER_LG_PAL_I_FM] = { /* LGINNOTEK PAL_I */
 		.name   = "LG PAL_I+FM (TAPC-I001D)",
 		.params = tuner_lg_pal_i_fm_params,
+		.count  = ARRAY_SIZE(tuner_lg_pal_i_fm_params),
 	},
 	[TUNER_LG_PAL_I] = { /* LGINNOTEK PAL_I */
 		.name   = "LG PAL_I (TAPC-I701D)",
 		.params = tuner_lg_pal_i_params,
+		.count  = ARRAY_SIZE(tuner_lg_pal_i_params),
 	},
 	[TUNER_LG_NTSC_FM] = { /* LGINNOTEK NTSC */
 		.name   = "LG NTSC+FM (TPI8NSR01F)",
 		.params = tuner_lg_ntsc_fm_params,
+		.count  = ARRAY_SIZE(tuner_lg_ntsc_fm_params),
 	},
 	[TUNER_LG_PAL_FM] = { /* LGINNOTEK PAL */
 		.name   = "LG PAL_BG+FM (TPI8PSB01D)",
 		.params = tuner_lg_pal_fm_params,
+		.count  = ARRAY_SIZE(tuner_lg_pal_fm_params),
 	},
 	[TUNER_LG_PAL] = { /* LGINNOTEK PAL */
 		.name   = "LG PAL_BG (TPI8PSB11D)",
 		.params = tuner_lg_pal_params,
+		.count  = ARRAY_SIZE(tuner_lg_pal_params),
 	},
 
 	/* 30-39 */
 	[TUNER_TEMIC_4009FN5_MULTI_PAL_FM] = { /* TEMIC PAL */
 		.name   = "Temic PAL* auto + FM (4009 FN5)",
 		.params = tuner_temic_4009_fn5_multi_pal_fm_params,
+		.count  = ARRAY_SIZE(tuner_temic_4009_fn5_multi_pal_fm_params),
 	},
 	[TUNER_SHARP_2U5JF5540_NTSC] = { /* SHARP NTSC */
 		.name   = "SHARP NTSC_JP (2U5JF5540)",
 		.params = tuner_sharp_2u5jf5540_params,
+		.count  = ARRAY_SIZE(tuner_sharp_2u5jf5540_params),
 	},
 	[TUNER_Samsung_PAL_TCPM9091PD27] = { /* Samsung PAL */
 		.name   = "Samsung PAL TCPM9091PD27",
 		.params = tuner_samsung_pal_tcpm9091pd27_params,
+		.count  = ARRAY_SIZE(tuner_samsung_pal_tcpm9091pd27_params),
 	},
 	[TUNER_MT2032] = { /* Microtune PAL|NTSC */
 		.name   = "MT20xx universal",
@@ -1248,86 +1203,106 @@
 	[TUNER_TEMIC_4106FH5] = { /* TEMIC PAL */
 		.name   = "Temic PAL_BG (4106 FH5)",
 		.params = tuner_temic_4106fh5_params,
+		.count  = ARRAY_SIZE(tuner_temic_4106fh5_params),
 	},
 	[TUNER_TEMIC_4012FY5] = { /* TEMIC PAL */
 		.name   = "Temic PAL_DK/SECAM_L (4012 FY5)",
 		.params = tuner_temic_4012fy5_params,
+		.count  = ARRAY_SIZE(tuner_temic_4012fy5_params),
 	},
 	[TUNER_TEMIC_4136FY5] = { /* TEMIC NTSC */
 		.name   = "Temic NTSC (4136 FY5)",
 		.params = tuner_temic_4136_fy5_params,
+		.count  = ARRAY_SIZE(tuner_temic_4136_fy5_params),
 	},
 	[TUNER_LG_PAL_NEW_TAPC] = { /* LGINNOTEK PAL */
 		.name   = "LG PAL (newer TAPC series)",
 		.params = tuner_lg_pal_new_tapc_params,
+		.count  = ARRAY_SIZE(tuner_lg_pal_new_tapc_params),
 	},
 	[TUNER_PHILIPS_FM1216ME_MK3] = { /* Philips PAL */
 		.name   = "Philips PAL/SECAM multi (FM1216ME MK3)",
 		.params = tuner_fm1216me_mk3_params,
+		.count  = ARRAY_SIZE(tuner_fm1216me_mk3_params),
 	},
 	[TUNER_LG_NTSC_NEW_TAPC] = { /* LGINNOTEK NTSC */
 		.name   = "LG NTSC (newer TAPC series)",
 		.params = tuner_lg_ntsc_new_tapc_params,
+		.count  = ARRAY_SIZE(tuner_lg_ntsc_new_tapc_params),
 	},
 
 	/* 40-49 */
 	[TUNER_HITACHI_NTSC] = { /* HITACHI NTSC */
 		.name   = "HITACHI V7-J180AT",
 		.params = tuner_hitachi_ntsc_params,
+		.count  = ARRAY_SIZE(tuner_hitachi_ntsc_params),
 	},
 	[TUNER_PHILIPS_PAL_MK] = { /* Philips PAL */
 		.name   = "Philips PAL_MK (FI1216 MK)",
 		.params = tuner_philips_pal_mk_params,
+		.count  = ARRAY_SIZE(tuner_philips_pal_mk_params),
 	},
 	[TUNER_PHILIPS_ATSC] = { /* Philips ATSC */
 		.name   = "Philips 1236D ATSC/NTSC dual in",
 		.params = tuner_philips_atsc_params,
+		.count  = ARRAY_SIZE(tuner_philips_atsc_params),
 	},
 	[TUNER_PHILIPS_FM1236_MK3] = { /* Philips NTSC */
 		.name   = "Philips NTSC MK3 (FM1236MK3 or FM1236/F)",
 		.params = tuner_fm1236_mk3_params,
+		.count  = ARRAY_SIZE(tuner_fm1236_mk3_params),
 	},
 	[TUNER_PHILIPS_4IN1] = { /* Philips NTSC */
 		.name   = "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)",
 		.params = tuner_philips_4in1_params,
+		.count  = ARRAY_SIZE(tuner_philips_4in1_params),
 	},
 	[TUNER_MICROTUNE_4049FM5] = { /* Microtune PAL */
 		.name   = "Microtune 4049 FM5",
 		.params = tuner_microtune_4049_fm5_params,
+		.count  = ARRAY_SIZE(tuner_microtune_4049_fm5_params),
 	},
 	[TUNER_PANASONIC_VP27] = { /* Panasonic NTSC */
 		.name   = "Panasonic VP27s/ENGE4324D",
 		.params = tuner_panasonic_vp27_params,
+		.count  = ARRAY_SIZE(tuner_panasonic_vp27_params),
 	},
 	[TUNER_LG_NTSC_TAPE] = { /* LGINNOTEK NTSC */
 		.name   = "LG NTSC (TAPE series)",
 		.params = tuner_lg_ntsc_tape_params,
+		.count  = ARRAY_SIZE(tuner_lg_ntsc_tape_params),
 	},
 	[TUNER_TNF_8831BGFF] = { /* Philips PAL */
 		.name   = "Tenna TNF 8831 BGFF)",
 		.params = tuner_tnf_8831bgff_params,
+		.count  = ARRAY_SIZE(tuner_tnf_8831bgff_params),
 	},
 	[TUNER_MICROTUNE_4042FI5] = { /* Microtune NTSC */
 		.name   = "Microtune 4042 FI5 ATSC/NTSC dual in",
 		.params = tuner_microtune_4042fi5_params,
+		.count  = ARRAY_SIZE(tuner_microtune_4042fi5_params),
 	},
 
 	/* 50-59 */
 	[TUNER_TCL_2002N] = { /* TCL NTSC */
 		.name   = "TCL 2002N",
 		.params = tuner_tcl_2002n_params,
+		.count  = ARRAY_SIZE(tuner_tcl_2002n_params),
 	},
 	[TUNER_PHILIPS_FM1256_IH3] = { /* Philips PAL */
 		.name   = "Philips PAL/SECAM_D (FM 1256 I-H3)",
 		.params = tuner_philips_fm1256_ih3_params,
+		.count  = ARRAY_SIZE(tuner_philips_fm1256_ih3_params),
 	},
 	[TUNER_THOMSON_DTT7610] = { /* THOMSON ATSC */
 		.name   = "Thomson DTT 7610 (ATSC/NTSC)",
 		.params = tuner_thomson_dtt7610_params,
+		.count  = ARRAY_SIZE(tuner_thomson_dtt7610_params),
 	},
 	[TUNER_PHILIPS_FQ1286] = { /* Philips NTSC */
 		.name   = "Philips FQ1286",
 		.params = tuner_philips_fq1286_params,
+		.count  = ARRAY_SIZE(tuner_philips_fq1286_params),
 	},
 	[TUNER_PHILIPS_TDA8290] = { /* Philips PAL|NTSC */
 		.name   = "tda8290+75",
@@ -1335,22 +1310,27 @@
 	[TUNER_TCL_2002MB] = { /* TCL PAL */
 		.name   = "TCL 2002MB",
 		.params = tuner_tcl_2002mb_params,
+		.count  = ARRAY_SIZE(tuner_tcl_2002mb_params),
 	},
 	[TUNER_PHILIPS_FQ1216AME_MK4] = { /* Philips PAL */
 		.name   = "Philips PAL/SECAM multi (FQ1216AME MK4)",
 		.params = tuner_philips_fq1216ame_mk4_params,
+		.count  = ARRAY_SIZE(tuner_philips_fq1216ame_mk4_params),
 	},
 	[TUNER_PHILIPS_FQ1236A_MK4] = { /* Philips NTSC */
 		.name   = "Philips FQ1236A MK4",
 		.params = tuner_philips_fq1236a_mk4_params,
+		.count  = ARRAY_SIZE(tuner_philips_fq1236a_mk4_params),
 	},
 	[TUNER_YMEC_TVF_8531MF] = { /* Philips NTSC */
 		.name   = "Ymec TVision TVF-8531MF/8831MF/8731MF",
 		.params = tuner_ymec_tvf_8531mf_params,
+		.count  = ARRAY_SIZE(tuner_ymec_tvf_8531mf_params),
 	},
 	[TUNER_YMEC_TVF_5533MF] = { /* Philips NTSC */
 		.name   = "Ymec TVision TVF-5533MF",
 		.params = tuner_ymec_tvf_5533mf_params,
+		.count  = ARRAY_SIZE(tuner_ymec_tvf_5533mf_params),
 	},
 
 	/* 60-69 */
@@ -1358,10 +1338,12 @@
 		/* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
 		.name   = "Thomson DTT 761X (ATSC/NTSC)",
 		.params = tuner_thomson_dtt761x_params,
+		.count  = ARRAY_SIZE(tuner_thomson_dtt761x_params),
 	},
 	[TUNER_TENA_9533_DI] = { /* Philips PAL */
 		.name   = "Tena TNF9533-D/IF/TNF9533-B/DF",
 		.params = tuner_tena_9533_di_params,
+		.count  = ARRAY_SIZE(tuner_tena_9533_di_params),
 	},
 	[TUNER_TEA5767] = { /* Philips RADIO */
 		.name   = "Philips TEA5767HN FM Radio",
@@ -1369,37 +1351,54 @@
 	},
 	[TUNER_PHILIPS_FMD1216ME_MK3] = { /* Philips PAL */
 		.name   = "Philips FMD1216ME MK3 Hybrid Tuner",
-		.params = tuner_tuner_philips_fmd1216me_mk3_params,
+		.params = tuner_philips_fmd1216me_mk3_params,
+		.count  = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_params),
 	},
 	[TUNER_LG_TDVS_H062F] = { /* LGINNOTEK ATSC */
 		.name   = "LG TDVS-H062F/TUA6034",
 		.params = tuner_tua6034_params,
+		.count  = ARRAY_SIZE(tuner_tua6034_params),
 	},
 	[TUNER_YMEC_TVF66T5_B_DFF] = { /* Philips PAL */
 		.name   = "Ymec TVF66T5-B/DFF",
 		.params = tuner_ymec_tvf66t5_b_dff_params,
+		.count  = ARRAY_SIZE(tuner_ymec_tvf66t5_b_dff_params),
 	},
-	[TUNER_LG_NTSC_TALN_MINI] = { /* LGINNOTEK NTSC */
-		.name   = "LG NTSC (TALN mini series)",
-		.params = tuner_lg_taln_mini_params,
+	[TUNER_LG_TALN] = { /* LGINNOTEK NTSC / PAL / SECAM */
+		.name   = "LG TALN series",
+		.params = tuner_lg_taln_params,
+		.count  = ARRAY_SIZE(tuner_lg_taln_params),
 	},
 	[TUNER_PHILIPS_TD1316] = { /* Philips PAL */
 		.name   = "Philips TD1316 Hybrid Tuner",
 		.params = tuner_philips_td1316_params,
+		.count  = ARRAY_SIZE(tuner_philips_td1316_params),
 	},
 	[TUNER_PHILIPS_TUV1236D] = { /* Philips ATSC */
 		.name   = "Philips TUV1236D ATSC/NTSC dual in",
-		.params = tuner_tuner_tuv1236d_params,
+		.params = tuner_tuv1236d_params,
+		.count  = ARRAY_SIZE(tuner_tuv1236d_params),
 	},
-	[TUNER_TNF_5335MF] = { /* Philips NTSC */
-		.name   = "Tena TNF 5335 MF",
+	[TUNER_TNF_5335MF] = { /* Tenna PAL/NTSC */
+		.name   = "Tena TNF 5335 and similar models",
 		.params = tuner_tnf_5335mf_params,
+		.count  = ARRAY_SIZE(tuner_tnf_5335mf_params),
 	},
 
 	/* 70-79 */
 	[TUNER_SAMSUNG_TCPN_2121P30A] = { /* Samsung NTSC */
 		.name   = "Samsung TCPN 2121P30A",
 		.params = tuner_samsung_tcpn_2121p30a_params,
+		.count  = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_params),
+	},
+	[TUNER_XCEIVE_XC3028] = { /* Xceive 3028 */
+		.name	= "Xceive xc3028",
+		/* see xc3028.c for details */
+	},
+	[TUNER_THOMSON_FE6600] = { /* Thomson PAL / DVB-T */
+		.name   = "Thomson FE6600",
+		.params = tuner_thomson_fe6600_params,
+		.count  = ARRAY_SIZE(tuner_thomson_fe6600_params),
 	},
 };
 
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index c8e5ad0..4efb01b 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -130,6 +130,7 @@
 	struct timer_list    wt;
 	int                  done;
 	int                  watch_stereo;
+	int 		     audmode;
 };
 
 /* ---------------------------------------------------------------------- */
@@ -1514,6 +1515,7 @@
 	chip->type = desc-chiplist;
 	chip->shadow.count = desc->registers+1;
 	chip->prevmode = -1;
+	chip->audmode = V4L2_TUNER_MODE_LANG1;
 	/* register */
 	i2c_attach_client(&chip->c);
 
@@ -1671,6 +1673,8 @@
 		struct v4l2_tuner *vt = arg;
 		int mode = 0;
 
+		if (chip->radio)
+			break;
 		switch (vt->audmode) {
 		case V4L2_TUNER_MODE_MONO:
 			mode = VIDEO_SOUND_MONO;
@@ -1685,8 +1689,9 @@
 			mode = VIDEO_SOUND_LANG2;
 			break;
 		default:
-			break;
+			return -EINVAL;
 		}
+		chip->audmode = vt->audmode;
 
 		if (desc->setmode && mode) {
 			chip->watch_stereo = 0;
@@ -1704,7 +1709,7 @@
 
 		if (chip->radio)
 			break;
-		vt->audmode = 0;
+		vt->audmode = chip->audmode;
 		vt->rxsubchans = 0;
 		vt->capability = V4L2_TUNER_CAP_STEREO |
 			V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
@@ -1716,19 +1721,12 @@
 			vt->rxsubchans |= V4L2_TUNER_SUB_MONO;
 		if (mode & VIDEO_SOUND_STEREO)
 			vt->rxsubchans |= V4L2_TUNER_SUB_STEREO;
+		/* Note: for SAP it should be mono/lang2 or stereo/lang2.
+		   When this module is converted fully to v4l2, then this
+		   should change for those chips that can detect SAP. */
 		if (mode & VIDEO_SOUND_LANG1)
-			vt->rxsubchans |= V4L2_TUNER_SUB_LANG1 |
-					  V4L2_TUNER_SUB_LANG2;
-
-		mode = chip->mode;
-		if (mode & VIDEO_SOUND_MONO)
-			vt->audmode = V4L2_TUNER_MODE_MONO;
-		if (mode & VIDEO_SOUND_STEREO)
-			vt->audmode = V4L2_TUNER_MODE_STEREO;
-		if (mode & VIDEO_SOUND_LANG1)
-			vt->audmode = V4L2_TUNER_MODE_LANG1;
-		if (mode & VIDEO_SOUND_LANG2)
-			vt->audmode = V4L2_TUNER_MODE_LANG2;
+			vt->rxsubchans = V4L2_TUNER_SUB_LANG1 |
+					 V4L2_TUNER_SUB_LANG2;
 		break;
 	}
 
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
index 1864423..69d0fe1 100644
--- a/drivers/media/video/tvp5150.c
+++ b/drivers/media/video/tvp5150.c
@@ -1,8 +1,8 @@
 /*
- * tvp5150 - Texas Instruments TVP5150A(M) video decoder driver
+ * tvp5150 - Texas Instruments TVP5150A/AM1 video decoder driver
  *
- * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@brturbo.com.br)
- * This code is placed under the terms of the GNU General Public License
+ * Copyright (c) 2005,2006 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This code is placed under the terms of the GNU General Public License v2
  */
 
 #include <linux/i2c.h>
@@ -13,10 +13,11 @@
 
 #include "tvp5150_reg.h"
 
-MODULE_DESCRIPTION("Texas Instruments TVP5150A video decoder driver");	/* standard i2c insmod options */
+MODULE_DESCRIPTION("Texas Instruments TVP5150A video decoder driver");
 MODULE_AUTHOR("Mauro Carvalho Chehab");
 MODULE_LICENSE("GPL");
 
+/* standard i2c insmod options */
 static unsigned short normal_i2c[] = {
 	0xb8 >> 1,
 	0xba >> 1,
@@ -29,6 +30,9 @@
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
+#define tvp5150_err(fmt, arg...) do { \
+	printk(KERN_ERR "%s %d-%04x: " fmt, c->driver->driver.name, \
+	       i2c_adapter_id(c->adapter), c->addr , ## arg); } while (0)
 #define tvp5150_info(fmt, arg...) do { \
 	printk(KERN_INFO "%s %d-%04x: " fmt, c->driver->driver.name, \
 	       i2c_adapter_id(c->adapter), c->addr , ## arg); } while (0)
@@ -84,7 +88,7 @@
 struct tvp5150 {
 	struct i2c_client *client;
 
-	int norm;
+	v4l2_std_id norm;	/* Current set standard */
 	int input;
 	int enable;
 	int bright;
@@ -125,310 +129,155 @@
 		tvp5150_dbg(0, "i2c i/o error: rc == %d (should be 2)\n", rc);
 }
 
+static void dump_reg_range(struct i2c_client *c, char *s, u8 init, const u8 end,int max_line)
+{
+	int i=0;
+
+	while (init!=(u8)(end+1)) {
+		if ((i%max_line) == 0) {
+			if (i>0)
+				printk("\n");
+			printk("tvp5150: %s reg 0x%02x = ",s,init);
+		}
+		printk("%02x ",tvp5150_read(c, init));
+
+		init++;
+		i++;
+	}
+	printk("\n");
+}
+
 static void dump_reg(struct i2c_client *c)
 {
 	printk("tvp5150: Video input source selection #1 = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VD_IN_SRC_SEL_1));
+					tvp5150_read(c, TVP5150_VD_IN_SRC_SEL_1));
 	printk("tvp5150: Analog channel controls = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_ANAL_CHL_CTL));
+					tvp5150_read(c, TVP5150_ANAL_CHL_CTL));
 	printk("tvp5150: Operation mode controls = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_OP_MODE_CTL));
+					tvp5150_read(c, TVP5150_OP_MODE_CTL));
 	printk("tvp5150: Miscellaneous controls = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_MISC_CTL));
-	printk("tvp5150: Autoswitch mask: TVP5150A / TVP5150AM = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_AUTOSW_MSK));
+					tvp5150_read(c, TVP5150_MISC_CTL));
+	printk("tvp5150: Autoswitch mask= 0x%02x\n",
+					tvp5150_read(c, TVP5150_AUTOSW_MSK));
 	printk("tvp5150: Color killer threshold control = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_COLOR_KIL_THSH_CTL));
-	printk("tvp5150: Luminance processing control #1 = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LUMA_PROC_CTL_1));
-	printk("tvp5150: Luminance processing control #2 = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LUMA_PROC_CTL_2));
+					tvp5150_read(c, TVP5150_COLOR_KIL_THSH_CTL));
+	printk("tvp5150: Luminance processing controls #1 #2 and #3 = %02x %02x %02x\n",
+					tvp5150_read(c, TVP5150_LUMA_PROC_CTL_1),
+					tvp5150_read(c, TVP5150_LUMA_PROC_CTL_2),
+					tvp5150_read(c, TVP5150_LUMA_PROC_CTL_3));
 	printk("tvp5150: Brightness control = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_BRIGHT_CTL));
+					tvp5150_read(c, TVP5150_BRIGHT_CTL));
 	printk("tvp5150: Color saturation control = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_SATURATION_CTL));
+					tvp5150_read(c, TVP5150_SATURATION_CTL));
 	printk("tvp5150: Hue control = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_HUE_CTL));
+					tvp5150_read(c, TVP5150_HUE_CTL));
 	printk("tvp5150: Contrast control = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_CONTRAST_CTL));
+					tvp5150_read(c, TVP5150_CONTRAST_CTL));
 	printk("tvp5150: Outputs and data rates select = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_DATA_RATE_SEL));
-	printk("tvp5150: Luminance processing control #3 = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LUMA_PROC_CTL_3));
+					tvp5150_read(c, TVP5150_DATA_RATE_SEL));
 	printk("tvp5150: Configuration shared pins = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_CONF_SHARED_PIN));
-	printk("tvp5150: Active video cropping start MSB = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_ACT_VD_CROP_ST_MSB));
-	printk("tvp5150: Active video cropping start LSB = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_ACT_VD_CROP_ST_LSB));
-	printk("tvp5150: Active video cropping stop MSB = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_ACT_VD_CROP_STP_MSB));
-	printk("tvp5150: Active video cropping stop LSB = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_ACT_VD_CROP_STP_LSB));
+					tvp5150_read(c, TVP5150_CONF_SHARED_PIN));
+	printk("tvp5150: Active video cropping start = 0x%02x%02x\n",
+					tvp5150_read(c, TVP5150_ACT_VD_CROP_ST_MSB),
+					tvp5150_read(c, TVP5150_ACT_VD_CROP_ST_LSB));
+	printk("tvp5150: Active video cropping stop  = 0x%02x%02x\n",
+					tvp5150_read(c, TVP5150_ACT_VD_CROP_STP_MSB),
+					tvp5150_read(c, TVP5150_ACT_VD_CROP_STP_LSB));
 	printk("tvp5150: Genlock/RTC = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_GENLOCK));
+					tvp5150_read(c, TVP5150_GENLOCK));
 	printk("tvp5150: Horizontal sync start = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_HORIZ_SYNC_START));
+					tvp5150_read(c, TVP5150_HORIZ_SYNC_START));
 	printk("tvp5150: Vertical blanking start = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VERT_BLANKING_START));
+					tvp5150_read(c, TVP5150_VERT_BLANKING_START));
 	printk("tvp5150: Vertical blanking stop = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VERT_BLANKING_STOP));
-	printk("tvp5150: Chrominance processing control #1 = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_CHROMA_PROC_CTL_1));
-	printk("tvp5150: Chrominance processing control #2 = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_CHROMA_PROC_CTL_2));
+					tvp5150_read(c, TVP5150_VERT_BLANKING_STOP));
+	printk("tvp5150: Chrominance processing control #1 and #2 = %02x %02x\n",
+					tvp5150_read(c, TVP5150_CHROMA_PROC_CTL_1),
+					tvp5150_read(c, TVP5150_CHROMA_PROC_CTL_2));
 	printk("tvp5150: Interrupt reset register B = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_INT_RESET_REG_B));
+					tvp5150_read(c, TVP5150_INT_RESET_REG_B));
 	printk("tvp5150: Interrupt enable register B = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_INT_ENABLE_REG_B));
+					tvp5150_read(c, TVP5150_INT_ENABLE_REG_B));
 	printk("tvp5150: Interrupt configuration register B = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_INTT_CONFIG_REG_B));
+					tvp5150_read(c, TVP5150_INTT_CONFIG_REG_B));
 	printk("tvp5150: Video standard = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VIDEO_STD));
-	printk("tvp5150: Cb gain factor = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_CB_GAIN_FACT));
-	printk("tvp5150: Cr gain factor = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_CR_GAIN_FACTOR));
+					tvp5150_read(c, TVP5150_VIDEO_STD));
+	printk("tvp5150: Chroma gain factor: Cb=0x%02x Cr=0x%02x\n",
+					tvp5150_read(c, TVP5150_CB_GAIN_FACT),
+					tvp5150_read(c, TVP5150_CR_GAIN_FACTOR));
 	printk("tvp5150: Macrovision on counter = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_MACROVISION_ON_CTR));
+					tvp5150_read(c, TVP5150_MACROVISION_ON_CTR));
 	printk("tvp5150: Macrovision off counter = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_MACROVISION_OFF_CTR));
-	printk("tvp5150: revision select (TVP5150AM1 only) = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_REV_SELECT));
-	printk("tvp5150: MSB of device ID = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_MSB_DEV_ID));
-	printk("tvp5150: LSB of device ID = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LSB_DEV_ID));
-	printk("tvp5150: ROM major version = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_ROM_MAJOR_VER));
-	printk("tvp5150: ROM minor version = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_ROM_MINOR_VER));
-	printk("tvp5150: Vertical line count MSB = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VERT_LN_COUNT_MSB));
-	printk("tvp5150: Vertical line count LSB = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VERT_LN_COUNT_LSB));
+					tvp5150_read(c, TVP5150_MACROVISION_OFF_CTR));
+	printk("tvp5150: ITU-R BT.656.%d timing(TVP5150AM1 only)\n",
+					(tvp5150_read(c, TVP5150_REV_SELECT)&1)?3:4);
+	printk("tvp5150: Device ID = %02x%02x\n",
+					tvp5150_read(c, TVP5150_MSB_DEV_ID),
+					tvp5150_read(c, TVP5150_LSB_DEV_ID));
+	printk("tvp5150: ROM version = (hex) %02x.%02x\n",
+					tvp5150_read(c, TVP5150_ROM_MAJOR_VER),
+					tvp5150_read(c, TVP5150_ROM_MINOR_VER));
+	printk("tvp5150: Vertical line count = 0x%02x%02x\n",
+					tvp5150_read(c, TVP5150_VERT_LN_COUNT_MSB),
+					tvp5150_read(c, TVP5150_VERT_LN_COUNT_LSB));
 	printk("tvp5150: Interrupt status register B = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_INT_STATUS_REG_B));
+					tvp5150_read(c, TVP5150_INT_STATUS_REG_B));
 	printk("tvp5150: Interrupt active register B = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_INT_ACTIVE_REG_B));
-	printk("tvp5150: Status register #1 = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_STATUS_REG_1));
-	printk("tvp5150: Status register #2 = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_STATUS_REG_2));
-	printk("tvp5150: Status register #3 = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_STATUS_REG_3));
-	printk("tvp5150: Status register #4 = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_STATUS_REG_4));
-	printk("tvp5150: Status register #5 = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_STATUS_REG_5));
-	printk("tvp5150: Closed caption data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_CC_DATA_REG1));
-	printk("tvp5150: Closed caption data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_CC_DATA_REG2));
-	printk("tvp5150: Closed caption data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_CC_DATA_REG3));
-	printk("tvp5150: Closed caption data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_CC_DATA_REG4));
-	printk("tvp5150: WSS data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_WSS_DATA_REG1));
-	printk("tvp5150: WSS data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_WSS_DATA_REG2));
-	printk("tvp5150: WSS data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_WSS_DATA_REG3));
-	printk("tvp5150: WSS data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_WSS_DATA_REG4));
-	printk("tvp5150: WSS data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_WSS_DATA_REG5));
-	printk("tvp5150: WSS data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_WSS_DATA_REG6));
-	printk("tvp5150: VPS data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VPS_DATA_REG1));
-	printk("tvp5150: VPS data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VPS_DATA_REG2));
-	printk("tvp5150: VPS data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VPS_DATA_REG3));
-	printk("tvp5150: VPS data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VPS_DATA_REG4));
-	printk("tvp5150: VPS data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VPS_DATA_REG5));
-	printk("tvp5150: VPS data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VPS_DATA_REG6));
-	printk("tvp5150: VPS data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VPS_DATA_REG7));
-	printk("tvp5150: VPS data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VPS_DATA_REG8));
-	printk("tvp5150: VPS data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VPS_DATA_REG9));
-	printk("tvp5150: VPS data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VPS_DATA_REG10));
-	printk("tvp5150: VPS data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VPS_DATA_REG11));
-	printk("tvp5150: VPS data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VPS_DATA_REG12));
-	printk("tvp5150: VPS data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VPS_DATA_REG13));
-	printk("tvp5150: VITC data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VITC_DATA_REG1));
-	printk("tvp5150: VITC data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VITC_DATA_REG2));
-	printk("tvp5150: VITC data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VITC_DATA_REG3));
-	printk("tvp5150: VITC data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VITC_DATA_REG4));
-	printk("tvp5150: VITC data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VITC_DATA_REG5));
-	printk("tvp5150: VITC data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VITC_DATA_REG6));
-	printk("tvp5150: VITC data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VITC_DATA_REG7));
-	printk("tvp5150: VITC data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VITC_DATA_REG8));
-	printk("tvp5150: VITC data registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VITC_DATA_REG9));
-	printk("tvp5150: VBI FIFO read data = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VBI_FIFO_READ_DATA));
-	printk("tvp5150: Teletext filter 1 = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_TELETEXT_FIL_1_1));
-	printk("tvp5150: Teletext filter 1 = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_TELETEXT_FIL_1_2));
-	printk("tvp5150: Teletext filter 1 = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_TELETEXT_FIL_1_3));
-	printk("tvp5150: Teletext filter 1 = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_TELETEXT_FIL_1_4));
-	printk("tvp5150: Teletext filter 1 = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_TELETEXT_FIL_1_5));
-	printk("tvp5150: Teletext filter 2 = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_TELETEXT_FIL_2_1));
-	printk("tvp5150: Teletext filter 2 = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_TELETEXT_FIL_2_2));
-	printk("tvp5150: Teletext filter 2 = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_TELETEXT_FIL_2_3));
-	printk("tvp5150: Teletext filter 2 = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_TELETEXT_FIL_2_4));
-	printk("tvp5150: Teletext filter 2 = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_TELETEXT_FIL_2_5));
+					tvp5150_read(c, TVP5150_INT_ACTIVE_REG_B));
+	printk("tvp5150: Status regs #1 to #5 = %02x %02x %02x %02x %02x\n",
+					tvp5150_read(c, TVP5150_STATUS_REG_1),
+					tvp5150_read(c, TVP5150_STATUS_REG_2),
+					tvp5150_read(c, TVP5150_STATUS_REG_3),
+					tvp5150_read(c, TVP5150_STATUS_REG_4),
+					tvp5150_read(c, TVP5150_STATUS_REG_5));
+
+	dump_reg_range(c,"Teletext filter 1",   TVP5150_TELETEXT_FIL1_INI,
+						TVP5150_TELETEXT_FIL1_END,8);
+	dump_reg_range(c,"Teletext filter 2",   TVP5150_TELETEXT_FIL2_INI,
+						TVP5150_TELETEXT_FIL2_END,8);
+
 	printk("tvp5150: Teletext filter enable = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_TELETEXT_FIL_ENA));
+					tvp5150_read(c, TVP5150_TELETEXT_FIL_ENA));
 	printk("tvp5150: Interrupt status register A = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_INT_STATUS_REG_A));
+					tvp5150_read(c, TVP5150_INT_STATUS_REG_A));
 	printk("tvp5150: Interrupt enable register A = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_INT_ENABLE_REG_A));
+					tvp5150_read(c, TVP5150_INT_ENABLE_REG_A));
 	printk("tvp5150: Interrupt configuration = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_INT_CONF));
-	printk("tvp5150: VDP configuration RAM data = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VDP_CONF_RAM_DATA));
-	printk("tvp5150: Configuration RAM address low byte = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_CONF_RAM_ADDR_LOW));
-	printk("tvp5150: Configuration RAM address high byte = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_CONF_RAM_ADDR_HIGH));
+					tvp5150_read(c, TVP5150_INT_CONF));
 	printk("tvp5150: VDP status register = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_VDP_STATUS_REG));
+					tvp5150_read(c, TVP5150_VDP_STATUS_REG));
 	printk("tvp5150: FIFO word count = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_FIFO_WORD_COUNT));
+					tvp5150_read(c, TVP5150_FIFO_WORD_COUNT));
 	printk("tvp5150: FIFO interrupt threshold = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_FIFO_INT_THRESHOLD));
+					tvp5150_read(c, TVP5150_FIFO_INT_THRESHOLD));
 	printk("tvp5150: FIFO reset = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_FIFO_RESET));
+					tvp5150_read(c, TVP5150_FIFO_RESET));
 	printk("tvp5150: Line number interrupt = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_NUMBER_INT));
-	printk("tvp5150: Pixel alignment register low byte = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_PIX_ALIGN_REG_LOW));
-	printk("tvp5150: Pixel alignment register high byte = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_PIX_ALIGN_REG_HIGH));
+					tvp5150_read(c, TVP5150_LINE_NUMBER_INT));
+	printk("tvp5150: Pixel alignment register = 0x%02x%02x\n",
+					tvp5150_read(c, TVP5150_PIX_ALIGN_REG_HIGH),
+					tvp5150_read(c, TVP5150_PIX_ALIGN_REG_LOW));
 	printk("tvp5150: FIFO output control = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_FIFO_OUT_CTRL));
-	printk("tvp5150: Full field enable 1 = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_FULL_FIELD_ENA_1));
-	printk("tvp5150: Full field enable 2 = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_FULL_FIELD_ENA_2));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_1));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_2));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_3));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_4));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_5));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_6));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_7));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_8));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_9));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_10));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_11));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_12));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_13));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_14));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_15));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_16));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_17));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_18));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_19));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_20));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_21));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_22));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_23));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_24));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_25));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_27));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_28));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_29));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_30));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_31));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_32));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_33));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_34));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_35));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_36));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_37));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_38));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_39));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_40));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_41));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_42));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_43));
-	printk("tvp5150: Line mode registers = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_LINE_MODE_REG_44));
+					tvp5150_read(c, TVP5150_FIFO_OUT_CTRL));
+	printk("tvp5150: Full field enable = 0x%02x\n",
+					tvp5150_read(c, TVP5150_FULL_FIELD_ENA));
 	printk("tvp5150: Full field mode register = 0x%02x\n",
-	       tvp5150_read(c, TVP5150_FULL_FIELD_MODE_REG));
+					tvp5150_read(c, TVP5150_FULL_FIELD_MODE_REG));
+
+	dump_reg_range(c,"CC   data",   TVP5150_CC_DATA_INI,
+					TVP5150_CC_DATA_END,8);
+
+	dump_reg_range(c,"WSS  data",   TVP5150_WSS_DATA_INI,
+					TVP5150_WSS_DATA_END,8);
+
+	dump_reg_range(c,"VPS  data",   TVP5150_VPS_DATA_INI,
+					TVP5150_VPS_DATA_END,8);
+
+	dump_reg_range(c,"VITC data",   TVP5150_VITC_DATA_INI,
+					TVP5150_VITC_DATA_END,10);
+
+	dump_reg_range(c,"Line mode",   TVP5150_LINE_MODE_INI,
+					TVP5150_LINE_MODE_END,8);
 }
 
 /****************************************************************************
@@ -593,10 +442,10 @@
 		TVP5150_FIFO_OUT_CTRL,0x01
 	},
 	{ /* 0xcf */
-		TVP5150_FULL_FIELD_ENA_1,0x00
+		TVP5150_FULL_FIELD_ENA,0x00
 	},
 	{ /* 0xd0 */
-		TVP5150_FULL_FIELD_ENA_2,0x00
+		TVP5150_LINE_MODE_INI,0x00
 	},
 	{ /* 0xfc */
 		TVP5150_FULL_FIELD_MODE_REG,0x7f
@@ -629,54 +478,101 @@
 	}
 };
 
+struct tvp5150_vbi_type {
+	unsigned int vbi_type;
+	unsigned int ini_line;
+	unsigned int end_line;
+	unsigned int by_field :1;
+};
+
 struct i2c_vbi_ram_value {
 	u16 reg;
-	unsigned char values[26];
+	struct tvp5150_vbi_type type;
+	unsigned char values[16];
 };
 
+/* This struct have the values for each supported VBI Standard
+ * by
+ tvp5150_vbi_types should follow the same order as vbi_ram_default
+ * value 0 means rom position 0x10, value 1 means rom position 0x30
+ * and so on. There are 16 possible locations from 0 to 15.
+ */
+
 static struct i2c_vbi_ram_value vbi_ram_default[] =
 {
-	{0x010, /* WST SECAM 6 */
-		{ 0xaa, 0xaa, 0xff, 0xff , 0xe7, 0x2e, 0x20, 0x26, 0xe6, 0xb4, 0x0e, 0x0, 0x0, 0x0, 0x10, 0x0 }
+	{0x010, /* Teletext, SECAM, WST System A */
+		{V4L2_SLICED_TELETEXT_SECAM,6,23,1},
+		{ 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x26,
+		  0xe6, 0xb4, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00 }
 	},
-	{0x030, /* WST PAL B 6 */
-		{ 0xaa, 0xaa, 0xff, 0xff , 0x27, 0x2e, 0x20, 0x2b, 0xa6, 0x72, 0x10, 0x0, 0x0, 0x0, 0x10, 0x0 }
+	{0x030, /* Teletext, PAL, WST System B */
+		{V4L2_SLICED_TELETEXT_PAL_B,6,22,1},
+		{ 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x2b,
+		  0xa6, 0x72, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00 }
 	},
-	{0x050, /* WST PAL C 6 */
-		{ 0xaa, 0xaa, 0xff, 0xff , 0xe7, 0x2e, 0x20, 0x22, 0xa6, 0x98, 0x0d, 0x0, 0x0, 0x0, 0x10, 0x0 }
+	{0x050, /* Teletext, PAL, WST System C */
+		{V4L2_SLICED_TELETEXT_PAL_C,6,22,1},
+		{ 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22,
+		  0xa6, 0x98, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 }
 	},
-	{0x070, /* WST NTSC 6 */
-		{ 0xaa, 0xaa, 0xff, 0xff , 0x27, 0x2e, 0x20, 0x23, 0x69, 0x93, 0x0d, 0x0, 0x0, 0x0, 0x10, 0x0 }
+	{0x070, /* Teletext, NTSC, WST System B */
+		{V4L2_SLICED_TELETEXT_NTSC_B,10,21,1},
+		{ 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x23,
+		  0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 }
 	},
-	{0x090, /* NABTS, NTSC 6 */
-		{ 0xaa, 0xaa, 0xff, 0xff , 0xe7, 0x2e, 0x20, 0x22, 0x69, 0x93, 0x0d, 0x0, 0x0, 0x0, 0x15, 0x0 }
+	{0x090, /* Tetetext, NTSC NABTS System C */
+		{V4L2_SLICED_TELETEXT_NTSC_C,10,21,1},
+		{ 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22,
+		  0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x15, 0x00 }
 	},
-	{0x0b0, /* NABTS, NTSC-J 6 */
-		{ 0xaa, 0xaa, 0xff, 0xff , 0xa7, 0x2e, 0x20, 0x23, 0x69, 0x93, 0x0d, 0x0, 0x0, 0x0, 0x10, 0x0 }
+	{0x0b0, /* Teletext, NTSC-J, NABTS System D */
+		{V4L2_SLICED_TELETEXT_NTSC_D,10,21,1},
+		{ 0xaa, 0xaa, 0xff, 0xff, 0xa7, 0x2e, 0x20, 0x23,
+		  0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 }
 	},
-	{0x0d0, /* CC, PAL/SECAM 6 */
-		{ 0xaa, 0x2a, 0xff, 0x3f , 0x04, 0x51, 0x6e, 0x02, 0xa6, 0x7b, 0x09, 0x0, 0x0, 0x0, 0x27, 0x0 }
+	{0x0d0, /* Closed Caption, PAL/SECAM */
+		{V4L2_SLICED_CAPTION_625,22,22,1},
+		{ 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02,
+		  0xa6, 0x7b, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 }
 	},
-	{0x0f0, /* CC, NTSC 6 */
-		{ 0xaa, 0x2a, 0xff, 0x3f , 0x04, 0x51, 0x6e, 0x02, 0x69, 0x8c, 0x09, 0x0, 0x0, 0x0, 0x27, 0x0 }
+	{0x0f0, /* Closed Caption, NTSC */
+		{V4L2_SLICED_CAPTION_525,21,21,1},
+		{ 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02,
+		  0x69, 0x8c, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 }
 	},
-	{0x110, /* WSS, PAL/SECAM 6 */
-		{ 0x5b, 0x55, 0xc5, 0xff , 0x0, 0x71, 0x6e, 0x42, 0xa6, 0xcd, 0x0f, 0x0, 0x0, 0x0, 0x3a, 0x0 }
+	{0x110, /* Wide Screen Signal, PAL/SECAM */
+		{V4L2_SLICED_WSS_625,23,23,1},
+		{ 0x5b, 0x55, 0xc5, 0xff, 0x00, 0x71, 0x6e, 0x42,
+		  0xa6, 0xcd, 0x0f, 0x00, 0x00, 0x00, 0x3a, 0x00 }
 	},
-	{0x130, /* WSS, NTSC C */
-		{ 0x38, 0x00, 0x3f, 0x00 , 0x0, 0x71, 0x6e, 0x43, 0x69, 0x7c, 0x08, 0x0, 0x0, 0x0, 0x39, 0x0 }
+	{0x130, /* Wide Screen Signal, NTSC C */
+		{V4L2_SLICED_WSS_525,20,20,1},
+		{ 0x38, 0x00, 0x3f, 0x00, 0x00, 0x71, 0x6e, 0x43,
+		  0x69, 0x7c, 0x08, 0x00, 0x00, 0x00, 0x39, 0x00 }
 	},
-	{0x150, /* VITC, PAL/SECAM 6 */
-		{ 0x0, 0x0, 0x0, 0x0 , 0x0, 0x8f, 0x6d, 0x49, 0xa6, 0x85, 0x08, 0x0, 0x0, 0x0, 0x4c, 0x0 }
+	{0x150, /* Vertical Interval Timecode (VITC), PAL/SECAM */
+		{V4l2_SLICED_VITC_625,6,22,0},
+		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49,
+		  0xa6, 0x85, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 }
 	},
-	{0x170, /* VITC, NTSC 6 */
-		{ 0x0, 0x0, 0x0, 0x0 , 0x0, 0x8f, 0x6d, 0x49, 0x69, 0x94, 0x08, 0x0, 0x0, 0x0, 0x4c, 0x0 }
+	{0x170, /* Vertical Interval Timecode (VITC), NTSC */
+		{V4l2_SLICED_VITC_525,10,20,0},
+		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49,
+		  0x69, 0x94, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 }
 	},
+	{0x190, /* Video Program System (VPS), PAL */
+		{V4L2_SLICED_VPS,16,16,0},
+		{ 0xaa, 0xaa, 0xff, 0xff, 0xba, 0xce, 0x2b, 0x0d,
+		  0xa6, 0xda, 0x0b, 0x00, 0x00, 0x00, 0x60, 0x00 }
+	},
+	/* 0x1d0 User programmable */
+
+	/* End of struct */
 	{ (u16)-1 }
 };
 
 static int tvp5150_write_inittab(struct i2c_client *c,
-				 const struct i2c_reg_value *regs)
+				const struct i2c_reg_value *regs)
 {
 	while (regs->reg != 0xff) {
 		tvp5150_write(c, regs->reg, regs->value);
@@ -686,15 +582,15 @@
 }
 
 static int tvp5150_vdp_init(struct i2c_client *c,
-				 const struct i2c_vbi_ram_value *regs)
+				const struct i2c_vbi_ram_value *regs)
 {
 	unsigned int i;
 
 	/* Disable Full Field */
-	tvp5150_write(c, TVP5150_FULL_FIELD_ENA_1, 0);
+	tvp5150_write(c, TVP5150_FULL_FIELD_ENA, 0);
 
 	/* Before programming, Line mode should be at 0xff */
-	for (i=TVP5150_FULL_FIELD_ENA_2; i<=TVP5150_LINE_MODE_REG_44; i++)
+	for (i=TVP5150_LINE_MODE_INI; i<=TVP5150_LINE_MODE_END; i++)
 		tvp5150_write(c, i, 0xff);
 
 	/* Load Ram Table */
@@ -710,6 +606,117 @@
 	return 0;
 }
 
+/* Fills VBI capabilities based on i2c_vbi_ram_value struct */
+static void tvp5150_vbi_get_cap(const struct i2c_vbi_ram_value *regs,
+				struct v4l2_sliced_vbi_cap *cap)
+{
+	int line;
+
+	memset(cap, 0, sizeof *cap);
+
+	while (regs->reg != (u16)-1 ) {
+		for (line=regs->type.ini_line;line<=regs->type.end_line;line++) {
+			cap->service_lines[0][line] |= regs->type.vbi_type;
+		}
+		cap->service_set |= regs->type.vbi_type;
+
+		regs++;
+	}
+}
+
+/* Set vbi processing
+ * type - one of tvp5150_vbi_types
+ * line - line to gather data
+ * fields: bit 0 field1, bit 1, field2
+ * flags (default=0xf0) is a bitmask, were set means:
+ *	bit 7: enable filtering null bytes on CC
+ *	bit 6: send data also to FIFO
+ *	bit 5: don't allow data with errors on FIFO
+ *	bit 4: enable ECC when possible
+ * pix_align = pix alignment:
+ *	LSB = field1
+ *	MSB = field2
+ */
+static int tvp5150_set_vbi(struct i2c_client *c,
+			const struct i2c_vbi_ram_value *regs,
+			unsigned int type,u8 flags, int line,
+			const int fields)
+{
+	struct tvp5150 *decoder = i2c_get_clientdata(c);
+	v4l2_std_id std=decoder->norm;
+	u8 reg;
+	int pos=0;
+
+	if (std == V4L2_STD_ALL) {
+		tvp5150_err("VBI can't be configured without knowing number of lines\n");
+		return 0;
+	} else if (std && V4L2_STD_625_50) {
+		/* Don't follow NTSC Line number convension */
+		line += 3;
+	}
+
+	if (line<6||line>27)
+		return 0;
+
+	while (regs->reg != (u16)-1 ) {
+		if ((type & regs->type.vbi_type) &&
+		    (line>=regs->type.ini_line) &&
+		    (line<=regs->type.end_line)) {
+			type=regs->type.vbi_type;
+			break;
+		}
+
+		regs++;
+		pos++;
+	}
+	if (regs->reg == (u16)-1)
+		return 0;
+
+	type=pos | (flags & 0xf0);
+	reg=((line-6)<<1)+TVP5150_LINE_MODE_INI;
+
+	if (fields&1) {
+		tvp5150_write(c, reg, type);
+	}
+
+	if (fields&2) {
+		tvp5150_write(c, reg+1, type);
+	}
+
+	return type;
+}
+
+static int tvp5150_get_vbi(struct i2c_client *c,
+			const struct i2c_vbi_ram_value *regs, int line)
+{
+	struct tvp5150 *decoder = i2c_get_clientdata(c);
+	v4l2_std_id std=decoder->norm;
+	u8 reg;
+	int pos, type=0;
+
+	if (std == V4L2_STD_ALL) {
+		tvp5150_err("VBI can't be configured without knowing number of lines\n");
+		return 0;
+	} else if (std && V4L2_STD_625_50) {
+		/* Don't follow NTSC Line number convension */
+		line += 3;
+	}
+
+	if (line<6||line>27)
+		return 0;
+
+	reg=((line-6)<<1)+TVP5150_LINE_MODE_INI;
+
+	pos=tvp5150_read(c, reg)&0x0f;
+	if (pos<0x0f)
+		type=regs[pos].type.vbi_type;
+
+	pos=tvp5150_read(c, reg+1)&0x0f;
+	if (pos<0x0f)
+		type|=regs[pos].type.vbi_type;
+
+	return type;
+}
 static int tvp5150_set_std(struct i2c_client *c, v4l2_std_id std)
 {
 	struct tvp5150 *decoder = i2c_get_clientdata(c);
@@ -854,6 +861,69 @@
 		*(v4l2_std_id *)arg = decoder->norm;
 		break;
 
+	case VIDIOC_G_SLICED_VBI_CAP:
+	{
+		struct v4l2_sliced_vbi_cap *cap = arg;
+		tvp5150_dbg(1, "VIDIOC_G_SLICED_VBI_CAP\n");
+
+		tvp5150_vbi_get_cap(vbi_ram_default, cap);
+		break;
+	}
+	case VIDIOC_S_FMT:
+	{
+		struct v4l2_format *fmt;
+		struct v4l2_sliced_vbi_format *svbi;
+		int i;
+
+		fmt = arg;
+		if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+			return -EINVAL;
+		svbi = &fmt->fmt.sliced;
+		if (svbi->service_set != 0) {
+			for (i = 0; i <= 23; i++) {
+				svbi->service_lines[1][i] = 0;
+
+				svbi->service_lines[0][i]=tvp5150_set_vbi(c,
+					 vbi_ram_default,
+					 svbi->service_lines[0][i],0xf0,i,3);
+			}
+			/* Enables FIFO */
+			tvp5150_write(c, TVP5150_FIFO_OUT_CTRL,1);
+		} else {
+			/* Disables FIFO*/
+			tvp5150_write(c, TVP5150_FIFO_OUT_CTRL,0);
+
+			/* Disable Full Field */
+			tvp5150_write(c, TVP5150_FULL_FIELD_ENA, 0);
+
+			/* Disable Line modes */
+			for (i=TVP5150_LINE_MODE_INI; i<=TVP5150_LINE_MODE_END; i++)
+				tvp5150_write(c, i, 0xff);
+		}
+		break;
+	}
+	case VIDIOC_G_FMT:
+	{
+		struct v4l2_format *fmt;
+		struct v4l2_sliced_vbi_format *svbi;
+
+		int i, mask=0;
+
+		fmt = arg;
+		if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+			return -EINVAL;
+		svbi = &fmt->fmt.sliced;
+		memset(svbi, 0, sizeof(*svbi));
+
+		for (i = 0; i <= 23; i++) {
+			svbi->service_lines[0][i]=tvp5150_get_vbi(c,
+				vbi_ram_default,i);
+			mask|=svbi->service_lines[0][i];
+		}
+		svbi->service_set=mask;
+		break;
+	}
+
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 	case VIDIOC_INT_G_REGISTER:
 	{
@@ -878,6 +948,7 @@
 	}
 #endif
 
+	case VIDIOC_LOG_STATUS:
 	case DECODER_DUMP:
 		dump_reg(c);
 		break;
@@ -1097,7 +1168,7 @@
 
 	rv = i2c_attach_client(c);
 
-	core->norm = V4L2_STD_ALL;
+	core->norm = V4L2_STD_ALL;	/* Default is autodetect */
 	core->input = 2;
 	core->enable = 1;
 	core->bright = 32768;
diff --git a/drivers/media/video/tvp5150_reg.h b/drivers/media/video/tvp5150_reg.h
index cd45c1d..4240043 100644
--- a/drivers/media/video/tvp5150_reg.h
+++ b/drivers/media/video/tvp5150_reg.h
@@ -1,3 +1,10 @@
+/*
+ * tvp5150 - Texas Instruments TVP5150A/AM1 video decoder registers
+ *
+ * Copyright (c) 2005,2006 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This code is placed under the terms of the GNU General Public License v2
+ */
+
 #define TVP5150_VD_IN_SRC_SEL_1      0x00 /* Video input source selection #1 */
 #define TVP5150_ANAL_CHL_CTL         0x01 /* Analog channel controls */
 #define TVP5150_OP_MODE_CTL          0x02 /* Operation mode controls */
@@ -64,49 +71,32 @@
 #define TVP5150_STATUS_REG_4        0x8b /* Status register #4 */
 #define TVP5150_STATUS_REG_5        0x8c /* Status register #5 */
 /* Reserved	8Dh-8Fh */
-#define TVP5150_CC_DATA_REG1        0x90 /* Closed caption data registers */
-#define TVP5150_CC_DATA_REG2        0x91 /* Closed caption data registers */
-#define TVP5150_CC_DATA_REG3        0x92 /* Closed caption data registers */
-#define TVP5150_CC_DATA_REG4        0x93 /* Closed caption data registers */
-#define TVP5150_WSS_DATA_REG1       0X94 /* WSS data registers */
-#define TVP5150_WSS_DATA_REG2       0X95 /* WSS data registers */
-#define TVP5150_WSS_DATA_REG3       0X96 /* WSS data registers */
-#define TVP5150_WSS_DATA_REG4       0X97 /* WSS data registers */
-#define TVP5150_WSS_DATA_REG5       0X98 /* WSS data registers */
-#define TVP5150_WSS_DATA_REG6       0X99 /* WSS data registers */
-#define TVP5150_VPS_DATA_REG1       0x9a /* VPS data registers */
-#define TVP5150_VPS_DATA_REG2       0x9b /* VPS data registers */
-#define TVP5150_VPS_DATA_REG3       0x9c /* VPS data registers */
-#define TVP5150_VPS_DATA_REG4       0x9d /* VPS data registers */
-#define TVP5150_VPS_DATA_REG5       0x9e /* VPS data registers */
-#define TVP5150_VPS_DATA_REG6       0x9f /* VPS data registers */
-#define TVP5150_VPS_DATA_REG7       0xa0 /* VPS data registers */
-#define TVP5150_VPS_DATA_REG8       0xa1 /* VPS data registers */
-#define TVP5150_VPS_DATA_REG9       0xa2 /* VPS data registers */
-#define TVP5150_VPS_DATA_REG10      0xa3 /* VPS data registers */
-#define TVP5150_VPS_DATA_REG11      0xa4 /* VPS data registers */
-#define TVP5150_VPS_DATA_REG12      0xa5 /* VPS data registers */
-#define TVP5150_VPS_DATA_REG13      0xa6 /* VPS data registers */
-#define TVP5150_VITC_DATA_REG1      0xa7 /* VITC data registers */
-#define TVP5150_VITC_DATA_REG2      0xa8 /* VITC data registers */
-#define TVP5150_VITC_DATA_REG3      0xa9 /* VITC data registers */
-#define TVP5150_VITC_DATA_REG4      0xaa /* VITC data registers */
-#define TVP5150_VITC_DATA_REG5      0xab /* VITC data registers */
-#define TVP5150_VITC_DATA_REG6      0xac /* VITC data registers */
-#define TVP5150_VITC_DATA_REG7      0xad /* VITC data registers */
-#define TVP5150_VITC_DATA_REG8      0xae /* VITC data registers */
-#define TVP5150_VITC_DATA_REG9      0xaf /* VITC data registers */
+ /* Closed caption data registers */
+#define TVP5150_CC_DATA_INI         0x90
+#define TVP5150_CC_DATA_END         0x93
+
+ /* WSS data registers */
+#define TVP5150_WSS_DATA_INI        0x94
+#define TVP5150_WSS_DATA_END        0x99
+
+/* VPS data registers */
+#define TVP5150_VPS_DATA_INI        0x9a
+#define TVP5150_VPS_DATA_END        0xa6
+
+/* VITC data registers */
+#define TVP5150_VITC_DATA_INI       0xa7
+#define TVP5150_VITC_DATA_END       0xaf
+
 #define TVP5150_VBI_FIFO_READ_DATA  0xb0 /* VBI FIFO read data */
-#define TVP5150_TELETEXT_FIL_1_1    0xb1 /* Teletext filter 1 */
-#define TVP5150_TELETEXT_FIL_1_2    0xb2 /* Teletext filter 1 */
-#define TVP5150_TELETEXT_FIL_1_3    0xb3 /* Teletext filter 1 */
-#define TVP5150_TELETEXT_FIL_1_4    0xb4 /* Teletext filter 1 */
-#define TVP5150_TELETEXT_FIL_1_5    0xb5 /* Teletext filter 1 */
-#define TVP5150_TELETEXT_FIL_2_1    0xb6 /* Teletext filter 2 */
-#define TVP5150_TELETEXT_FIL_2_2    0xb7 /* Teletext filter 2 */
-#define TVP5150_TELETEXT_FIL_2_3    0xb8 /* Teletext filter 2 */
-#define TVP5150_TELETEXT_FIL_2_4    0xb9 /* Teletext filter 2 */
-#define TVP5150_TELETEXT_FIL_2_5    0xba /* Teletext filter 2 */
+
+/* Teletext filter 1 */
+#define TVP5150_TELETEXT_FIL1_INI  0xb1
+#define TVP5150_TELETEXT_FIL1_END  0xb5
+
+/* Teletext filter 2 */
+#define TVP5150_TELETEXT_FIL2_INI  0xb6
+#define TVP5150_TELETEXT_FIL2_END  0xba
+
 #define TVP5150_TELETEXT_FIL_ENA    0xbb /* Teletext filter enable */
 /* Reserved	BCh-BFh */
 #define TVP5150_INT_STATUS_REG_A    0xc0 /* Interrupt status register A */
@@ -124,50 +114,11 @@
 #define TVP5150_PIX_ALIGN_REG_HIGH  0xcc /* Pixel alignment register high byte */
 #define TVP5150_FIFO_OUT_CTRL       0xcd /* FIFO output control */
 /* Reserved	CEh */
-#define TVP5150_FULL_FIELD_ENA_1    0xcf /* Full field enable 1 */
-#define TVP5150_FULL_FIELD_ENA_2    0xd0 /* Full field enable 2 */
-#define TVP5150_LINE_MODE_REG_1     0xd1 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_2     0xd2 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_3     0xd3 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_4     0xd4 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_5     0xd5 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_6     0xd6 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_7     0xd7 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_8     0xd8 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_9     0xd9 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_10    0xda /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_11    0xdb /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_12    0xdc /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_13    0xdd /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_14    0xde /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_15    0xdf /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_16    0xe0 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_17    0xe1 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_18    0xe2 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_19    0xe3 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_20    0xe4 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_21    0xe5 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_22    0xe6 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_23    0xe7 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_24    0xe8 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_25    0xe9 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_27    0xea /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_28    0xeb /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_29    0xec /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_30    0xed /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_31    0xee /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_32    0xef /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_33    0xf0 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_34    0xf1 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_35    0xf2 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_36    0xf3 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_37    0xf4 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_38    0xf5 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_39    0xf6 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_40    0xf7 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_41    0xf8 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_42    0xf9 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_43    0xfa /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_44    0xfb /* Line mode registers */
+#define TVP5150_FULL_FIELD_ENA      0xcf /* Full field enable 1 */
+
+/* Line mode registers */
+#define TVP5150_LINE_MODE_INI       0xd0
+#define TVP5150_LINE_MODE_END       0xfb
+
 #define TVP5150_FULL_FIELD_MODE_REG 0xfc /* Full field mode register */
 /* Reserved	FDh-FFh */
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index cd2c447..95a6e47 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -97,7 +97,7 @@
 	memset(vs, 0, sizeof(struct v4l2_standard));
 	vs->index = index;
 	vs->id    = id;
-	if (id & (V4L2_STD_NTSC | V4L2_STD_PAL_M)) {
+	if (id & V4L2_STD_525_60) {
 		vs->frameperiod.numerator = 1001;
 		vs->frameperiod.denominator = 30000;
 		vs->framelines = 525;
@@ -110,7 +110,6 @@
 	return 0;
 }
 
-
 /* ----------------------------------------------------------------- */
 /* priority handling                                                 */
 
@@ -171,7 +170,7 @@
 
 
 /* ----------------------------------------------------------------- */
-/* some arrays for pretty-printing debug messages                    */
+/* some arrays for pretty-printing debug messages of enum types      */
 
 char *v4l2_field_names[] = {
 	[V4L2_FIELD_ANY]        = "any",
@@ -192,6 +191,14 @@
 	[V4L2_BUF_TYPE_VBI_OUTPUT]    = "vbi-out",
 };
 
+static char *v4l2_memory_names[] = {
+	[V4L2_MEMORY_MMAP]    = "mmap",
+	[V4L2_MEMORY_USERPTR] = "userptr",
+	[V4L2_MEMORY_OVERLAY] = "overlay",
+};
+
+#define prt_names(a,arr) (((a)>=0)&&((a)<ARRAY_SIZE(arr)))?arr[a]:"unknown"
+
 /* ------------------------------------------------------------------ */
 /* debug help functions                                               */
 
@@ -324,6 +331,15 @@
 };
 #define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls)
 
+static void v4l_print_pix_fmt (char *s, struct v4l2_pix_format *fmt)
+{
+	printk ("%s: width=%d, height=%d, format=%d, field=%s, "
+		"bytesperline=%d sizeimage=%d, colorspace=%d\n", s,
+		fmt->width,fmt->height,fmt->pixelformat,
+		prt_names(fmt->field,v4l2_field_names),
+		fmt->bytesperline,fmt->sizeimage,fmt->colorspace);
+};
+
 /* Common ioctl debug function. This function can be used by
    external ioctl messages as well as internal V4L ioctl */
 void v4l_printk_ioctl(unsigned int cmd)
@@ -362,6 +378,541 @@
 	}
 }
 
+/* Common ioctl debug function. This function can be used by
+   external ioctl messages as well as internal V4L ioctl and its
+   arguments */
+void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
+{
+	printk(s);
+	printk(": ");
+	v4l_printk_ioctl(cmd);
+	switch (cmd) {
+	case VIDIOC_INT_G_CHIP_IDENT:
+	{
+		enum v4l2_chip_ident  *p=arg;
+		printk ("%s: chip ident=%d\n", s, *p);
+		break;
+	}
+	case VIDIOC_G_PRIORITY:
+	case VIDIOC_S_PRIORITY:
+	{
+		enum v4l2_priority *p=arg;
+		printk ("%s: priority=%d\n", s, *p);
+		break;
+	}
+	case VIDIOC_INT_S_TUNER_MODE:
+	{
+		enum v4l2_tuner_type *p=arg;
+		printk ("%s: tuner type=%d\n", s, *p);
+		break;
+	}
+	case DECODER_SET_VBI_BYPASS:
+	case DECODER_ENABLE_OUTPUT:
+	case DECODER_GET_STATUS:
+	case DECODER_SET_OUTPUT:
+	case DECODER_SET_INPUT:
+	case DECODER_SET_GPIO:
+	case DECODER_SET_NORM:
+	case VIDIOCCAPTURE:
+	case VIDIOCSYNC:
+	case VIDIOCSWRITEMODE:
+	case TUNER_SET_TYPE_ADDR:
+	case TUNER_SET_STANDBY:
+	case TDA9887_SET_CONFIG:
+	case AUDC_SET_INPUT:
+	case VIDIOC_OVERLAY_OLD:
+	case VIDIOC_STREAMOFF:
+	case VIDIOC_G_OUTPUT:
+	case VIDIOC_S_OUTPUT:
+	case VIDIOC_STREAMON:
+	case VIDIOC_G_INPUT:
+	case VIDIOC_OVERLAY:
+	case VIDIOC_S_INPUT:
+	{
+		int *p=arg;
+		printk ("%s: value=%d\n", s, *p);
+		break;
+	}
+	case MSP_SET_MATRIX:
+	{
+		struct msp_matrix *p=arg;
+		printk ("%s: input=%d, output=%d\n", s, p->input, p->output);
+		break;
+	}
+	case VIDIOC_G_AUDIO:
+	case VIDIOC_S_AUDIO:
+	case VIDIOC_ENUMAUDIO:
+	case VIDIOC_G_AUDIO_OLD:
+	{
+		struct v4l2_audio *p=arg;
+
+		printk ("%s: index=%d, name=%s, capability=%d, mode=%d\n",
+			s,p->index, p->name,p->capability, p->mode);
+		break;
+	}
+	case VIDIOC_G_AUDOUT:
+	case VIDIOC_S_AUDOUT:
+	case VIDIOC_ENUMAUDOUT:
+	case VIDIOC_G_AUDOUT_OLD:
+	{
+		struct v4l2_audioout *p=arg;
+		printk ("%s: index=%d, name=%s, capability=%d, mode=%d\n", s,
+				p->index, p->name, p->capability,p->mode);
+		break;
+	}
+	case VIDIOC_QBUF:
+	case VIDIOC_DQBUF:
+	case VIDIOC_QUERYBUF:
+	{
+		struct v4l2_buffer *p=arg;
+		struct v4l2_timecode *tc=&p->timecode;
+		printk ("%s: %02ld:%02d:%02d.%08ld index=%d, type=%s, "
+			"bytesused=%d, flags=0x%08d, "
+			"field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx\n",
+				s,
+				(p->timestamp.tv_sec/3600),
+				(int)(p->timestamp.tv_sec/60)%60,
+				(int)(p->timestamp.tv_sec%60),
+				p->timestamp.tv_usec,
+				p->index,
+				prt_names(p->type,v4l2_type_names),
+				p->bytesused,p->flags,
+				p->field,p->sequence,
+				prt_names(p->memory,v4l2_memory_names),
+				p->m.userptr);
+		printk ("%s: timecode= %02d:%02d:%02d type=%d, "
+			"flags=0x%08d, frames=%d, userbits=0x%08x",
+				s,tc->hours,tc->minutes,tc->seconds,
+				tc->type, tc->flags, tc->frames, (__u32) tc->userbits);
+		break;
+	}
+	case VIDIOC_QUERYCAP:
+	{
+		struct v4l2_capability *p=arg;
+		printk ("%s: driver=%s, card=%s, bus=%s, version=%d, "
+			"capabilities=%d\n", s,
+				p->driver,p->card,p->bus_info,
+				p->version,
+				p->capabilities);
+		break;
+	}
+	case VIDIOC_G_CTRL:
+	case VIDIOC_S_CTRL:
+	case VIDIOC_S_CTRL_OLD:
+	{
+		struct v4l2_control *p=arg;
+		printk ("%s: id=%d, value=%d\n", s, p->id, p->value);
+		break;
+	}
+	case VIDIOC_G_CROP:
+	case VIDIOC_S_CROP:
+	{
+		struct v4l2_crop *p=arg;
+		/*FIXME: Should also show rect structs */
+		printk ("%s: type=%d\n", s, p->type);
+		break;
+	}
+	case VIDIOC_CROPCAP:
+	case VIDIOC_CROPCAP_OLD:
+	{
+		struct v4l2_cropcap *p=arg;
+		/*FIXME: Should also show rect structs */
+		printk ("%s: type=%d\n", s, p->type);
+		break;
+	}
+	case VIDIOC_INT_DECODE_VBI_LINE:
+	{
+		struct v4l2_decode_vbi_line *p=arg;
+		printk ("%s: is_second_field=%d, ptr=0x%08lx, line=%d, "
+			"type=%d\n", s,
+				p->is_second_field,(unsigned long)p->p,p->line,p->type);
+		break;
+	}
+	case VIDIOC_ENUM_FMT:
+	{
+		struct v4l2_fmtdesc *p=arg;
+		printk ("%s: index=%d, type=%d, flags=%d, description=%s,"
+			" pixelformat=%d\n", s,
+				p->index, p->type, p->flags,p->description,
+				p->pixelformat);
+
+		break;
+	}
+	case VIDIOC_G_FMT:
+	case VIDIOC_S_FMT:
+	case VIDIOC_TRY_FMT:
+	{
+		struct v4l2_format *p=arg;
+		printk ("%s: type=%s\n", s,
+				prt_names(p->type,v4l2_type_names));
+		switch (p->type) {
+		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+			v4l_print_pix_fmt (s, &p->fmt.pix);
+			break;
+		default:
+			break;
+		}
+	}
+	case VIDIOC_G_FBUF:
+	case VIDIOC_S_FBUF:
+	{
+		struct v4l2_framebuffer *p=arg;
+		printk ("%s: capability=%d, flags=%d, base=0x%08lx\n", s,
+				p->capability,p->flags, (unsigned long)p->base);
+		v4l_print_pix_fmt (s, &p->fmt);
+		break;
+	}
+	case VIDIOC_G_FREQUENCY:
+	case VIDIOC_S_FREQUENCY:
+	{
+		struct v4l2_frequency *p=arg;
+		printk ("%s: tuner=%d, type=%d, frequency=%d\n", s,
+				p->tuner,p->type,p->frequency);
+		break;
+	}
+	case VIDIOC_ENUMINPUT:
+	{
+		struct v4l2_input *p=arg;
+		printk ("%s: index=%d, name=%s, type=%d, audioset=%d, "
+			"tuner=%d, std=%lld, status=%d\n", s,
+				p->index,p->name,p->type,p->audioset,
+				p->tuner,p->std,
+				p->status);
+		break;
+	}
+	case VIDIOC_G_JPEGCOMP:
+	case VIDIOC_S_JPEGCOMP:
+	{
+		struct v4l2_jpegcompression *p=arg;
+		printk ("%s: quality=%d, APPn=%d, APP_len=%d, COM_len=%d,"
+			" jpeg_markers=%d\n", s,
+				p->quality,p->APPn,p->APP_len,
+				p->COM_len,p->jpeg_markers);
+		break;
+	}
+	case VIDIOC_G_MODULATOR:
+	case VIDIOC_S_MODULATOR:
+	{
+		struct v4l2_modulator *p=arg;
+		printk ("%s: index=%d, name=%s, capability=%d, rangelow=%d,"
+			" rangehigh=%d, txsubchans=%d\n", s,
+				p->index, p->name,p->capability,p->rangelow,
+				p->rangehigh,p->txsubchans);
+		break;
+	}
+	case VIDIOC_G_MPEGCOMP:
+	case VIDIOC_S_MPEGCOMP:
+	{
+		struct v4l2_mpeg_compression *p=arg;
+		/*FIXME: Several fields not shown */
+		printk ("%s: ts_pid_pmt=%d, ts_pid_audio=%d, ts_pid_video=%d, "
+			"ts_pid_pcr=%d, ps_size=%d, au_sample_rate=%d, "
+			"au_pesid=%c, vi_frame_rate=%d, vi_frames_per_gop=%d, "
+			"vi_bframes_count=%d, vi_pesid=%c\n", s,
+				p->ts_pid_pmt,p->ts_pid_audio, p->ts_pid_video,
+				p->ts_pid_pcr, p->ps_size, p->au_sample_rate,
+				p->au_pesid, p->vi_frame_rate,
+				p->vi_frames_per_gop, p->vi_bframes_count,
+				p->vi_pesid);
+		break;
+	}
+	case VIDIOC_ENUMOUTPUT:
+	{
+		struct v4l2_output *p=arg;
+		printk ("%s: index=%d, name=%s,type=%d, audioset=%d, "
+			"modulator=%d, std=%lld\n",
+				s,p->index,p->name,p->type,p->audioset,
+				p->modulator,p->std);
+		break;
+	}
+	case VIDIOC_QUERYCTRL:
+	{
+		struct v4l2_queryctrl *p=arg;
+		printk ("%s: id=%d, type=%d, name=%s, min/max=%d/%d,"
+			" step=%d, default=%d, flags=0x%08x\n", s,
+				p->id,p->type,p->name,p->minimum,p->maximum,
+				p->step,p->default_value,p->flags);
+		break;
+	}
+	case VIDIOC_QUERYMENU:
+	{
+		struct v4l2_querymenu *p=arg;
+		printk ("%s: id=%d, index=%d, name=%s\n", s,
+				p->id,p->index,p->name);
+		break;
+	}
+	case VIDIOC_INT_G_REGISTER:
+	case VIDIOC_INT_S_REGISTER:
+	{
+		struct v4l2_register *p=arg;
+		printk ("%s: i2c_id=%d, reg=%lu, val=%d\n", s,
+				p->i2c_id,p->reg,p->val);
+
+		break;
+	}
+	case VIDIOC_REQBUFS:
+	{
+		struct v4l2_requestbuffers *p=arg;
+		printk ("%s: count=%d, type=%s, memory=%s\n", s,
+				p->count,
+				prt_names(p->type,v4l2_type_names),
+				prt_names(p->memory,v4l2_memory_names));
+		break;
+	}
+	case VIDIOC_INT_S_AUDIO_ROUTING:
+	case VIDIOC_INT_S_VIDEO_ROUTING:
+	case VIDIOC_INT_G_AUDIO_ROUTING:
+	case VIDIOC_INT_G_VIDEO_ROUTING:
+	{
+		struct v4l2_routing  *p=arg;
+		printk ("%s: input=%d, output=%d\n", s, p->input, p->output);
+		break;
+	}
+	case VIDIOC_G_SLICED_VBI_CAP:
+	{
+		struct v4l2_sliced_vbi_cap *p=arg;
+		printk ("%s: service_set=%d\n", s,
+				p->service_set);
+		break;
+	}
+	case VIDIOC_INT_S_VBI_DATA:
+	case VIDIOC_INT_G_VBI_DATA:
+	{
+		struct v4l2_sliced_vbi_data  *p=arg;
+		printk ("%s: id=%d, field=%d, line=%d\n", s,
+				p->id, p->field, p->line);
+		break;
+	}
+	case VIDIOC_ENUMSTD:
+	{
+		struct v4l2_standard *p=arg;
+		printk ("%s: index=%d, id=%lld, name=%s, fps=%d/%d, framelines=%d\n", s,
+				p->index, p->id, p->name,
+				p->frameperiod.numerator,
+				p->frameperiod.denominator,
+				p->framelines);
+
+		break;
+	}
+	case VIDIOC_G_PARM:
+	case VIDIOC_S_PARM:
+	case VIDIOC_S_PARM_OLD:
+	{
+		struct v4l2_streamparm *p=arg;
+		printk ("%s: type=%d\n", s, p->type);
+
+		break;
+	}
+	case VIDIOC_G_TUNER:
+	case VIDIOC_S_TUNER:
+	{
+		struct v4l2_tuner *p=arg;
+		printk ("%s: index=%d, name=%s, type=%d, capability=%d, "
+			"rangelow=%d, rangehigh=%d, signal=%d, afc=%d, "
+			"rxsubchans=%d, audmode=%d\n", s,
+				p->index, p->name, p->type,
+				p->capability, p->rangelow,p->rangehigh,
+				p->rxsubchans, p->audmode, p->signal,
+				p->afc);
+		break;
+	}
+	case VIDIOCGVBIFMT:
+	case VIDIOCSVBIFMT:
+	{
+		struct vbi_format *p=arg;
+		printk ("%s: sampling_rate=%d, samples_per_line=%d, "
+			"sample_format=%d, start=%d/%d, count=%d/%d, flags=%d\n", s,
+				p->sampling_rate,p->samples_per_line,
+				p->sample_format,p->start[0],p->start[1],
+				p->count[0],p->count[1],p->flags);
+		break;
+	}
+	case VIDIOCGAUDIO:
+	case VIDIOCSAUDIO:
+	{
+		struct video_audio *p=arg;
+		printk ("%s: audio=%d, volume=%d, bass=%d, treble=%d, "
+			"flags=%d, name=%s, mode=%d, balance=%d, step=%d\n",
+				s,p->audio,p->volume,p->bass, p->treble,
+				p->flags,p->name,p->mode,p->balance,p->step);
+		break;
+	}
+	case VIDIOCGFBUF:
+	case VIDIOCSFBUF:
+	{
+		struct video_buffer *p=arg;
+		printk ("%s: base=%08lx, height=%d, width=%d, depth=%d, "
+			"bytesperline=%d\n", s,
+				(unsigned long) p->base, p->height, p->width,
+				p->depth,p->bytesperline);
+		break;
+	}
+	case VIDIOCGCAP:
+	{
+		struct video_capability *p=arg;
+		printk ("%s: name=%s, type=%d, channels=%d, audios=%d, "
+			"maxwidth=%d, maxheight=%d, minwidth=%d, minheight=%d\n",
+				s,p->name,p->type,p->channels,p->audios,
+				p->maxwidth,p->maxheight,p->minwidth,
+				p->minheight);
+
+		break;
+	}
+	case VIDIOCGCAPTURE:
+	case VIDIOCSCAPTURE:
+	{
+		struct video_capture *p=arg;
+		printk ("%s: x=%d, y=%d, width=%d, height=%d, decimation=%d,"
+			" flags=%d\n", s,
+				p->x, p->y,p->width, p->height,
+				p->decimation,p->flags);
+		break;
+	}
+	case VIDIOCGCHAN:
+	case VIDIOCSCHAN:
+	{
+		struct video_channel *p=arg;
+		printk ("%s: channel=%d, name=%s, tuners=%d, flags=%d, "
+			"type=%d, norm=%d\n", s,
+				p->channel,p->name,p->tuners,
+				p->flags,p->type,p->norm);
+
+		break;
+	}
+	case VIDIOCSMICROCODE:
+	{
+		struct video_code *p=arg;
+		printk ("%s: loadwhat=%s, datasize=%d\n", s,
+				p->loadwhat,p->datasize);
+		break;
+	}
+	case DECODER_GET_CAPABILITIES:
+	{
+		struct video_decoder_capability *p=arg;
+		printk ("%s: flags=%d, inputs=%d, outputs=%d\n", s,
+				p->flags,p->inputs,p->outputs);
+		break;
+	}
+	case DECODER_INIT:
+	{
+		struct video_decoder_init *p=arg;
+		printk ("%s: len=%c\n", s, p->len);
+		break;
+	}
+	case VIDIOCGPLAYINFO:
+	{
+		struct video_info *p=arg;
+		printk ("%s: frame_count=%d, h_size=%d, v_size=%d, "
+			"smpte_timecode=%d, picture_type=%d, "
+			"temporal_reference=%d, user_data=%s\n", s,
+				p->frame_count, p->h_size,
+				p->v_size, p->smpte_timecode,
+				p->picture_type, p->temporal_reference,
+				p->user_data);
+		break;
+	}
+	case VIDIOCKEY:
+	{
+		struct video_key *p=arg;
+		printk ("%s: key=%s, flags=%d\n", s,
+				p->key, p->flags);
+		break;
+	}
+	case VIDIOCGMBUF:
+	{
+		struct video_mbuf *p=arg;
+		printk ("%s: size=%d, frames=%d, offsets=0x%08lx\n", s,
+				p->size,
+				p->frames,
+				(unsigned long)p->offsets);
+		break;
+	}
+	case VIDIOCMCAPTURE:
+	{
+		struct video_mmap *p=arg;
+		printk ("%s: frame=%d, height=%d, width=%d, format=%d\n", s,
+				p->frame,
+				p->height, p->width,
+				p->format);
+		break;
+	}
+	case VIDIOCGPICT:
+	case VIDIOCSPICT:
+	case DECODER_SET_PICTURE:
+	{
+		struct video_picture *p=arg;
+
+		printk ("%s: brightness=%d, hue=%d, colour=%d, contrast=%d,"
+			" whiteness=%d, depth=%d, palette=%d\n", s,
+				p->brightness, p->hue, p->colour,
+				p->contrast, p->whiteness, p->depth,
+				p->palette);
+		break;
+	}
+	case VIDIOCSPLAYMODE:
+	{
+		struct video_play_mode *p=arg;
+		printk ("%s: mode=%d, p1=%d, p2=%d\n", s,
+				p->mode,p->p1,p->p2);
+		break;
+	}
+	case VIDIOCGTUNER:
+	case VIDIOCSTUNER:
+	{
+		struct video_tuner *p=arg;
+		printk ("%s: tuner=%d, name=%s, rangelow=%ld, rangehigh=%ld, "
+			"flags=%d, mode=%d, signal=%d\n", s,
+				p->tuner, p->name,p->rangelow, p->rangehigh,
+				p->flags,p->mode, p->signal);
+		break;
+	}
+	case VIDIOCGUNIT:
+	{
+		struct video_unit *p=arg;
+		printk ("%s: video=%d, vbi=%d, radio=%d, audio=%d, "
+			"teletext=%d\n", s,
+				p->video,p->vbi,p->radio,p->audio,p->teletext);
+		break;
+	}
+	case VIDIOCGWIN:
+	case VIDIOCSWIN:
+	{
+		struct video_window *p=arg;
+		printk ("%s: x=%d, y=%d, width=%d, height=%d, chromakey=%d,"
+			" flags=%d, clipcount=%d\n", s,
+				p->x, p->y,p->width, p->height,
+				p->chromakey,p->flags,
+				p->clipcount);
+		break;
+	}
+	case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+	case VIDIOC_INT_I2S_CLOCK_FREQ:
+	case VIDIOC_INT_S_STANDBY:
+	{
+		u32 *p=arg;
+
+		printk ("%s: value=%d\n", s, *p);
+		break;
+	}
+	case VIDIOCGFREQ:
+	case VIDIOCSFREQ:
+	{
+		unsigned long *p=arg;
+		printk ("%s: value=%lu\n", s, *p);
+		break;
+	}
+	case VIDIOC_G_STD:
+	case VIDIOC_S_STD:
+	case VIDIOC_QUERYSTD:
+	{
+		v4l2_std_id *p=arg;
+
+		printk ("%s: value=%llu\n", s, *p);
+		break;
+	}
+	}
+}
+
 /* ----------------------------------------------------------------- */
 
 EXPORT_SYMBOL(v4l2_video_std_construct);
@@ -376,6 +927,7 @@
 EXPORT_SYMBOL(v4l2_field_names);
 EXPORT_SYMBOL(v4l2_type_names);
 EXPORT_SYMBOL(v4l_printk_ioctl);
+EXPORT_SYMBOL(v4l_printk_ioctl_arg);
 
 /*
  * Local variables:
diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/video-buf-dvb.c
index 0a4004a..caf3e7e 100644
--- a/drivers/media/video/video-buf-dvb.c
+++ b/drivers/media/video/video-buf-dvb.c
@@ -96,7 +96,7 @@
 	if (!demux->dmx.frontend)
 		return -EINVAL;
 
-	down(&dvb->lock);
+	mutex_lock(&dvb->lock);
 	dvb->nfeeds++;
 	rc = dvb->nfeeds;
 
@@ -110,7 +110,7 @@
 	}
 
 out:
-	up(&dvb->lock);
+	mutex_unlock(&dvb->lock);
 	return rc;
 }
 
@@ -120,14 +120,14 @@
 	struct videobuf_dvb *dvb = demux->priv;
 	int err = 0;
 
-	down(&dvb->lock);
+	mutex_lock(&dvb->lock);
 	dvb->nfeeds--;
 	if (0 == dvb->nfeeds  &&  NULL != dvb->thread) {
 		// FIXME: cx8802_cancel_buffers(dev);
 		err = kthread_stop(dvb->thread);
 		dvb->thread = NULL;
 	}
-	up(&dvb->lock);
+	mutex_unlock(&dvb->lock);
 	return err;
 }
 
@@ -139,7 +139,7 @@
 {
 	int result;
 
-	init_MUTEX(&dvb->lock);
+	mutex_init(&dvb->lock);
 
 	/* register adapter */
 	result = dvb_register_adapter(&dvb->adapter, dvb->name, module);
diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c
index 9ef4775..87e9375 100644
--- a/drivers/media/video/video-buf.c
+++ b/drivers/media/video/video-buf.c
@@ -59,8 +59,7 @@
 		pg = vmalloc_to_page(virt);
 		if (NULL == pg)
 			goto err;
-		if (PageHighMem(pg))
-			BUG();
+		BUG_ON(PageHighMem(pg));
 		sglist[i].page   = pg;
 		sglist[i].length = PAGE_SIZE;
 	}
@@ -385,7 +384,7 @@
 	q->ops     = ops;
 	q->priv_data = priv;
 
-	init_MUTEX(&q->lock);
+	mutex_init(&q->lock);
 	INIT_LIST_HEAD(&q->stream);
 }
 
@@ -428,7 +427,7 @@
 void
 videobuf_queue_cancel(struct videobuf_queue *q)
 {
-	unsigned long flags;
+	unsigned long flags=0;
 	int i;
 
 	/* remove queued buffers from list */
@@ -549,7 +548,7 @@
 	if (!list_empty(&q->stream))
 		return -EBUSY;
 
-	down(&q->lock);
+	mutex_lock(&q->lock);
 	count = req->count;
 	if (count > VIDEO_MAX_FRAME)
 		count = VIDEO_MAX_FRAME;
@@ -566,7 +565,7 @@
 	req->count = count;
 
  done:
-	up(&q->lock);
+	mutex_unlock(&q->lock);
 	return retval;
 }
 
@@ -589,10 +588,10 @@
 {
 	struct videobuf_buffer *buf;
 	enum v4l2_field field;
-	unsigned long flags;
+	unsigned long flags=0;
 	int retval;
 
-	down(&q->lock);
+	mutex_lock(&q->lock);
 	retval = -EBUSY;
 	if (q->reading)
 		goto done;
@@ -652,7 +651,7 @@
 	retval = 0;
 
  done:
-	up(&q->lock);
+	mutex_unlock(&q->lock);
 	return retval;
 }
 
@@ -663,7 +662,7 @@
 	struct videobuf_buffer *buf;
 	int retval;
 
-	down(&q->lock);
+	mutex_lock(&q->lock);
 	retval = -EBUSY;
 	if (q->reading)
 		goto done;
@@ -693,7 +692,7 @@
 	videobuf_status(b,buf,q->type);
 
  done:
-	up(&q->lock);
+	mutex_unlock(&q->lock);
 	return retval;
 }
 
@@ -701,10 +700,10 @@
 {
 	struct videobuf_buffer *buf;
 	struct list_head *list;
-	unsigned long flags;
+	unsigned long flags=0;
 	int retval;
 
-	down(&q->lock);
+	mutex_lock(&q->lock);
 	retval = -EBUSY;
 	if (q->reading)
 		goto done;
@@ -721,7 +720,7 @@
 	spin_unlock_irqrestore(q->irqlock,flags);
 
  done:
-	up(&q->lock);
+	mutex_unlock(&q->lock);
 	return retval;
 }
 
@@ -729,7 +728,7 @@
 {
 	int retval = -EINVAL;
 
-	down(&q->lock);
+	mutex_lock(&q->lock);
 	if (!q->streaming)
 		goto done;
 	videobuf_queue_cancel(q);
@@ -737,7 +736,7 @@
 	retval = 0;
 
  done:
-	up(&q->lock);
+	mutex_unlock(&q->lock);
 	return retval;
 }
 
@@ -746,7 +745,7 @@
 		       size_t count, loff_t *ppos)
 {
 	enum v4l2_field field;
-	unsigned long flags;
+	unsigned long flags=0;
 	int retval;
 
 	/* setup stuff */
@@ -788,11 +787,11 @@
 			  int nonblocking)
 {
 	enum v4l2_field field;
-	unsigned long flags;
+	unsigned long flags=0;
 	unsigned size, nbufs, bytes;
 	int retval;
 
-	down(&q->lock);
+	mutex_lock(&q->lock);
 
 	nbufs = 1; size = 0;
 	q->ops->buf_setup(q,&nbufs,&size);
@@ -860,14 +859,14 @@
 	}
 
  done:
-	up(&q->lock);
+	mutex_unlock(&q->lock);
 	return retval;
 }
 
 int videobuf_read_start(struct videobuf_queue *q)
 {
 	enum v4l2_field field;
-	unsigned long flags;
+	unsigned long flags=0;
 	int count = 0, size = 0;
 	int err, i;
 
@@ -919,10 +918,10 @@
 {
 	unsigned int *fc, bytes;
 	int err, retval;
-	unsigned long flags;
+	unsigned long flags=0;
 
 	dprintk(2,"%s\n",__FUNCTION__);
-	down(&q->lock);
+	mutex_lock(&q->lock);
 	retval = -EBUSY;
 	if (q->streaming)
 		goto done;
@@ -996,7 +995,7 @@
 	}
 
  done:
-	up(&q->lock);
+	mutex_unlock(&q->lock);
 	return retval;
 }
 
@@ -1007,7 +1006,7 @@
 	struct videobuf_buffer *buf = NULL;
 	unsigned int rc = 0;
 
-	down(&q->lock);
+	mutex_lock(&q->lock);
 	if (q->streaming) {
 		if (!list_empty(&q->stream))
 			buf = list_entry(q->stream.next,
@@ -1035,7 +1034,7 @@
 		    buf->state == STATE_ERROR)
 			rc = POLLIN|POLLRDNORM;
 	}
-	up(&q->lock);
+	mutex_unlock(&q->lock);
 	return rc;
 }
 
@@ -1064,7 +1063,7 @@
 	map->count--;
 	if (0 == map->count) {
 		dprintk(1,"munmap %p q=%p\n",map,q);
-		down(&q->lock);
+		mutex_lock(&q->lock);
 		for (i = 0; i < VIDEO_MAX_FRAME; i++) {
 			if (NULL == q->bufs[i])
 				continue;
@@ -1076,7 +1075,7 @@
 			q->bufs[i]->baddr = 0;
 			q->ops->buf_release(q,q->bufs[i]);
 		}
-		up(&q->lock);
+		mutex_unlock(&q->lock);
 		kfree(map);
 	}
 	return;
@@ -1170,7 +1169,7 @@
 	unsigned int first,last,size,i;
 	int retval;
 
-	down(&q->lock);
+	mutex_lock(&q->lock);
 	retval = -EINVAL;
 	if (!(vma->vm_flags & VM_WRITE)) {
 		dprintk(1,"mmap app bug: PROT_WRITE please\n");
@@ -1238,7 +1237,7 @@
 	retval = 0;
 
  done:
-	up(&q->lock);
+	mutex_unlock(&q->lock);
 	return retval;
 }
 
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index 078880e..75e3d41 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -224,13 +224,13 @@
 	struct  video_device *vfl = video_devdata(file);
 	int retval = 0;
 
-	down(&vfl->lock);
+	mutex_lock(&vfl->lock);
 	if (vfl->users) {
 		retval = -EBUSY;
 	} else {
 		vfl->users++;
 	}
-	up(&vfl->lock);
+	mutex_unlock(&vfl->lock);
 	return retval;
 }
 
@@ -279,23 +279,23 @@
 	switch(type)
 	{
 		case VFL_TYPE_GRABBER:
-			base=0;
-			end=64;
+			base=MINOR_VFL_TYPE_GRABBER_MIN;
+			end=MINOR_VFL_TYPE_GRABBER_MAX+1;
 			name_base = "video";
 			break;
 		case VFL_TYPE_VTX:
-			base=192;
-			end=224;
+			base=MINOR_VFL_TYPE_VTX_MIN;
+			end=MINOR_VFL_TYPE_VTX_MAX+1;
 			name_base = "vtx";
 			break;
 		case VFL_TYPE_VBI:
-			base=224;
-			end=256;
+			base=MINOR_VFL_TYPE_VBI_MIN;
+			end=MINOR_VFL_TYPE_VBI_MAX+1;
 			name_base = "vbi";
 			break;
 		case VFL_TYPE_RADIO:
-			base=64;
-			end=128;
+			base=MINOR_VFL_TYPE_RADIO_MIN;
+			end=MINOR_VFL_TYPE_RADIO_MAX+1;
 			name_base = "radio";
 			break;
 		default:
@@ -328,7 +328,7 @@
 	sprintf(vfd->devfs_name, "v4l/%s%d", name_base, i - base);
 	devfs_mk_cdev(MKDEV(VIDEO_MAJOR, vfd->minor),
 			S_IFCHR | S_IRUSR | S_IWUSR, vfd->devfs_name);
-	init_MUTEX(&vfd->lock);
+	mutex_init(&vfd->lock);
 
 	/* sysfs class */
 	memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev));
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index c8fd823..0229819 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -42,6 +42,7 @@
 #include <linux/videodev.h>
 #include <linux/videodev2.h>
 #include <linux/video_decoder.h>
+#include <linux/mutex.h>
 
 #include <asm/paccess.h>
 #include <asm/io.h>
@@ -245,7 +246,7 @@
 	struct vino_framebuffer *buffer[VINO_FRAMEBUFFER_COUNT_MAX];
 
 	spinlock_t queue_lock;
-	struct semaphore queue_sem;
+	struct mutex queue_mutex;
 	wait_queue_head_t frame_wait_queue;
 };
 
@@ -283,7 +284,7 @@
 	/* the driver is currently processing the queue */
 	int capturing;
 
-	struct semaphore sem;
+	struct mutex mutex;
 	spinlock_t capture_lock;
 
 	unsigned int users;
@@ -1131,11 +1132,11 @@
 	if (q->type != VINO_MEMORY_MMAP)
 		return;
 
-	down(&q->queue_sem);
+	mutex_lock(&q->queue_mutex);
 
 	vino_queue_free_with_count(q, q->length);
 
-	up(&q->queue_sem);
+	mutex_unlock(&q->queue_mutex);
 }
 
 static int vino_queue_init(struct vino_framebuffer_queue *q,
@@ -1159,7 +1160,7 @@
 	if (*length < 1)
 		return -EINVAL;
 
-	down(&q->queue_sem);
+	mutex_lock(&q->queue_mutex);
 
 	if (*length > VINO_FRAMEBUFFER_COUNT_MAX)
 		*length = VINO_FRAMEBUFFER_COUNT_MAX;
@@ -1211,7 +1212,7 @@
 		q->magic = VINO_QUEUE_MAGIC;
 	}
 
-	up(&q->queue_sem);
+	mutex_unlock(&q->queue_mutex);
 
 	return ret;
 }
@@ -4045,7 +4046,7 @@
 	dprintk("open(): channel = %c\n",
 	       (vcs->channel == VINO_CHANNEL_A) ? 'A' : 'B');
 
-	down(&vcs->sem);
+	mutex_lock(&vcs->mutex);
 
 	if (vcs->users) {
 		dprintk("open(): driver busy\n");
@@ -4062,7 +4063,7 @@
 	vcs->users++;
 
  out:
-	up(&vcs->sem);
+	mutex_unlock(&vcs->mutex);
 
 	dprintk("open(): %s!\n", ret ? "failed" : "complete");
 
@@ -4075,7 +4076,7 @@
 	struct vino_channel_settings *vcs = video_get_drvdata(dev);
 	dprintk("close():\n");
 
-	down(&vcs->sem);
+	mutex_lock(&vcs->mutex);
 
 	vcs->users--;
 
@@ -4087,7 +4088,7 @@
 		vino_queue_free(&vcs->fb_queue);
 	}
 
-	up(&vcs->sem);
+	mutex_unlock(&vcs->mutex);
 
 	return 0;
 }
@@ -4130,7 +4131,7 @@
 
 	// TODO: reject mmap if already mapped
 
-	if (down_interruptible(&vcs->sem))
+	if (mutex_lock_interruptible(&vcs->mutex))
 		return -EINTR;
 
 	if (vcs->reading) {
@@ -4214,7 +4215,7 @@
 	vma->vm_ops = &vino_vm_ops;
 
 out:
-	up(&vcs->sem);
+	mutex_unlock(&vcs->mutex);
 
 	return ret;
 }
@@ -4374,12 +4375,12 @@
 	struct vino_channel_settings *vcs = video_get_drvdata(dev);
 	int ret;
 
-	if (down_interruptible(&vcs->sem))
+	if (mutex_lock_interruptible(&vcs->mutex))
 		return -EINTR;
 
 	ret = video_usercopy(inode, file, cmd, arg, vino_do_ioctl);
 
-	up(&vcs->sem);
+	mutex_unlock(&vcs->mutex);
 
 	return ret;
 }
@@ -4564,10 +4565,10 @@
 
 	vcs->capturing = 0;
 
-	init_MUTEX(&vcs->sem);
+	mutex_init(&vcs->mutex);
 	spin_lock_init(&vcs->capture_lock);
 
-	init_MUTEX(&vcs->fb_queue.queue_sem);
+	mutex_init(&vcs->fb_queue.queue_mutex);
 	spin_lock_init(&vcs->fb_queue.queue_lock);
 	init_waitqueue_head(&vcs->fb_queue.frame_wait_queue);
 
diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c
index 285d7d0..c32fad1 100644
--- a/drivers/mmc/pxamci.c
+++ b/drivers/mmc/pxamci.c
@@ -438,7 +438,7 @@
 
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	irq = platform_get_irq(pdev, 0);
-	if (!r || irq == NO_IRQ)
+	if (!r || irq < 0)
 		return -ENXIO;
 
 	r = request_mem_region(r->start, SZ_4K, DRIVER_NAME);
diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c
index 53e3afc..09d5c3f 100644
--- a/drivers/net/arm/am79c961a.c
+++ b/drivers/net/arm/am79c961a.c
@@ -696,7 +696,9 @@
 	dev->base_addr = res->start;
 	dev->irq = platform_get_irq(pdev, 0);
 
-    	ret = -ENODEV;
+	ret = -ENODEV;
+	if (dev->irq < 0)
+		goto nodev;
 	if (!request_region(dev->base_addr, 0x18, dev->name))
 		goto nodev;
 
diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c
index e67b1d0..95e2bb8 100644
--- a/drivers/net/fs_enet/mac-fcc.c
+++ b/drivers/net/fs_enet/mac-fcc.c
@@ -118,6 +118,8 @@
 
 	/* Fill out IRQ field */
 	fep->interrupt = platform_get_irq(pdev, 0);
+	if (fep->interrupt < 0)
+		return -EINVAL;
 
 	/* Attach the memory for the FCC Parameter RAM */
 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_pram");
diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c
index 2e8f444..3dad69d 100644
--- a/drivers/net/fs_enet/mac-fec.c
+++ b/drivers/net/fs_enet/mac-fec.c
@@ -144,6 +144,8 @@
 	
 	/* Fill out IRQ field */
 	fep->interrupt = platform_get_irq_byname(pdev,"interrupt");
+	if (fep->interrupt < 0)
+		return -EINVAL;
 	
 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
 	fep->fec.fecp =(void*)r->start;
diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c
index a3897fd..a772b28 100644
--- a/drivers/net/fs_enet/mac-scc.c
+++ b/drivers/net/fs_enet/mac-scc.c
@@ -118,6 +118,8 @@
 
 	/* Fill out IRQ field */
 	fep->interrupt = platform_get_irq_byname(pdev, "interrupt");
+	if (fep->interrupt < 0)
+		return -EINVAL;
 
 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
 	fep->scc.sccp = (void *)r->start;
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 0e8e3fc..771e25d 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -193,8 +193,12 @@
 		priv->interruptTransmit = platform_get_irq_byname(pdev, "tx");
 		priv->interruptReceive = platform_get_irq_byname(pdev, "rx");
 		priv->interruptError = platform_get_irq_byname(pdev, "error");
+		if (priv->interruptTransmit < 0 || priv->interruptReceive < 0 || priv->interruptError < 0)
+			goto regs_fail;
 	} else {
 		priv->interruptTransmit = platform_get_irq(pdev, 0);
+		if (priv->interruptTransmit < 0)
+			goto regs_fail;
 	}
 
 	/* get a pointer to the register memory */
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index 8936058..6e2ec56 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -740,7 +740,7 @@
 	struct sk_buff *newskb;
 	struct sk_buff *dataskb;
 	struct urb *next_urb;
-	int		docopy;
+	unsigned int len, docopy;
 
 	IRDA_DEBUG(2, "%s(), len=%d\n", __FUNCTION__, urb->actual_length);
 	
@@ -851,10 +851,11 @@
 	dataskb->dev = self->netdev;
 	dataskb->mac.raw  = dataskb->data;
 	dataskb->protocol = htons(ETH_P_IRDA);
+	len = dataskb->len;
 	netif_rx(dataskb);
 
 	/* Keep stats up to date */
-	self->stats.rx_bytes += dataskb->len;
+	self->stats.rx_bytes += len;
 	self->stats.rx_packets++;
 	self->netdev->last_rx = jiffies;
 
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index 7ec0812..75e9b3b 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -2221,6 +2221,10 @@
 
 	ndev->dma = (unsigned char)-1;
 	ndev->irq = platform_get_irq(pdev, 0);
+	if (ndev->irq < 0) {
+		ret = -ENODEV;
+		goto out_free_netdev;
+	}
 
 	ret = smc_request_attrib(pdev);
 	if (ret)
diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c
index 47b5ade..2c23d75 100644
--- a/drivers/pcmcia/omap_cf.c
+++ b/drivers/pcmcia/omap_cf.c
@@ -218,7 +218,7 @@
 
 	/* either CFLASH.IREQ (INT_1610_CF) or some GPIO */
 	irq = platform_get_irq(pdev, 0);
-	if (!irq)
+	if (irq < 0)
 		return -EINVAL;
 
 	cf = kcalloc(1, sizeof *cf, GFP_KERNEL);
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 3c606cf..5c94a5d 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -379,6 +379,14 @@
 config SCSI_AACRAID
 	tristate "Adaptec AACRAID support"
 	depends on SCSI && PCI
+	help
+	  This driver supports a variety of Dell, HP, Adaptec, IBM and
+	  ICP storage products. For a list of supported products, refer
+	  to <file:Documentation/scsi/aacraid.txt>.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called aacraid.
+
 
 source "drivers/scsi/aic7xxx/Kconfig.aic7xxx"
 
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 320e765..15dc2e0 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -163,7 +163,7 @@
 CFLAGS_ncr53c8xx.o	:= $(ncr53c8xx-flags-y) $(ncr53c8xx-flags-m)
 zalon7xx-objs	:= zalon.o ncr53c8xx.o
 NCR_Q720_mod-objs	:= NCR_Q720.o ncr53c8xx.o
-libata-objs	:= libata-core.o libata-scsi.o
+libata-objs	:= libata-core.o libata-scsi.o libata-bmdma.o
 oktagon_esp_mod-objs	:= oktagon_esp.o oktagon_io.o
 
 # Files generated that shall be removed upon make clean
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 559ff7a..e97ab3e 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -66,6 +66,9 @@
 	AHCI_IRQ_ON_SG		= (1 << 31),
 	AHCI_CMD_ATAPI		= (1 << 5),
 	AHCI_CMD_WRITE		= (1 << 6),
+	AHCI_CMD_PREFETCH	= (1 << 7),
+	AHCI_CMD_RESET		= (1 << 8),
+	AHCI_CMD_CLR_BUSY	= (1 << 10),
 
 	RX_FIS_D2H_REG		= 0x40,	/* offset of D2H Register FIS data */
 
@@ -85,6 +88,7 @@
 
 	/* HOST_CAP bits */
 	HOST_CAP_64		= (1 << 31), /* PCI DAC (64-bit DMA) support */
+	HOST_CAP_CLO		= (1 << 24), /* Command List Override support */
 
 	/* registers for each SATA port */
 	PORT_LST_ADDR		= 0x00, /* command list DMA addr */
@@ -138,6 +142,7 @@
 	PORT_CMD_LIST_ON	= (1 << 15), /* cmd list DMA engine running */
 	PORT_CMD_FIS_ON		= (1 << 14), /* FIS DMA engine running */
 	PORT_CMD_FIS_RX		= (1 << 4), /* Enable FIS receive DMA engine */
+	PORT_CMD_CLO		= (1 << 3), /* Command list override */
 	PORT_CMD_POWER_ON	= (1 << 2), /* Power up device */
 	PORT_CMD_SPIN_UP	= (1 << 1), /* Spin up device */
 	PORT_CMD_START		= (1 << 0), /* Enable port DMA engine */
@@ -184,9 +189,9 @@
 static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
 static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static int ahci_qc_issue(struct ata_queued_cmd *qc);
+static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
 static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
-static void ahci_phy_reset(struct ata_port *ap);
+static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes);
 static void ahci_irq_clear(struct ata_port *ap);
 static void ahci_eng_timeout(struct ata_port *ap);
 static int ahci_port_start(struct ata_port *ap);
@@ -202,11 +207,11 @@
 	.name			= DRV_NAME,
 	.ioctl			= ata_scsi_ioctl,
 	.queuecommand		= ata_scsi_queuecmd,
+	.eh_timed_out		= ata_scsi_timed_out,
 	.eh_strategy_handler	= ata_scsi_error,
 	.can_queue		= ATA_DEF_QUEUE,
 	.this_id		= ATA_SHT_THIS_ID,
 	.sg_tablesize		= AHCI_MAX_SG,
-	.max_sectors		= ATA_MAX_SECTORS,
 	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
 	.emulated		= ATA_SHT_EMULATED,
 	.use_clustering		= AHCI_USE_CLUSTERING,
@@ -225,7 +230,7 @@
 
 	.tf_read		= ahci_tf_read,
 
-	.phy_reset		= ahci_phy_reset,
+	.probe_reset		= ahci_probe_reset,
 
 	.qc_prep		= ahci_qc_prep,
 	.qc_issue		= ahci_qc_issue,
@@ -247,8 +252,7 @@
 	{
 		.sht		= &ahci_sht,
 		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-				  ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
-				  ATA_FLAG_PIO_DMA,
+				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
 		.pio_mask	= 0x1f, /* pio0-4 */
 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
 		.port_ops	= &ahci_ops,
@@ -450,17 +454,48 @@
 	writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
 }
 
-static void ahci_phy_reset(struct ata_port *ap)
+static int ahci_stop_engine(struct ata_port *ap)
+{
+	void __iomem *mmio = ap->host_set->mmio_base;
+	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+	int work;
+	u32 tmp;
+
+	tmp = readl(port_mmio + PORT_CMD);
+	tmp &= ~PORT_CMD_START;
+	writel(tmp, port_mmio + PORT_CMD);
+
+	/* wait for engine to stop.  TODO: this could be
+	 * as long as 500 msec
+	 */
+	work = 1000;
+	while (work-- > 0) {
+		tmp = readl(port_mmio + PORT_CMD);
+		if ((tmp & PORT_CMD_LIST_ON) == 0)
+			return 0;
+		udelay(10);
+	}
+
+	return -EIO;
+}
+
+static void ahci_start_engine(struct ata_port *ap)
+{
+	void __iomem *mmio = ap->host_set->mmio_base;
+	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+	u32 tmp;
+
+	tmp = readl(port_mmio + PORT_CMD);
+	tmp |= PORT_CMD_START;
+	writel(tmp, port_mmio + PORT_CMD);
+	readl(port_mmio + PORT_CMD); /* flush */
+}
+
+static unsigned int ahci_dev_classify(struct ata_port *ap)
 {
 	void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
 	struct ata_taskfile tf;
-	struct ata_device *dev = &ap->device[0];
-	u32 new_tmp, tmp;
-
-	__sata_phy_reset(ap);
-
-	if (ap->flags & ATA_FLAG_PORT_DISABLED)
-		return;
+	u32 tmp;
 
 	tmp = readl(port_mmio + PORT_SIG);
 	tf.lbah		= (tmp >> 24)	& 0xff;
@@ -468,15 +503,46 @@
 	tf.lbal		= (tmp >> 8)	& 0xff;
 	tf.nsect	= (tmp)		& 0xff;
 
-	dev->class = ata_dev_classify(&tf);
-	if (!ata_dev_present(dev)) {
-		ata_port_disable(ap);
-		return;
-	}
+	return ata_dev_classify(&tf);
+}
+
+static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, u32 opts)
+{
+	pp->cmd_slot[0].opts = cpu_to_le32(opts);
+	pp->cmd_slot[0].status = 0;
+	pp->cmd_slot[0].tbl_addr = cpu_to_le32(pp->cmd_tbl_dma & 0xffffffff);
+	pp->cmd_slot[0].tbl_addr_hi = cpu_to_le32((pp->cmd_tbl_dma >> 16) >> 16);
+}
+
+static int ahci_hardreset(struct ata_port *ap, int verbose, unsigned int *class)
+{
+	int rc;
+
+	DPRINTK("ENTER\n");
+
+	ahci_stop_engine(ap);
+	rc = sata_std_hardreset(ap, verbose, class);
+	ahci_start_engine(ap);
+
+	if (rc == 0)
+		*class = ahci_dev_classify(ap);
+	if (*class == ATA_DEV_UNKNOWN)
+		*class = ATA_DEV_NONE;
+
+	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
+	return rc;
+}
+
+static void ahci_postreset(struct ata_port *ap, unsigned int *class)
+{
+	void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+	u32 new_tmp, tmp;
+
+	ata_std_postreset(ap, class);
 
 	/* Make sure port's ATAPI bit is set appropriately */
 	new_tmp = tmp = readl(port_mmio + PORT_CMD);
-	if (dev->class == ATA_DEV_ATAPI)
+	if (*class == ATA_DEV_ATAPI)
 		new_tmp |= PORT_CMD_ATAPI;
 	else
 		new_tmp &= ~PORT_CMD_ATAPI;
@@ -486,6 +552,12 @@
 	}
 }
 
+static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes)
+{
+	return ata_drive_probe_reset(ap, NULL, NULL, ahci_hardreset,
+				     ahci_postreset, classes);
+}
+
 static u8 ahci_check_status(struct ata_port *ap)
 {
 	void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr;
@@ -533,42 +605,36 @@
 {
 	struct ata_port *ap = qc->ap;
 	struct ahci_port_priv *pp = ap->private_data;
+	int is_atapi = is_atapi_taskfile(&qc->tf);
 	u32 opts;
 	const u32 cmd_fis_len = 5; /* five dwords */
 	unsigned int n_elem;
 
 	/*
-	 * Fill in command slot information (currently only one slot,
-	 * slot 0, is currently since we don't do queueing)
-	 */
-
-	opts = cmd_fis_len;
-	if (qc->tf.flags & ATA_TFLAG_WRITE)
-		opts |= AHCI_CMD_WRITE;
-	if (is_atapi_taskfile(&qc->tf))
-		opts |= AHCI_CMD_ATAPI;
-
-	pp->cmd_slot[0].opts = cpu_to_le32(opts);
-	pp->cmd_slot[0].status = 0;
-	pp->cmd_slot[0].tbl_addr = cpu_to_le32(pp->cmd_tbl_dma & 0xffffffff);
-	pp->cmd_slot[0].tbl_addr_hi = cpu_to_le32((pp->cmd_tbl_dma >> 16) >> 16);
-
-	/*
 	 * Fill in command table information.  First, the header,
 	 * a SATA Register - Host to Device command FIS.
 	 */
 	ata_tf_to_fis(&qc->tf, pp->cmd_tbl, 0);
-	if (opts & AHCI_CMD_ATAPI) {
+	if (is_atapi) {
 		memset(pp->cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
-		memcpy(pp->cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, ap->cdb_len);
+		memcpy(pp->cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb,
+		       qc->dev->cdb_len);
 	}
 
-	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
-		return;
+	n_elem = 0;
+	if (qc->flags & ATA_QCFLAG_DMAMAP)
+		n_elem = ahci_fill_sg(qc);
 
-	n_elem = ahci_fill_sg(qc);
+	/*
+	 * Fill in command slot information.
+	 */
+	opts = cmd_fis_len | n_elem << 16;
+	if (qc->tf.flags & ATA_TFLAG_WRITE)
+		opts |= AHCI_CMD_WRITE;
+	if (is_atapi)
+		opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
 
-	pp->cmd_slot[0].opts |= cpu_to_le32(n_elem << 16);
+	ahci_fill_cmd_slot(pp, opts);
 }
 
 static void ahci_restart_port(struct ata_port *ap, u32 irq_stat)
@@ -576,7 +642,6 @@
 	void __iomem *mmio = ap->host_set->mmio_base;
 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
 	u32 tmp;
-	int work;
 
 	if ((ap->device[0].class != ATA_DEV_ATAPI) ||
 	    ((irq_stat & PORT_IRQ_TF_ERR) == 0))
@@ -592,20 +657,7 @@
 			readl(port_mmio + PORT_SCR_ERR));
 
 	/* stop DMA */
-	tmp = readl(port_mmio + PORT_CMD);
-	tmp &= ~PORT_CMD_START;
-	writel(tmp, port_mmio + PORT_CMD);
-
-	/* wait for engine to stop.  TODO: this could be
-	 * as long as 500 msec
-	 */
-	work = 1000;
-	while (work-- > 0) {
-		tmp = readl(port_mmio + PORT_CMD);
-		if ((tmp & PORT_CMD_LIST_ON) == 0)
-			break;
-		udelay(10);
-	}
+	ahci_stop_engine(ap);
 
 	/* clear SATA phy error, if any */
 	tmp = readl(port_mmio + PORT_SCR_ERR);
@@ -624,10 +676,7 @@
 	}
 
 	/* re-start DMA */
-	tmp = readl(port_mmio + PORT_CMD);
-	tmp |= PORT_CMD_START;
-	writel(tmp, port_mmio + PORT_CMD);
-	readl(port_mmio + PORT_CMD); /* flush */
+	ahci_start_engine(ap);
 }
 
 static void ahci_eng_timeout(struct ata_port *ap)
@@ -642,25 +691,13 @@
 
 	spin_lock_irqsave(&host_set->lock, flags);
 
+	ahci_restart_port(ap, readl(port_mmio + PORT_IRQ_STAT));
 	qc = ata_qc_from_tag(ap, ap->active_tag);
-	if (!qc) {
-		printk(KERN_ERR "ata%u: BUG: timeout without command\n",
-		       ap->id);
-	} else {
-		ahci_restart_port(ap, readl(port_mmio + PORT_IRQ_STAT));
-
-		/* hack alert!  We cannot use the supplied completion
-	 	 * function from inside the ->eh_strategy_handler() thread.
-	 	 * libata is the only user of ->eh_strategy_handler() in
-	 	 * any kernel, so the default scsi_done() assumes it is
-	 	 * not being called from the SCSI EH.
-	 	 */
-		qc->scsidone = scsi_finish_command;
-		qc->err_mask |= AC_ERR_OTHER;
-		ata_qc_complete(qc);
-	}
+	qc->err_mask |= AC_ERR_TIMEOUT;
 
 	spin_unlock_irqrestore(&host_set->lock, flags);
+
+	ata_eh_qc_complete(qc);
 }
 
 static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
@@ -678,7 +715,7 @@
 	ci = readl(port_mmio + PORT_CMD_ISSUE);
 	if (likely((ci & 0x1) == 0)) {
 		if (qc) {
-			assert(qc->err_mask == 0);
+			WARN_ON(qc->err_mask);
 			ata_qc_complete(qc);
 			qc = NULL;
 		}
@@ -697,7 +734,7 @@
 		ahci_restart_port(ap, status);
 
 		if (qc) {
-			qc->err_mask |= AC_ERR_OTHER;
+			qc->err_mask |= err_mask;
 			ata_qc_complete(qc);
 		}
 	}
@@ -770,7 +807,7 @@
 	return IRQ_RETVAL(handled);
 }
 
-static int ahci_qc_issue(struct ata_queued_cmd *qc)
+static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
 	void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c
index fc3ca05..9327b62 100644
--- a/drivers/scsi/ata_piix.c
+++ b/drivers/scsi/ata_piix.c
@@ -101,36 +101,54 @@
 	ICH5_PCS		= 0x92,	/* port control and status */
 	PIIX_SCC		= 0x0A, /* sub-class code register */
 
-	PIIX_FLAG_AHCI		= (1 << 28), /* AHCI possible */
-	PIIX_FLAG_CHECKINTR	= (1 << 29), /* make sure PCI INTx enabled */
-	PIIX_FLAG_COMBINED	= (1 << 30), /* combined mode possible */
+	PIIX_FLAG_IGNORE_PCS	= (1 << 25), /* ignore PCS present bits */
+	PIIX_FLAG_SCR		= (1 << 26), /* SCR available */
+	PIIX_FLAG_AHCI		= (1 << 27), /* AHCI possible */
+	PIIX_FLAG_CHECKINTR	= (1 << 28), /* make sure PCI INTx enabled */
+	PIIX_FLAG_COMBINED	= (1 << 29), /* combined mode possible */
+	/* ICH6/7 use different scheme for map value */
+	PIIX_FLAG_COMBINED_ICH6	= PIIX_FLAG_COMBINED | (1 << 30),
 
 	/* combined mode.  if set, PATA is channel 0.
 	 * if clear, PATA is channel 1.
 	 */
-	PIIX_COMB_PATA_P0	= (1 << 1),
-	PIIX_COMB		= (1 << 2), /* combined mode enabled? */
-
 	PIIX_PORT_ENABLED	= (1 << 0),
 	PIIX_PORT_PRESENT	= (1 << 4),
 
 	PIIX_80C_PRI		= (1 << 5) | (1 << 4),
 	PIIX_80C_SEC		= (1 << 7) | (1 << 6),
 
-	ich5_pata		= 0,
-	ich5_sata		= 1,
-	piix4_pata		= 2,
-	ich6_sata		= 3,
-	ich6_sata_ahci		= 4,
+	/* controller IDs */
+	piix4_pata		= 0,
+	ich5_pata		= 1,
+	ich5_sata		= 2,
+	esb_sata		= 3,
+	ich6_sata		= 4,
+	ich6_sata_ahci		= 5,
+	ich6m_sata_ahci		= 6,
+
+	/* constants for mapping table */
+	P0			= 0,  /* port 0 */
+	P1			= 1,  /* port 1 */
+	P2			= 2,  /* port 2 */
+	P3			= 3,  /* port 3 */
+	IDE			= -1, /* IDE */
+	NA			= -2, /* not avaliable */
+	RV			= -3, /* reserved */
 
 	PIIX_AHCI_DEVICE	= 6,
 };
 
+struct piix_map_db {
+	const u32 mask;
+	const int map[][4];
+};
+
 static int piix_init_one (struct pci_dev *pdev,
 				    const struct pci_device_id *ent);
 
-static void piix_pata_phy_reset(struct ata_port *ap);
-static void piix_sata_phy_reset(struct ata_port *ap);
+static int piix_pata_probe_reset(struct ata_port *ap, unsigned int *classes);
+static int piix_sata_probe_reset(struct ata_port *ap, unsigned int *classes);
 static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev);
 static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev);
 
@@ -147,19 +165,32 @@
 	 * list in drivers/pci/quirks.c.
 	 */
 
+	/* 82801EB (ICH5) */
 	{ 0x8086, 0x24d1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
+	/* 82801EB (ICH5) */
 	{ 0x8086, 0x24df, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
-	{ 0x8086, 0x25a3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
-	{ 0x8086, 0x25b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
+	/* 6300ESB (ICH5 variant with broken PCS present bits) */
+	{ 0x8086, 0x25a3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, esb_sata },
+	/* 6300ESB pretending RAID */
+	{ 0x8086, 0x25b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, esb_sata },
+	/* 82801FB/FW (ICH6/ICH6W) */
 	{ 0x8086, 0x2651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata },
+	/* 82801FR/FRW (ICH6R/ICH6RW) */
 	{ 0x8086, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
-	{ 0x8086, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
+	/* 82801FBM ICH6M (ICH6R with only port 0 and 2 implemented) */
+	{ 0x8086, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6m_sata_ahci },
+	/* 82801GB/GR/GH (ICH7, identical to ICH6) */
 	{ 0x8086, 0x27c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
-	{ 0x8086, 0x27c4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
+	/* 2801GBM/GHM (ICH7M, identical to ICH6M) */
+	{ 0x8086, 0x27c4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6m_sata_ahci },
+	/* Enterprise Southbridge 2 (where's the datasheet?) */
 	{ 0x8086, 0x2680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
+	/* SATA Controller 1 IDE (ICH8, no datasheet yet) */
 	{ 0x8086, 0x2820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
+	/* SATA Controller 2 IDE (ICH8, ditto) */
 	{ 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
-	{ 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
+	/* Mobile SATA Controller IDE (ICH8M, ditto) */
+	{ 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6m_sata_ahci },
 
 	{ }	/* terminate list */
 };
@@ -178,11 +209,11 @@
 	.name			= DRV_NAME,
 	.ioctl			= ata_scsi_ioctl,
 	.queuecommand		= ata_scsi_queuecmd,
+	.eh_timed_out		= ata_scsi_timed_out,
 	.eh_strategy_handler	= ata_scsi_error,
 	.can_queue		= ATA_DEF_QUEUE,
 	.this_id		= ATA_SHT_THIS_ID,
 	.sg_tablesize		= LIBATA_MAX_PRD,
-	.max_sectors		= ATA_MAX_SECTORS,
 	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
 	.emulated		= ATA_SHT_EMULATED,
 	.use_clustering		= ATA_SHT_USE_CLUSTERING,
@@ -205,7 +236,7 @@
 	.exec_command		= ata_exec_command,
 	.dev_select		= ata_std_dev_select,
 
-	.phy_reset		= piix_pata_phy_reset,
+	.probe_reset		= piix_pata_probe_reset,
 
 	.bmdma_setup		= ata_bmdma_setup,
 	.bmdma_start		= ata_bmdma_start,
@@ -233,7 +264,7 @@
 	.exec_command		= ata_exec_command,
 	.dev_select		= ata_std_dev_select,
 
-	.phy_reset		= piix_sata_phy_reset,
+	.probe_reset		= piix_sata_probe_reset,
 
 	.bmdma_setup		= ata_bmdma_setup,
 	.bmdma_start		= ata_bmdma_start,
@@ -252,12 +283,62 @@
 	.host_stop		= ata_host_stop,
 };
 
+static struct piix_map_db ich5_map_db = {
+	.mask = 0x7,
+	.map = {
+		/* PM   PS   SM   SS       MAP  */
+		{  P0,  NA,  P1,  NA }, /* 000b */
+		{  P1,  NA,  P0,  NA }, /* 001b */
+		{  RV,  RV,  RV,  RV },
+		{  RV,  RV,  RV,  RV },
+		{  P0,  P1, IDE, IDE }, /* 100b */
+		{  P1,  P0, IDE, IDE }, /* 101b */
+		{ IDE, IDE,  P0,  P1 }, /* 110b */
+		{ IDE, IDE,  P1,  P0 }, /* 111b */
+	},
+};
+
+static struct piix_map_db ich6_map_db = {
+	.mask = 0x3,
+	.map = {
+		/* PM   PS   SM   SS       MAP */
+		{  P0,  P1,  P2,  P3 }, /* 00b */
+		{ IDE, IDE,  P1,  P3 }, /* 01b */
+		{  P0,  P2, IDE, IDE }, /* 10b */
+		{  RV,  RV,  RV,  RV },
+	},
+};
+
+static struct piix_map_db ich6m_map_db = {
+	.mask = 0x3,
+	.map = {
+		/* PM   PS   SM   SS       MAP */
+		{  P0,  P1,  P2,  P3 }, /* 00b */
+		{  RV,  RV,  RV,  RV },
+		{  P0,  P2, IDE, IDE }, /* 10b */
+		{  RV,  RV,  RV,  RV },
+	},
+};
+
 static struct ata_port_info piix_port_info[] = {
+	/* piix4_pata */
+	{
+		.sht		= &piix_sht,
+		.host_flags	= ATA_FLAG_SLAVE_POSS,
+		.pio_mask	= 0x1f,	/* pio0-4 */
+#if 0
+		.mwdma_mask	= 0x06, /* mwdma1-2 */
+#else
+		.mwdma_mask	= 0x00, /* mwdma broken */
+#endif
+		.udma_mask	= ATA_UDMA_MASK_40C,
+		.port_ops	= &piix_pata_ops,
+	},
+
 	/* ich5_pata */
 	{
 		.sht		= &piix_sht,
-		.host_flags	= ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST |
-				  PIIX_FLAG_CHECKINTR,
+		.host_flags	= ATA_FLAG_SLAVE_POSS | PIIX_FLAG_CHECKINTR,
 		.pio_mask	= 0x1f,	/* pio0-4 */
 #if 0
 		.mwdma_mask	= 0x06, /* mwdma1-2 */
@@ -271,50 +352,63 @@
 	/* ich5_sata */
 	{
 		.sht		= &piix_sht,
-		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_SRST |
-				  PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR,
+		.host_flags	= ATA_FLAG_SATA | PIIX_FLAG_COMBINED |
+				  PIIX_FLAG_CHECKINTR,
 		.pio_mask	= 0x1f,	/* pio0-4 */
 		.mwdma_mask	= 0x07, /* mwdma0-2 */
 		.udma_mask	= 0x7f,	/* udma0-6 */
 		.port_ops	= &piix_sata_ops,
+		.private_data	= &ich5_map_db,
 	},
 
-	/* piix4_pata */
+	/* i6300esb_sata */
 	{
 		.sht		= &piix_sht,
-		.host_flags	= ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+		.host_flags	= ATA_FLAG_SATA | PIIX_FLAG_COMBINED |
+				  PIIX_FLAG_CHECKINTR | PIIX_FLAG_IGNORE_PCS,
 		.pio_mask	= 0x1f,	/* pio0-4 */
-#if 0
-		.mwdma_mask	= 0x06, /* mwdma1-2 */
-#else
-		.mwdma_mask	= 0x00, /* mwdma broken */
-#endif
-		.udma_mask	= ATA_UDMA_MASK_40C,
-		.port_ops	= &piix_pata_ops,
+		.mwdma_mask	= 0x07, /* mwdma0-2 */
+		.udma_mask	= 0x7f,	/* udma0-6 */
+		.port_ops	= &piix_sata_ops,
+		.private_data	= &ich5_map_db,
 	},
 
 	/* ich6_sata */
 	{
 		.sht		= &piix_sht,
-		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_SRST |
-				  PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR |
-				  ATA_FLAG_SLAVE_POSS,
+		.host_flags	= ATA_FLAG_SATA | PIIX_FLAG_COMBINED_ICH6 |
+				  PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR,
 		.pio_mask	= 0x1f,	/* pio0-4 */
 		.mwdma_mask	= 0x07, /* mwdma0-2 */
 		.udma_mask	= 0x7f,	/* udma0-6 */
 		.port_ops	= &piix_sata_ops,
+		.private_data	= &ich6_map_db,
 	},
 
 	/* ich6_sata_ahci */
 	{
 		.sht		= &piix_sht,
-		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_SRST |
-				  PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR |
-				  ATA_FLAG_SLAVE_POSS | PIIX_FLAG_AHCI,
+		.host_flags	= ATA_FLAG_SATA | PIIX_FLAG_COMBINED_ICH6 |
+				  PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR |
+				  PIIX_FLAG_AHCI,
 		.pio_mask	= 0x1f,	/* pio0-4 */
 		.mwdma_mask	= 0x07, /* mwdma0-2 */
 		.udma_mask	= 0x7f,	/* udma0-6 */
 		.port_ops	= &piix_sata_ops,
+		.private_data	= &ich6_map_db,
+	},
+
+	/* ich6m_sata_ahci */
+	{
+		.sht		= &piix_sht,
+		.host_flags	= ATA_FLAG_SATA | PIIX_FLAG_COMBINED_ICH6 |
+				  PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR |
+				  PIIX_FLAG_AHCI,
+		.pio_mask	= 0x1f,	/* pio0-4 */
+		.mwdma_mask	= 0x07, /* mwdma0-2 */
+		.udma_mask	= 0x7f,	/* udma0-6 */
+		.port_ops	= &piix_sata_ops,
+		.private_data	= &ich6m_map_db,
 	},
 };
 
@@ -363,102 +457,123 @@
 }
 
 /**
- *	piix_pata_phy_reset - Probe specified port on PATA host controller
- *	@ap: Port to probe
+ *	piix_pata_probeinit - probeinit for PATA host controller
+ *	@ap: Target port
  *
- *	Probe PATA phy.
+ *	Probeinit including cable detection.
  *
  *	LOCKING:
  *	None (inherited from caller).
  */
+static void piix_pata_probeinit(struct ata_port *ap)
+{
+	piix_pata_cbl_detect(ap);
+	ata_std_probeinit(ap);
+}
 
-static void piix_pata_phy_reset(struct ata_port *ap)
+/**
+ *	piix_pata_probe_reset - Perform reset on PATA port and classify
+ *	@ap: Port to reset
+ *	@classes: Resulting classes of attached devices
+ *
+ *	Reset PATA phy and classify attached devices.
+ *
+ *	LOCKING:
+ *	None (inherited from caller).
+ */
+static int piix_pata_probe_reset(struct ata_port *ap, unsigned int *classes)
 {
 	struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
 
 	if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->hard_port_no])) {
-		ata_port_disable(ap);
 		printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
-		return;
+		return 0;
 	}
 
-	piix_pata_cbl_detect(ap);
-
-	ata_port_probe(ap);
-
-	ata_bus_reset(ap);
+	return ata_drive_probe_reset(ap, piix_pata_probeinit,
+				     ata_std_softreset, NULL,
+				     ata_std_postreset, classes);
 }
 
 /**
  *	piix_sata_probe - Probe PCI device for present SATA devices
  *	@ap: Port associated with the PCI device we wish to probe
  *
- *	Reads SATA PCI device's PCI config register Port Configuration
- *	and Status (PCS) to determine port and device availability.
+ *	Reads and configures SATA PCI device's PCI config register
+ *	Port Configuration and Status (PCS) to determine port and
+ *	device availability.
  *
  *	LOCKING:
  *	None (inherited from caller).
  *
  *	RETURNS:
- *	Non-zero if port is enabled, it may or may not have a device
- *	attached in that case (PRESENT bit would only be set if BIOS probe
- *	was done). Zero is returned if port is disabled.
+ *	Mask of avaliable devices on the port.
  */
-static int piix_sata_probe (struct ata_port *ap)
+static unsigned int piix_sata_probe (struct ata_port *ap)
 {
 	struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
-	int combined = (ap->flags & ATA_FLAG_SLAVE_POSS);
-	int orig_mask, mask, i;
+	const unsigned int *map = ap->host_set->private_data;
+	int base = 2 * ap->hard_port_no;
+	unsigned int present_mask = 0;
+	int port, i;
 	u8 pcs;
 
-	mask = (PIIX_PORT_PRESENT << ap->hard_port_no) |
-	       (PIIX_PORT_ENABLED << ap->hard_port_no);
-
 	pci_read_config_byte(pdev, ICH5_PCS, &pcs);
-	orig_mask = (int) pcs & 0xff;
+	DPRINTK("ata%u: ENTER, pcs=0x%x base=%d\n", ap->id, pcs, base);
 
-	/* TODO: this is vaguely wrong for ICH6 combined mode,
-	 * where only two of the four SATA ports are mapped
-	 * onto a single ATA channel.  It is also vaguely inaccurate
-	 * for ICH5, which has only two ports.  However, this is ok,
-	 * as further device presence detection code will handle
-	 * any false positives produced here.
-	 */
-
-	for (i = 0; i < 4; i++) {
-		mask = (PIIX_PORT_ENABLED << i);
-
-		if ((orig_mask & mask) == mask)
-			if (combined || (i == ap->hard_port_no))
-				return 1;
+	/* enable all ports on this ap and wait for them to settle */
+	for (i = 0; i < 2; i++) {
+		port = map[base + i];
+		if (port >= 0)
+			pcs |= 1 << port;
 	}
 
-	return 0;
+	pci_write_config_byte(pdev, ICH5_PCS, pcs);
+	msleep(100);
+
+	/* let's see which devices are present */
+	pci_read_config_byte(pdev, ICH5_PCS, &pcs);
+
+	for (i = 0; i < 2; i++) {
+		port = map[base + i];
+		if (port < 0)
+			continue;
+		if (ap->flags & PIIX_FLAG_IGNORE_PCS || pcs & 1 << (4 + port))
+			present_mask |= 1 << i;
+		else
+			pcs &= ~(1 << port);
+	}
+
+	/* disable offline ports on non-AHCI controllers */
+	if (!(ap->flags & PIIX_FLAG_AHCI))
+		pci_write_config_byte(pdev, ICH5_PCS, pcs);
+
+	DPRINTK("ata%u: LEAVE, pcs=0x%x present_mask=0x%x\n",
+		ap->id, pcs, present_mask);
+
+	return present_mask;
 }
 
 /**
- *	piix_sata_phy_reset - Probe specified port on SATA host controller
- *	@ap: Port to probe
+ *	piix_sata_probe_reset - Perform reset on SATA port and classify
+ *	@ap: Port to reset
+ *	@classes: Resulting classes of attached devices
  *
- *	Probe SATA phy.
+ *	Reset SATA phy and classify attached devices.
  *
  *	LOCKING:
  *	None (inherited from caller).
  */
-
-static void piix_sata_phy_reset(struct ata_port *ap)
+static int piix_sata_probe_reset(struct ata_port *ap, unsigned int *classes)
 {
 	if (!piix_sata_probe(ap)) {
-		ata_port_disable(ap);
 		printk(KERN_INFO "ata%u: SATA port has no device.\n", ap->id);
-		return;
+		return 0;
 	}
 
-	ap->cbl = ATA_CBL_SATA;
-
-	ata_port_probe(ap);
-
-	ata_bus_reset(ap);
+	return ata_drive_probe_reset(ap, ata_std_probeinit,
+				     ata_std_softreset, NULL,
+				     ata_std_postreset, classes);
 }
 
 /**
@@ -627,6 +742,7 @@
 
 /**
  *	piix_check_450nx_errata	-	Check for problem 450NX setup
+ *	@ata_dev: the PCI device to check
  *	
  *	Check for the present of 450NX errata #19 and errata #25. If
  *	they are found return an error code so we can turn off DMA
@@ -659,6 +775,54 @@
 	return no_piix_dma;
 }		
 
+static void __devinit piix_init_sata_map(struct pci_dev *pdev,
+					 struct ata_port_info *pinfo)
+{
+	struct piix_map_db *map_db = pinfo[0].private_data;
+	const unsigned int *map;
+	int i, invalid_map = 0;
+	u8 map_value;
+
+	pci_read_config_byte(pdev, ICH5_PMR, &map_value);
+
+	map = map_db->map[map_value & map_db->mask];
+
+	dev_printk(KERN_INFO, &pdev->dev, "MAP [");
+	for (i = 0; i < 4; i++) {
+		switch (map[i]) {
+		case RV:
+			invalid_map = 1;
+			printk(" XX");
+			break;
+
+		case NA:
+			printk(" --");
+			break;
+
+		case IDE:
+			WARN_ON((i & 1) || map[i + 1] != IDE);
+			pinfo[i / 2] = piix_port_info[ich5_pata];
+			i++;
+			printk(" IDE IDE");
+			break;
+
+		default:
+			printk(" P%d", map[i]);
+			if (i & 1)
+				pinfo[i / 2].host_flags |= ATA_FLAG_SLAVE_POSS;
+			break;
+		}
+	}
+	printk(" ]\n");
+
+	if (invalid_map)
+		dev_printk(KERN_ERR, &pdev->dev,
+			   "invalid MAP value %u\n", map_value);
+
+	pinfo[0].private_data = (void *)map;
+	pinfo[1].private_data = (void *)map;
+}
+
 /**
  *	piix_init_one - Register PIIX ATA PCI device with kernel services
  *	@pdev: PCI device to register
@@ -677,9 +841,9 @@
 static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	static int printed_version;
-	struct ata_port_info *port_info[2];
-	unsigned int combined = 0;
-	unsigned int pata_chan = 0, sata_chan = 0;
+	struct ata_port_info port_info[2];
+	struct ata_port_info *ppinfo[2] = { &port_info[0], &port_info[1] };
+	unsigned long host_flags;
 
 	if (!printed_version++)
 		dev_printk(KERN_DEBUG, &pdev->dev,
@@ -689,10 +853,12 @@
 	if (!in_module_init)
 		return -ENODEV;
 
-	port_info[0] = &piix_port_info[ent->driver_data];
-	port_info[1] = &piix_port_info[ent->driver_data];
+	port_info[0] = piix_port_info[ent->driver_data];
+	port_info[1] = piix_port_info[ent->driver_data];
 
-	if (port_info[0]->host_flags & PIIX_FLAG_AHCI) {
+	host_flags = port_info[0].host_flags;
+
+	if (host_flags & PIIX_FLAG_AHCI) {
 		u8 tmp;
 		pci_read_config_byte(pdev, PIIX_SCC, &tmp);
 		if (tmp == PIIX_AHCI_DEVICE) {
@@ -702,18 +868,9 @@
 		}
 	}
 
-	if (port_info[0]->host_flags & PIIX_FLAG_COMBINED) {
-		u8 tmp;
-		pci_read_config_byte(pdev, ICH5_PMR, &tmp);
-
-		if (tmp & PIIX_COMB) {
-			combined = 1;
-			if (tmp & PIIX_COMB_PATA_P0)
-				sata_chan = 1;
-			else
-				pata_chan = 1;
-		}
-	}
+	/* Initialize SATA map */
+	if (host_flags & ATA_FLAG_SATA)
+		piix_init_sata_map(pdev, port_info);
 
 	/* On ICH5, some BIOSen disable the interrupt using the
 	 * PCI_COMMAND_INTX_DISABLE bit added in PCI 2.3.
@@ -721,28 +878,19 @@
 	 * MSI is disabled (and it is disabled, as we don't use
 	 * message-signalled interrupts currently).
 	 */
-	if (port_info[0]->host_flags & PIIX_FLAG_CHECKINTR)
+	if (host_flags & PIIX_FLAG_CHECKINTR)
 		pci_intx(pdev, 1);
 
-	if (combined) {
-		port_info[sata_chan] = &piix_port_info[ent->driver_data];
-		port_info[sata_chan]->host_flags |= ATA_FLAG_SLAVE_POSS;
-		port_info[pata_chan] = &piix_port_info[ich5_pata];
-
-		dev_printk(KERN_WARNING, &pdev->dev,
-			   "combined mode detected (p=%u, s=%u)\n",
-			   pata_chan, sata_chan);
-	}
 	if (piix_check_450nx_errata(pdev)) {
 		/* This writes into the master table but it does not
 		   really matter for this errata as we will apply it to
 		   all the PIIX devices on the board */
-		port_info[0]->mwdma_mask = 0;
-		port_info[0]->udma_mask = 0;
-		port_info[1]->mwdma_mask = 0;
-		port_info[1]->udma_mask = 0;
+		port_info[0].mwdma_mask = 0;
+		port_info[0].udma_mask = 0;
+		port_info[1].mwdma_mask = 0;
+		port_info[1].udma_mask = 0;
 	}
-	return ata_pci_init_one(pdev, port_info, 2);
+	return ata_pci_init_one(pdev, ppinfo, 2);
 }
 
 static int __init piix_init(void)
diff --git a/drivers/scsi/libata-bmdma.c b/drivers/scsi/libata-bmdma.c
new file mode 100644
index 0000000..a93336ad
--- /dev/null
+++ b/drivers/scsi/libata-bmdma.c
@@ -0,0 +1,703 @@
+/*
+ *  libata-bmdma.c - helper library for PCI IDE BMDMA
+ *
+ *  Maintained by:  Jeff Garzik <jgarzik@pobox.com>
+ *    		    Please ALWAYS copy linux-ide@vger.kernel.org
+ *		    on emails.
+ *
+ *  Copyright 2003-2006 Red Hat, Inc.  All rights reserved.
+ *  Copyright 2003-2006 Jeff Garzik
+ *
+ *
+ *  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; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *  libata documentation is available via 'make {ps|pdf}docs',
+ *  as Documentation/DocBook/libata.*
+ *
+ *  Hardware documentation available from http://www.t13.org/ and
+ *  http://www.sata-io.org/
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/libata.h>
+
+#include "libata.h"
+
+/**
+ *	ata_tf_load_pio - send taskfile registers to host controller
+ *	@ap: Port to which output is sent
+ *	@tf: ATA taskfile register set
+ *
+ *	Outputs ATA taskfile to standard ATA host controller.
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+
+static void ata_tf_load_pio(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+	unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+	if (tf->ctl != ap->last_ctl) {
+		outb(tf->ctl, ioaddr->ctl_addr);
+		ap->last_ctl = tf->ctl;
+		ata_wait_idle(ap);
+	}
+
+	if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+		outb(tf->hob_feature, ioaddr->feature_addr);
+		outb(tf->hob_nsect, ioaddr->nsect_addr);
+		outb(tf->hob_lbal, ioaddr->lbal_addr);
+		outb(tf->hob_lbam, ioaddr->lbam_addr);
+		outb(tf->hob_lbah, ioaddr->lbah_addr);
+		VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
+			tf->hob_feature,
+			tf->hob_nsect,
+			tf->hob_lbal,
+			tf->hob_lbam,
+			tf->hob_lbah);
+	}
+
+	if (is_addr) {
+		outb(tf->feature, ioaddr->feature_addr);
+		outb(tf->nsect, ioaddr->nsect_addr);
+		outb(tf->lbal, ioaddr->lbal_addr);
+		outb(tf->lbam, ioaddr->lbam_addr);
+		outb(tf->lbah, ioaddr->lbah_addr);
+		VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
+			tf->feature,
+			tf->nsect,
+			tf->lbal,
+			tf->lbam,
+			tf->lbah);
+	}
+
+	if (tf->flags & ATA_TFLAG_DEVICE) {
+		outb(tf->device, ioaddr->device_addr);
+		VPRINTK("device 0x%X\n", tf->device);
+	}
+
+	ata_wait_idle(ap);
+}
+
+/**
+ *	ata_tf_load_mmio - send taskfile registers to host controller
+ *	@ap: Port to which output is sent
+ *	@tf: ATA taskfile register set
+ *
+ *	Outputs ATA taskfile to standard ATA host controller using MMIO.
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+
+static void ata_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+	unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+	if (tf->ctl != ap->last_ctl) {
+		writeb(tf->ctl, (void __iomem *) ap->ioaddr.ctl_addr);
+		ap->last_ctl = tf->ctl;
+		ata_wait_idle(ap);
+	}
+
+	if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+		writeb(tf->hob_feature, (void __iomem *) ioaddr->feature_addr);
+		writeb(tf->hob_nsect, (void __iomem *) ioaddr->nsect_addr);
+		writeb(tf->hob_lbal, (void __iomem *) ioaddr->lbal_addr);
+		writeb(tf->hob_lbam, (void __iomem *) ioaddr->lbam_addr);
+		writeb(tf->hob_lbah, (void __iomem *) ioaddr->lbah_addr);
+		VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
+			tf->hob_feature,
+			tf->hob_nsect,
+			tf->hob_lbal,
+			tf->hob_lbam,
+			tf->hob_lbah);
+	}
+
+	if (is_addr) {
+		writeb(tf->feature, (void __iomem *) ioaddr->feature_addr);
+		writeb(tf->nsect, (void __iomem *) ioaddr->nsect_addr);
+		writeb(tf->lbal, (void __iomem *) ioaddr->lbal_addr);
+		writeb(tf->lbam, (void __iomem *) ioaddr->lbam_addr);
+		writeb(tf->lbah, (void __iomem *) ioaddr->lbah_addr);
+		VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
+			tf->feature,
+			tf->nsect,
+			tf->lbal,
+			tf->lbam,
+			tf->lbah);
+	}
+
+	if (tf->flags & ATA_TFLAG_DEVICE) {
+		writeb(tf->device, (void __iomem *) ioaddr->device_addr);
+		VPRINTK("device 0x%X\n", tf->device);
+	}
+
+	ata_wait_idle(ap);
+}
+
+
+/**
+ *	ata_tf_load - send taskfile registers to host controller
+ *	@ap: Port to which output is sent
+ *	@tf: ATA taskfile register set
+ *
+ *	Outputs ATA taskfile to standard ATA host controller using MMIO
+ *	or PIO as indicated by the ATA_FLAG_MMIO flag.
+ *	Writes the control, feature, nsect, lbal, lbam, and lbah registers.
+ *	Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect,
+ *	hob_lbal, hob_lbam, and hob_lbah.
+ *
+ *	This function waits for idle (!BUSY and !DRQ) after writing
+ *	registers.  If the control register has a new value, this
+ *	function also waits for idle after writing control and before
+ *	writing the remaining registers.
+ *
+ *	May be used as the tf_load() entry in ata_port_operations.
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+	if (ap->flags & ATA_FLAG_MMIO)
+		ata_tf_load_mmio(ap, tf);
+	else
+		ata_tf_load_pio(ap, tf);
+}
+
+/**
+ *	ata_exec_command_pio - issue ATA command to host controller
+ *	@ap: port to which command is being issued
+ *	@tf: ATA taskfile register set
+ *
+ *	Issues PIO write to ATA command register, with proper
+ *	synchronization with interrupt handler / other threads.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+static void ata_exec_command_pio(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+	DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
+
+       	outb(tf->command, ap->ioaddr.command_addr);
+	ata_pause(ap);
+}
+
+
+/**
+ *	ata_exec_command_mmio - issue ATA command to host controller
+ *	@ap: port to which command is being issued
+ *	@tf: ATA taskfile register set
+ *
+ *	Issues MMIO write to ATA command register, with proper
+ *	synchronization with interrupt handler / other threads.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+static void ata_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+	DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
+
+       	writeb(tf->command, (void __iomem *) ap->ioaddr.command_addr);
+	ata_pause(ap);
+}
+
+
+/**
+ *	ata_exec_command - issue ATA command to host controller
+ *	@ap: port to which command is being issued
+ *	@tf: ATA taskfile register set
+ *
+ *	Issues PIO/MMIO write to ATA command register, with proper
+ *	synchronization with interrupt handler / other threads.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+	if (ap->flags & ATA_FLAG_MMIO)
+		ata_exec_command_mmio(ap, tf);
+	else
+		ata_exec_command_pio(ap, tf);
+}
+
+/**
+ *	ata_tf_read_pio - input device's ATA taskfile shadow registers
+ *	@ap: Port from which input is read
+ *	@tf: ATA taskfile register set for storing input
+ *
+ *	Reads ATA taskfile registers for currently-selected device
+ *	into @tf.
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+
+static void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+
+	tf->command = ata_check_status(ap);
+	tf->feature = inb(ioaddr->error_addr);
+	tf->nsect = inb(ioaddr->nsect_addr);
+	tf->lbal = inb(ioaddr->lbal_addr);
+	tf->lbam = inb(ioaddr->lbam_addr);
+	tf->lbah = inb(ioaddr->lbah_addr);
+	tf->device = inb(ioaddr->device_addr);
+
+	if (tf->flags & ATA_TFLAG_LBA48) {
+		outb(tf->ctl | ATA_HOB, ioaddr->ctl_addr);
+		tf->hob_feature = inb(ioaddr->error_addr);
+		tf->hob_nsect = inb(ioaddr->nsect_addr);
+		tf->hob_lbal = inb(ioaddr->lbal_addr);
+		tf->hob_lbam = inb(ioaddr->lbam_addr);
+		tf->hob_lbah = inb(ioaddr->lbah_addr);
+	}
+}
+
+/**
+ *	ata_tf_read_mmio - input device's ATA taskfile shadow registers
+ *	@ap: Port from which input is read
+ *	@tf: ATA taskfile register set for storing input
+ *
+ *	Reads ATA taskfile registers for currently-selected device
+ *	into @tf via MMIO.
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+
+static void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+
+	tf->command = ata_check_status(ap);
+	tf->feature = readb((void __iomem *)ioaddr->error_addr);
+	tf->nsect = readb((void __iomem *)ioaddr->nsect_addr);
+	tf->lbal = readb((void __iomem *)ioaddr->lbal_addr);
+	tf->lbam = readb((void __iomem *)ioaddr->lbam_addr);
+	tf->lbah = readb((void __iomem *)ioaddr->lbah_addr);
+	tf->device = readb((void __iomem *)ioaddr->device_addr);
+
+	if (tf->flags & ATA_TFLAG_LBA48) {
+		writeb(tf->ctl | ATA_HOB, (void __iomem *) ap->ioaddr.ctl_addr);
+		tf->hob_feature = readb((void __iomem *)ioaddr->error_addr);
+		tf->hob_nsect = readb((void __iomem *)ioaddr->nsect_addr);
+		tf->hob_lbal = readb((void __iomem *)ioaddr->lbal_addr);
+		tf->hob_lbam = readb((void __iomem *)ioaddr->lbam_addr);
+		tf->hob_lbah = readb((void __iomem *)ioaddr->lbah_addr);
+	}
+}
+
+
+/**
+ *	ata_tf_read - input device's ATA taskfile shadow registers
+ *	@ap: Port from which input is read
+ *	@tf: ATA taskfile register set for storing input
+ *
+ *	Reads ATA taskfile registers for currently-selected device
+ *	into @tf.
+ *
+ *	Reads nsect, lbal, lbam, lbah, and device.  If ATA_TFLAG_LBA48
+ *	is set, also reads the hob registers.
+ *
+ *	May be used as the tf_read() entry in ata_port_operations.
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	if (ap->flags & ATA_FLAG_MMIO)
+		ata_tf_read_mmio(ap, tf);
+	else
+		ata_tf_read_pio(ap, tf);
+}
+
+/**
+ *	ata_check_status_pio - Read device status reg & clear interrupt
+ *	@ap: port where the device is
+ *
+ *	Reads ATA taskfile status register for currently-selected device
+ *	and return its value. This also clears pending interrupts
+ *      from this device
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+static u8 ata_check_status_pio(struct ata_port *ap)
+{
+	return inb(ap->ioaddr.status_addr);
+}
+
+/**
+ *	ata_check_status_mmio - Read device status reg & clear interrupt
+ *	@ap: port where the device is
+ *
+ *	Reads ATA taskfile status register for currently-selected device
+ *	via MMIO and return its value. This also clears pending interrupts
+ *      from this device
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+static u8 ata_check_status_mmio(struct ata_port *ap)
+{
+       	return readb((void __iomem *) ap->ioaddr.status_addr);
+}
+
+
+/**
+ *	ata_check_status - Read device status reg & clear interrupt
+ *	@ap: port where the device is
+ *
+ *	Reads ATA taskfile status register for currently-selected device
+ *	and return its value. This also clears pending interrupts
+ *      from this device
+ *
+ *	May be used as the check_status() entry in ata_port_operations.
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+u8 ata_check_status(struct ata_port *ap)
+{
+	if (ap->flags & ATA_FLAG_MMIO)
+		return ata_check_status_mmio(ap);
+	return ata_check_status_pio(ap);
+}
+
+
+/**
+ *	ata_altstatus - Read device alternate status reg
+ *	@ap: port where the device is
+ *
+ *	Reads ATA taskfile alternate status register for
+ *	currently-selected device and return its value.
+ *
+ *	Note: may NOT be used as the check_altstatus() entry in
+ *	ata_port_operations.
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+u8 ata_altstatus(struct ata_port *ap)
+{
+	if (ap->ops->check_altstatus)
+		return ap->ops->check_altstatus(ap);
+
+	if (ap->flags & ATA_FLAG_MMIO)
+		return readb((void __iomem *)ap->ioaddr.altstatus_addr);
+	return inb(ap->ioaddr.altstatus_addr);
+}
+
+#ifdef CONFIG_PCI
+static struct ata_probe_ent *
+ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port)
+{
+	struct ata_probe_ent *probe_ent;
+
+	probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
+	if (!probe_ent) {
+		printk(KERN_ERR DRV_NAME "(%s): out of memory\n",
+		       kobject_name(&(dev->kobj)));
+		return NULL;
+	}
+
+	INIT_LIST_HEAD(&probe_ent->node);
+	probe_ent->dev = dev;
+
+	probe_ent->sht = port->sht;
+	probe_ent->host_flags = port->host_flags;
+	probe_ent->pio_mask = port->pio_mask;
+	probe_ent->mwdma_mask = port->mwdma_mask;
+	probe_ent->udma_mask = port->udma_mask;
+	probe_ent->port_ops = port->port_ops;
+
+	return probe_ent;
+}
+
+
+/**
+ *	ata_pci_init_native_mode - Initialize native-mode driver
+ *	@pdev:  pci device to be initialized
+ *	@port:  array[2] of pointers to port info structures.
+ *	@ports: bitmap of ports present
+ *
+ *	Utility function which allocates and initializes an
+ *	ata_probe_ent structure for a standard dual-port
+ *	PIO-based IDE controller.  The returned ata_probe_ent
+ *	structure can be passed to ata_device_add().  The returned
+ *	ata_probe_ent structure should then be freed with kfree().
+ *
+ *	The caller need only pass the address of the primary port, the
+ *	secondary will be deduced automatically. If the device has non
+ *	standard secondary port mappings this function can be called twice,
+ *	once for each interface.
+ */
+
+struct ata_probe_ent *
+ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int ports)
+{
+	struct ata_probe_ent *probe_ent =
+		ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
+	int p = 0;
+
+	if (!probe_ent)
+		return NULL;
+
+	probe_ent->irq = pdev->irq;
+	probe_ent->irq_flags = SA_SHIRQ;
+	probe_ent->private_data = port[0]->private_data;
+
+	if (ports & ATA_PORT_PRIMARY) {
+		probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 0);
+		probe_ent->port[p].altstatus_addr =
+		probe_ent->port[p].ctl_addr =
+			pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS;
+		probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4);
+		ata_std_ports(&probe_ent->port[p]);
+		p++;
+	}
+
+	if (ports & ATA_PORT_SECONDARY) {
+		probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 2);
+		probe_ent->port[p].altstatus_addr =
+		probe_ent->port[p].ctl_addr =
+			pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS;
+		probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4) + 8;
+		ata_std_ports(&probe_ent->port[p]);
+		p++;
+	}
+
+	probe_ent->n_ports = p;
+	return probe_ent;
+}
+
+
+static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
+				struct ata_port_info *port, int port_num)
+{
+	struct ata_probe_ent *probe_ent;
+
+	probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port);
+	if (!probe_ent)
+		return NULL;
+
+	probe_ent->legacy_mode = 1;
+	probe_ent->n_ports = 1;
+	probe_ent->hard_port_no = port_num;
+	probe_ent->private_data = port->private_data;
+
+	switch(port_num)
+	{
+		case 0:
+			probe_ent->irq = 14;
+			probe_ent->port[0].cmd_addr = 0x1f0;
+			probe_ent->port[0].altstatus_addr =
+			probe_ent->port[0].ctl_addr = 0x3f6;
+			break;
+		case 1:
+			probe_ent->irq = 15;
+			probe_ent->port[0].cmd_addr = 0x170;
+			probe_ent->port[0].altstatus_addr =
+			probe_ent->port[0].ctl_addr = 0x376;
+			break;
+	}
+
+	probe_ent->port[0].bmdma_addr =
+		pci_resource_start(pdev, 4) + 8 * port_num;
+	ata_std_ports(&probe_ent->port[0]);
+
+	return probe_ent;
+}
+
+
+/**
+ *	ata_pci_init_one - Initialize/register PCI IDE host controller
+ *	@pdev: Controller to be initialized
+ *	@port_info: Information from low-level host driver
+ *	@n_ports: Number of ports attached to host controller
+ *
+ *	This is a helper function which can be called from a driver's
+ *	xxx_init_one() probe function if the hardware uses traditional
+ *	IDE taskfile registers.
+ *
+ *	This function calls pci_enable_device(), reserves its register
+ *	regions, sets the dma mask, enables bus master mode, and calls
+ *	ata_device_add()
+ *
+ *	LOCKING:
+ *	Inherited from PCI layer (may sleep).
+ *
+ *	RETURNS:
+ *	Zero on success, negative on errno-based value on error.
+ */
+
+int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
+		      unsigned int n_ports)
+{
+	struct ata_probe_ent *probe_ent = NULL, *probe_ent2 = NULL;
+	struct ata_port_info *port[2];
+	u8 tmp8, mask;
+	unsigned int legacy_mode = 0;
+	int disable_dev_on_err = 1;
+	int rc;
+
+	DPRINTK("ENTER\n");
+
+	port[0] = port_info[0];
+	if (n_ports > 1)
+		port[1] = port_info[1];
+	else
+		port[1] = port[0];
+
+	if ((port[0]->host_flags & ATA_FLAG_NO_LEGACY) == 0
+	    && (pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
+		/* TODO: What if one channel is in native mode ... */
+		pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8);
+		mask = (1 << 2) | (1 << 0);
+		if ((tmp8 & mask) != mask)
+			legacy_mode = (1 << 3);
+	}
+
+	/* FIXME... */
+	if ((!legacy_mode) && (n_ports > 2)) {
+		printk(KERN_ERR "ata: BUG: native mode, n_ports > 2\n");
+		n_ports = 2;
+		/* For now */
+	}
+
+	/* FIXME: Really for ATA it isn't safe because the device may be
+	   multi-purpose and we want to leave it alone if it was already
+	   enabled. Secondly for shared use as Arjan says we want refcounting
+
+	   Checking dev->is_enabled is insufficient as this is not set at
+	   boot for the primary video which is BIOS enabled
+         */
+
+	rc = pci_enable_device(pdev);
+	if (rc)
+		return rc;
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc) {
+		disable_dev_on_err = 0;
+		goto err_out;
+	}
+
+	/* FIXME: Should use platform specific mappers for legacy port ranges */
+	if (legacy_mode) {
+		if (!request_region(0x1f0, 8, "libata")) {
+			struct resource *conflict, res;
+			res.start = 0x1f0;
+			res.end = 0x1f0 + 8 - 1;
+			conflict = ____request_resource(&ioport_resource, &res);
+			if (!strcmp(conflict->name, "libata"))
+				legacy_mode |= (1 << 0);
+			else {
+				disable_dev_on_err = 0;
+				printk(KERN_WARNING "ata: 0x1f0 IDE port busy\n");
+			}
+		} else
+			legacy_mode |= (1 << 0);
+
+		if (!request_region(0x170, 8, "libata")) {
+			struct resource *conflict, res;
+			res.start = 0x170;
+			res.end = 0x170 + 8 - 1;
+			conflict = ____request_resource(&ioport_resource, &res);
+			if (!strcmp(conflict->name, "libata"))
+				legacy_mode |= (1 << 1);
+			else {
+				disable_dev_on_err = 0;
+				printk(KERN_WARNING "ata: 0x170 IDE port busy\n");
+			}
+		} else
+			legacy_mode |= (1 << 1);
+	}
+
+	/* we have legacy mode, but all ports are unavailable */
+	if (legacy_mode == (1 << 3)) {
+		rc = -EBUSY;
+		goto err_out_regions;
+	}
+
+	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+
+	if (legacy_mode) {
+		if (legacy_mode & (1 << 0))
+			probe_ent = ata_pci_init_legacy_port(pdev, port[0], 0);
+		if (legacy_mode & (1 << 1))
+			probe_ent2 = ata_pci_init_legacy_port(pdev, port[1], 1);
+	} else {
+		if (n_ports == 2)
+			probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
+		else
+			probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY);
+	}
+	if (!probe_ent && !probe_ent2) {
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+
+	pci_set_master(pdev);
+
+	/* FIXME: check ata_device_add return */
+	if (legacy_mode) {
+		if (legacy_mode & (1 << 0))
+			ata_device_add(probe_ent);
+		if (legacy_mode & (1 << 1))
+			ata_device_add(probe_ent2);
+	} else
+		ata_device_add(probe_ent);
+
+	kfree(probe_ent);
+	kfree(probe_ent2);
+
+	return 0;
+
+err_out_regions:
+	if (legacy_mode & (1 << 0))
+		release_region(0x1f0, 8);
+	if (legacy_mode & (1 << 1))
+		release_region(0x170, 8);
+	pci_release_regions(pdev);
+err_out:
+	if (disable_dev_on_err)
+		pci_disable_device(pdev);
+	return rc;
+}
+
+#endif /* CONFIG_PCI */
+
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 4f91b0d..714b42b 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -61,24 +61,17 @@
 
 #include "libata.h"
 
-static unsigned int ata_busy_sleep (struct ata_port *ap,
-				    unsigned long tmout_pat,
-			    	    unsigned long tmout);
-static void ata_dev_reread_id(struct ata_port *ap, struct ata_device *dev);
-static void ata_dev_init_params(struct ata_port *ap, struct ata_device *dev);
+static unsigned int ata_dev_init_params(struct ata_port *ap,
+					struct ata_device *dev);
 static void ata_set_mode(struct ata_port *ap);
 static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev);
-static unsigned int ata_get_mode_mask(const struct ata_port *ap, int shift);
-static int fgb(u32 bitmap);
-static int ata_choose_xfer_mode(const struct ata_port *ap,
-				u8 *xfer_mode_out,
-				unsigned int *xfer_shift_out);
-static void __ata_qc_complete(struct ata_queued_cmd *qc);
+static unsigned int ata_dev_xfermask(struct ata_port *ap,
+				     struct ata_device *dev);
 
 static unsigned int ata_unique_id = 1;
 static struct workqueue_struct *ata_wq;
 
-int atapi_enabled = 0;
+int atapi_enabled = 1;
 module_param(atapi_enabled, int, 0444);
 MODULE_PARM_DESC(atapi_enabled, "Enable discovery of ATAPI devices (0=off, 1=on)");
 
@@ -91,403 +84,6 @@
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 
-/**
- *	ata_tf_load_pio - send taskfile registers to host controller
- *	@ap: Port to which output is sent
- *	@tf: ATA taskfile register set
- *
- *	Outputs ATA taskfile to standard ATA host controller.
- *
- *	LOCKING:
- *	Inherited from caller.
- */
-
-static void ata_tf_load_pio(struct ata_port *ap, const struct ata_taskfile *tf)
-{
-	struct ata_ioports *ioaddr = &ap->ioaddr;
-	unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
-
-	if (tf->ctl != ap->last_ctl) {
-		outb(tf->ctl, ioaddr->ctl_addr);
-		ap->last_ctl = tf->ctl;
-		ata_wait_idle(ap);
-	}
-
-	if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
-		outb(tf->hob_feature, ioaddr->feature_addr);
-		outb(tf->hob_nsect, ioaddr->nsect_addr);
-		outb(tf->hob_lbal, ioaddr->lbal_addr);
-		outb(tf->hob_lbam, ioaddr->lbam_addr);
-		outb(tf->hob_lbah, ioaddr->lbah_addr);
-		VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
-			tf->hob_feature,
-			tf->hob_nsect,
-			tf->hob_lbal,
-			tf->hob_lbam,
-			tf->hob_lbah);
-	}
-
-	if (is_addr) {
-		outb(tf->feature, ioaddr->feature_addr);
-		outb(tf->nsect, ioaddr->nsect_addr);
-		outb(tf->lbal, ioaddr->lbal_addr);
-		outb(tf->lbam, ioaddr->lbam_addr);
-		outb(tf->lbah, ioaddr->lbah_addr);
-		VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
-			tf->feature,
-			tf->nsect,
-			tf->lbal,
-			tf->lbam,
-			tf->lbah);
-	}
-
-	if (tf->flags & ATA_TFLAG_DEVICE) {
-		outb(tf->device, ioaddr->device_addr);
-		VPRINTK("device 0x%X\n", tf->device);
-	}
-
-	ata_wait_idle(ap);
-}
-
-/**
- *	ata_tf_load_mmio - send taskfile registers to host controller
- *	@ap: Port to which output is sent
- *	@tf: ATA taskfile register set
- *
- *	Outputs ATA taskfile to standard ATA host controller using MMIO.
- *
- *	LOCKING:
- *	Inherited from caller.
- */
-
-static void ata_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
-{
-	struct ata_ioports *ioaddr = &ap->ioaddr;
-	unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
-
-	if (tf->ctl != ap->last_ctl) {
-		writeb(tf->ctl, (void __iomem *) ap->ioaddr.ctl_addr);
-		ap->last_ctl = tf->ctl;
-		ata_wait_idle(ap);
-	}
-
-	if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
-		writeb(tf->hob_feature, (void __iomem *) ioaddr->feature_addr);
-		writeb(tf->hob_nsect, (void __iomem *) ioaddr->nsect_addr);
-		writeb(tf->hob_lbal, (void __iomem *) ioaddr->lbal_addr);
-		writeb(tf->hob_lbam, (void __iomem *) ioaddr->lbam_addr);
-		writeb(tf->hob_lbah, (void __iomem *) ioaddr->lbah_addr);
-		VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
-			tf->hob_feature,
-			tf->hob_nsect,
-			tf->hob_lbal,
-			tf->hob_lbam,
-			tf->hob_lbah);
-	}
-
-	if (is_addr) {
-		writeb(tf->feature, (void __iomem *) ioaddr->feature_addr);
-		writeb(tf->nsect, (void __iomem *) ioaddr->nsect_addr);
-		writeb(tf->lbal, (void __iomem *) ioaddr->lbal_addr);
-		writeb(tf->lbam, (void __iomem *) ioaddr->lbam_addr);
-		writeb(tf->lbah, (void __iomem *) ioaddr->lbah_addr);
-		VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
-			tf->feature,
-			tf->nsect,
-			tf->lbal,
-			tf->lbam,
-			tf->lbah);
-	}
-
-	if (tf->flags & ATA_TFLAG_DEVICE) {
-		writeb(tf->device, (void __iomem *) ioaddr->device_addr);
-		VPRINTK("device 0x%X\n", tf->device);
-	}
-
-	ata_wait_idle(ap);
-}
-
-
-/**
- *	ata_tf_load - send taskfile registers to host controller
- *	@ap: Port to which output is sent
- *	@tf: ATA taskfile register set
- *
- *	Outputs ATA taskfile to standard ATA host controller using MMIO
- *	or PIO as indicated by the ATA_FLAG_MMIO flag.
- *	Writes the control, feature, nsect, lbal, lbam, and lbah registers.
- *	Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect,
- *	hob_lbal, hob_lbam, and hob_lbah.
- *
- *	This function waits for idle (!BUSY and !DRQ) after writing
- *	registers.  If the control register has a new value, this
- *	function also waits for idle after writing control and before
- *	writing the remaining registers.
- *
- *	May be used as the tf_load() entry in ata_port_operations.
- *
- *	LOCKING:
- *	Inherited from caller.
- */
-void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
-{
-	if (ap->flags & ATA_FLAG_MMIO)
-		ata_tf_load_mmio(ap, tf);
-	else
-		ata_tf_load_pio(ap, tf);
-}
-
-/**
- *	ata_exec_command_pio - issue ATA command to host controller
- *	@ap: port to which command is being issued
- *	@tf: ATA taskfile register set
- *
- *	Issues PIO write to ATA command register, with proper
- *	synchronization with interrupt handler / other threads.
- *
- *	LOCKING:
- *	spin_lock_irqsave(host_set lock)
- */
-
-static void ata_exec_command_pio(struct ata_port *ap, const struct ata_taskfile *tf)
-{
-	DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
-
-       	outb(tf->command, ap->ioaddr.command_addr);
-	ata_pause(ap);
-}
-
-
-/**
- *	ata_exec_command_mmio - issue ATA command to host controller
- *	@ap: port to which command is being issued
- *	@tf: ATA taskfile register set
- *
- *	Issues MMIO write to ATA command register, with proper
- *	synchronization with interrupt handler / other threads.
- *
- *	LOCKING:
- *	spin_lock_irqsave(host_set lock)
- */
-
-static void ata_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
-{
-	DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
-
-       	writeb(tf->command, (void __iomem *) ap->ioaddr.command_addr);
-	ata_pause(ap);
-}
-
-
-/**
- *	ata_exec_command - issue ATA command to host controller
- *	@ap: port to which command is being issued
- *	@tf: ATA taskfile register set
- *
- *	Issues PIO/MMIO write to ATA command register, with proper
- *	synchronization with interrupt handler / other threads.
- *
- *	LOCKING:
- *	spin_lock_irqsave(host_set lock)
- */
-void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
-{
-	if (ap->flags & ATA_FLAG_MMIO)
-		ata_exec_command_mmio(ap, tf);
-	else
-		ata_exec_command_pio(ap, tf);
-}
-
-/**
- *	ata_tf_to_host - issue ATA taskfile to host controller
- *	@ap: port to which command is being issued
- *	@tf: ATA taskfile register set
- *
- *	Issues ATA taskfile register set to ATA host controller,
- *	with proper synchronization with interrupt handler and
- *	other threads.
- *
- *	LOCKING:
- *	spin_lock_irqsave(host_set lock)
- */
-
-static inline void ata_tf_to_host(struct ata_port *ap,
-				  const struct ata_taskfile *tf)
-{
-	ap->ops->tf_load(ap, tf);
-	ap->ops->exec_command(ap, tf);
-}
-
-/**
- *	ata_tf_read_pio - input device's ATA taskfile shadow registers
- *	@ap: Port from which input is read
- *	@tf: ATA taskfile register set for storing input
- *
- *	Reads ATA taskfile registers for currently-selected device
- *	into @tf.
- *
- *	LOCKING:
- *	Inherited from caller.
- */
-
-static void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf)
-{
-	struct ata_ioports *ioaddr = &ap->ioaddr;
-
-	tf->command = ata_check_status(ap);
-	tf->feature = inb(ioaddr->error_addr);
-	tf->nsect = inb(ioaddr->nsect_addr);
-	tf->lbal = inb(ioaddr->lbal_addr);
-	tf->lbam = inb(ioaddr->lbam_addr);
-	tf->lbah = inb(ioaddr->lbah_addr);
-	tf->device = inb(ioaddr->device_addr);
-
-	if (tf->flags & ATA_TFLAG_LBA48) {
-		outb(tf->ctl | ATA_HOB, ioaddr->ctl_addr);
-		tf->hob_feature = inb(ioaddr->error_addr);
-		tf->hob_nsect = inb(ioaddr->nsect_addr);
-		tf->hob_lbal = inb(ioaddr->lbal_addr);
-		tf->hob_lbam = inb(ioaddr->lbam_addr);
-		tf->hob_lbah = inb(ioaddr->lbah_addr);
-	}
-}
-
-/**
- *	ata_tf_read_mmio - input device's ATA taskfile shadow registers
- *	@ap: Port from which input is read
- *	@tf: ATA taskfile register set for storing input
- *
- *	Reads ATA taskfile registers for currently-selected device
- *	into @tf via MMIO.
- *
- *	LOCKING:
- *	Inherited from caller.
- */
-
-static void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf)
-{
-	struct ata_ioports *ioaddr = &ap->ioaddr;
-
-	tf->command = ata_check_status(ap);
-	tf->feature = readb((void __iomem *)ioaddr->error_addr);
-	tf->nsect = readb((void __iomem *)ioaddr->nsect_addr);
-	tf->lbal = readb((void __iomem *)ioaddr->lbal_addr);
-	tf->lbam = readb((void __iomem *)ioaddr->lbam_addr);
-	tf->lbah = readb((void __iomem *)ioaddr->lbah_addr);
-	tf->device = readb((void __iomem *)ioaddr->device_addr);
-
-	if (tf->flags & ATA_TFLAG_LBA48) {
-		writeb(tf->ctl | ATA_HOB, (void __iomem *) ap->ioaddr.ctl_addr);
-		tf->hob_feature = readb((void __iomem *)ioaddr->error_addr);
-		tf->hob_nsect = readb((void __iomem *)ioaddr->nsect_addr);
-		tf->hob_lbal = readb((void __iomem *)ioaddr->lbal_addr);
-		tf->hob_lbam = readb((void __iomem *)ioaddr->lbam_addr);
-		tf->hob_lbah = readb((void __iomem *)ioaddr->lbah_addr);
-	}
-}
-
-
-/**
- *	ata_tf_read - input device's ATA taskfile shadow registers
- *	@ap: Port from which input is read
- *	@tf: ATA taskfile register set for storing input
- *
- *	Reads ATA taskfile registers for currently-selected device
- *	into @tf.
- *
- *	Reads nsect, lbal, lbam, lbah, and device.  If ATA_TFLAG_LBA48
- *	is set, also reads the hob registers.
- *
- *	May be used as the tf_read() entry in ata_port_operations.
- *
- *	LOCKING:
- *	Inherited from caller.
- */
-void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
-{
-	if (ap->flags & ATA_FLAG_MMIO)
-		ata_tf_read_mmio(ap, tf);
-	else
-		ata_tf_read_pio(ap, tf);
-}
-
-/**
- *	ata_check_status_pio - Read device status reg & clear interrupt
- *	@ap: port where the device is
- *
- *	Reads ATA taskfile status register for currently-selected device
- *	and return its value. This also clears pending interrupts
- *      from this device
- *
- *	LOCKING:
- *	Inherited from caller.
- */
-static u8 ata_check_status_pio(struct ata_port *ap)
-{
-	return inb(ap->ioaddr.status_addr);
-}
-
-/**
- *	ata_check_status_mmio - Read device status reg & clear interrupt
- *	@ap: port where the device is
- *
- *	Reads ATA taskfile status register for currently-selected device
- *	via MMIO and return its value. This also clears pending interrupts
- *      from this device
- *
- *	LOCKING:
- *	Inherited from caller.
- */
-static u8 ata_check_status_mmio(struct ata_port *ap)
-{
-       	return readb((void __iomem *) ap->ioaddr.status_addr);
-}
-
-
-/**
- *	ata_check_status - Read device status reg & clear interrupt
- *	@ap: port where the device is
- *
- *	Reads ATA taskfile status register for currently-selected device
- *	and return its value. This also clears pending interrupts
- *      from this device
- *
- *	May be used as the check_status() entry in ata_port_operations.
- *
- *	LOCKING:
- *	Inherited from caller.
- */
-u8 ata_check_status(struct ata_port *ap)
-{
-	if (ap->flags & ATA_FLAG_MMIO)
-		return ata_check_status_mmio(ap);
-	return ata_check_status_pio(ap);
-}
-
-
-/**
- *	ata_altstatus - Read device alternate status reg
- *	@ap: port where the device is
- *
- *	Reads ATA taskfile alternate status register for
- *	currently-selected device and return its value.
- *
- *	Note: may NOT be used as the check_altstatus() entry in
- *	ata_port_operations.
- *
- *	LOCKING:
- *	Inherited from caller.
- */
-u8 ata_altstatus(struct ata_port *ap)
-{
-	if (ap->ops->check_altstatus)
-		return ap->ops->check_altstatus(ap);
-
-	if (ap->flags & ATA_FLAG_MMIO)
-		return readb((void __iomem *)ap->ioaddr.altstatus_addr);
-	return inb(ap->ioaddr.altstatus_addr);
-}
-
 
 /**
  *	ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
@@ -632,58 +228,148 @@
 	return -1;
 }
 
-static const char * const xfer_mode_str[] = {
-	"UDMA/16",
-	"UDMA/25",
-	"UDMA/33",
-	"UDMA/44",
-	"UDMA/66",
-	"UDMA/100",
-	"UDMA/133",
-	"UDMA7",
-	"MWDMA0",
-	"MWDMA1",
-	"MWDMA2",
-	"PIO0",
-	"PIO1",
-	"PIO2",
-	"PIO3",
-	"PIO4",
+/**
+ *	ata_pack_xfermask - Pack pio, mwdma and udma masks into xfer_mask
+ *	@pio_mask: pio_mask
+ *	@mwdma_mask: mwdma_mask
+ *	@udma_mask: udma_mask
+ *
+ *	Pack @pio_mask, @mwdma_mask and @udma_mask into a single
+ *	unsigned int xfer_mask.
+ *
+ *	LOCKING:
+ *	None.
+ *
+ *	RETURNS:
+ *	Packed xfer_mask.
+ */
+static unsigned int ata_pack_xfermask(unsigned int pio_mask,
+				      unsigned int mwdma_mask,
+				      unsigned int udma_mask)
+{
+	return ((pio_mask << ATA_SHIFT_PIO) & ATA_MASK_PIO) |
+		((mwdma_mask << ATA_SHIFT_MWDMA) & ATA_MASK_MWDMA) |
+		((udma_mask << ATA_SHIFT_UDMA) & ATA_MASK_UDMA);
+}
+
+static const struct ata_xfer_ent {
+	unsigned int shift, bits;
+	u8 base;
+} ata_xfer_tbl[] = {
+	{ ATA_SHIFT_PIO, ATA_BITS_PIO, XFER_PIO_0 },
+	{ ATA_SHIFT_MWDMA, ATA_BITS_MWDMA, XFER_MW_DMA_0 },
+	{ ATA_SHIFT_UDMA, ATA_BITS_UDMA, XFER_UDMA_0 },
+	{ -1, },
 };
 
 /**
- *	ata_udma_string - convert UDMA bit offset to string
- *	@mask: mask of bits supported; only highest bit counts.
+ *	ata_xfer_mask2mode - Find matching XFER_* for the given xfer_mask
+ *	@xfer_mask: xfer_mask of interest
+ *
+ *	Return matching XFER_* value for @xfer_mask.  Only the highest
+ *	bit of @xfer_mask is considered.
+ *
+ *	LOCKING:
+ *	None.
+ *
+ *	RETURNS:
+ *	Matching XFER_* value, 0 if no match found.
+ */
+static u8 ata_xfer_mask2mode(unsigned int xfer_mask)
+{
+	int highbit = fls(xfer_mask) - 1;
+	const struct ata_xfer_ent *ent;
+
+	for (ent = ata_xfer_tbl; ent->shift >= 0; ent++)
+		if (highbit >= ent->shift && highbit < ent->shift + ent->bits)
+			return ent->base + highbit - ent->shift;
+	return 0;
+}
+
+/**
+ *	ata_xfer_mode2mask - Find matching xfer_mask for XFER_*
+ *	@xfer_mode: XFER_* of interest
+ *
+ *	Return matching xfer_mask for @xfer_mode.
+ *
+ *	LOCKING:
+ *	None.
+ *
+ *	RETURNS:
+ *	Matching xfer_mask, 0 if no match found.
+ */
+static unsigned int ata_xfer_mode2mask(u8 xfer_mode)
+{
+	const struct ata_xfer_ent *ent;
+
+	for (ent = ata_xfer_tbl; ent->shift >= 0; ent++)
+		if (xfer_mode >= ent->base && xfer_mode < ent->base + ent->bits)
+			return 1 << (ent->shift + xfer_mode - ent->base);
+	return 0;
+}
+
+/**
+ *	ata_xfer_mode2shift - Find matching xfer_shift for XFER_*
+ *	@xfer_mode: XFER_* of interest
+ *
+ *	Return matching xfer_shift for @xfer_mode.
+ *
+ *	LOCKING:
+ *	None.
+ *
+ *	RETURNS:
+ *	Matching xfer_shift, -1 if no match found.
+ */
+static int ata_xfer_mode2shift(unsigned int xfer_mode)
+{
+	const struct ata_xfer_ent *ent;
+
+	for (ent = ata_xfer_tbl; ent->shift >= 0; ent++)
+		if (xfer_mode >= ent->base && xfer_mode < ent->base + ent->bits)
+			return ent->shift;
+	return -1;
+}
+
+/**
+ *	ata_mode_string - convert xfer_mask to string
+ *	@xfer_mask: mask of bits supported; only highest bit counts.
  *
  *	Determine string which represents the highest speed
- *	(highest bit in @udma_mask).
+ *	(highest bit in @modemask).
  *
  *	LOCKING:
  *	None.
  *
  *	RETURNS:
  *	Constant C string representing highest speed listed in
- *	@udma_mask, or the constant C string "<n/a>".
+ *	@mode_mask, or the constant C string "<n/a>".
  */
-
-static const char *ata_mode_string(unsigned int mask)
+static const char *ata_mode_string(unsigned int xfer_mask)
 {
-	int i;
+	static const char * const xfer_mode_str[] = {
+		"PIO0",
+		"PIO1",
+		"PIO2",
+		"PIO3",
+		"PIO4",
+		"MWDMA0",
+		"MWDMA1",
+		"MWDMA2",
+		"UDMA/16",
+		"UDMA/25",
+		"UDMA/33",
+		"UDMA/44",
+		"UDMA/66",
+		"UDMA/100",
+		"UDMA/133",
+		"UDMA7",
+	};
+	int highbit;
 
-	for (i = 7; i >= 0; i--)
-		if (mask & (1 << i))
-			goto out;
-	for (i = ATA_SHIFT_MWDMA + 2; i >= ATA_SHIFT_MWDMA; i--)
-		if (mask & (1 << i))
-			goto out;
-	for (i = ATA_SHIFT_PIO + 4; i >= ATA_SHIFT_PIO; i--)
-		if (mask & (1 << i))
-			goto out;
-
+	highbit = fls(xfer_mask) - 1;
+	if (highbit >= 0 && highbit < ARRAY_SIZE(xfer_mode_str))
+		return xfer_mode_str[highbit];
 	return "<n/a>";
-
-out:
-	return xfer_mode_str[i];
 }
 
 /**
@@ -838,6 +524,7 @@
  *	ata_dev_try_classify - Parse returned ATA device signature
  *	@ap: ATA channel to examine
  *	@device: Device to examine (starting at zero)
+ *	@r_err: Value of error register on completion
  *
  *	After an event -- SRST, E.D.D., or SATA COMRESET -- occurs,
  *	an ATA/ATAPI-defined set of values is placed in the ATA
@@ -850,11 +537,14 @@
  *
  *	LOCKING:
  *	caller.
+ *
+ *	RETURNS:
+ *	Device type - %ATA_DEV_ATA, %ATA_DEV_ATAPI or %ATA_DEV_NONE.
  */
 
-static u8 ata_dev_try_classify(struct ata_port *ap, unsigned int device)
+static unsigned int
+ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err)
 {
-	struct ata_device *dev = &ap->device[device];
 	struct ata_taskfile tf;
 	unsigned int class;
 	u8 err;
@@ -865,8 +555,8 @@
 
 	ap->ops->tf_read(ap, &tf);
 	err = tf.feature;
-
-	dev->class = ATA_DEV_NONE;
+	if (r_err)
+		*r_err = err;
 
 	/* see if device passed diags */
 	if (err == 1)
@@ -874,22 +564,20 @@
 	else if ((device == 0) && (err == 0x81))
 		/* do nothing */ ;
 	else
-		return err;
+		return ATA_DEV_NONE;
 
-	/* determine if device if ATA or ATAPI */
+	/* determine if device is ATA or ATAPI */
 	class = ata_dev_classify(&tf);
+
 	if (class == ATA_DEV_UNKNOWN)
-		return err;
+		return ATA_DEV_NONE;
 	if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0))
-		return err;
-
-	dev->class = class;
-
-	return err;
+		return ATA_DEV_NONE;
+	return class;
 }
 
 /**
- *	ata_dev_id_string - Convert IDENTIFY DEVICE page into string
+ *	ata_id_string - Convert IDENTIFY DEVICE page into string
  *	@id: IDENTIFY DEVICE results we will examine
  *	@s: string into which data is output
  *	@ofs: offset into identify device page
@@ -903,8 +591,8 @@
  *	caller.
  */
 
-void ata_dev_id_string(const u16 *id, unsigned char *s,
-		       unsigned int ofs, unsigned int len)
+void ata_id_string(const u16 *id, unsigned char *s,
+		   unsigned int ofs, unsigned int len)
 {
 	unsigned int c;
 
@@ -922,6 +610,49 @@
 	}
 }
 
+/**
+ *	ata_id_c_string - Convert IDENTIFY DEVICE page into C string
+ *	@id: IDENTIFY DEVICE results we will examine
+ *	@s: string into which data is output
+ *	@ofs: offset into identify device page
+ *	@len: length of string to return. must be an odd number.
+ *
+ *	This function is identical to ata_id_string except that it
+ *	trims trailing spaces and terminates the resulting string with
+ *	null.  @len must be actual maximum length (even number) + 1.
+ *
+ *	LOCKING:
+ *	caller.
+ */
+void ata_id_c_string(const u16 *id, unsigned char *s,
+		     unsigned int ofs, unsigned int len)
+{
+	unsigned char *p;
+
+	WARN_ON(!(len & 1));
+
+	ata_id_string(id, s, ofs, len - 1);
+
+	p = s + strnlen(s, len - 1);
+	while (p > s && p[-1] == ' ')
+		p--;
+	*p = '\0';
+}
+
+static u64 ata_id_n_sectors(const u16 *id)
+{
+	if (ata_id_has_lba(id)) {
+		if (ata_id_has_lba48(id))
+			return ata_id_u64(id, 100);
+		else
+			return ata_id_u32(id, 60);
+	} else {
+		if (ata_id_current_chs_valid(id))
+			return ata_id_u32(id, 57);
+		else
+			return id[1] * id[3] * id[6];
+	}
+}
 
 /**
  *	ata_noop_dev_select - Select device 0/1 on ATA bus
@@ -1011,90 +742,172 @@
 
 /**
  *	ata_dump_id - IDENTIFY DEVICE info debugging output
- *	@dev: Device whose IDENTIFY DEVICE page we will dump
+ *	@id: IDENTIFY DEVICE page to dump
  *
- *	Dump selected 16-bit words from a detected device's
- *	IDENTIFY PAGE page.
+ *	Dump selected 16-bit words from the given IDENTIFY DEVICE
+ *	page.
  *
  *	LOCKING:
  *	caller.
  */
 
-static inline void ata_dump_id(const struct ata_device *dev)
+static inline void ata_dump_id(const u16 *id)
 {
 	DPRINTK("49==0x%04x  "
 		"53==0x%04x  "
 		"63==0x%04x  "
 		"64==0x%04x  "
 		"75==0x%04x  \n",
-		dev->id[49],
-		dev->id[53],
-		dev->id[63],
-		dev->id[64],
-		dev->id[75]);
+		id[49],
+		id[53],
+		id[63],
+		id[64],
+		id[75]);
 	DPRINTK("80==0x%04x  "
 		"81==0x%04x  "
 		"82==0x%04x  "
 		"83==0x%04x  "
 		"84==0x%04x  \n",
-		dev->id[80],
-		dev->id[81],
-		dev->id[82],
-		dev->id[83],
-		dev->id[84]);
+		id[80],
+		id[81],
+		id[82],
+		id[83],
+		id[84]);
 	DPRINTK("88==0x%04x  "
 		"93==0x%04x\n",
-		dev->id[88],
-		dev->id[93]);
+		id[88],
+		id[93]);
 }
 
-/*
- *	Compute the PIO modes available for this device. This is not as
- *	trivial as it seems if we must consider early devices correctly.
+/**
+ *	ata_id_xfermask - Compute xfermask from the given IDENTIFY data
+ *	@id: IDENTIFY data to compute xfer mask from
  *
- *	FIXME: pre IDE drive timing (do we care ?). 
+ *	Compute the xfermask for this device. This is not as trivial
+ *	as it seems if we must consider early devices correctly.
+ *
+ *	FIXME: pre IDE drive timing (do we care ?).
+ *
+ *	LOCKING:
+ *	None.
+ *
+ *	RETURNS:
+ *	Computed xfermask
  */
-
-static unsigned int ata_pio_modes(const struct ata_device *adev)
+static unsigned int ata_id_xfermask(const u16 *id)
 {
-	u16 modes;
+	unsigned int pio_mask, mwdma_mask, udma_mask;
 
 	/* Usual case. Word 53 indicates word 64 is valid */
-	if (adev->id[ATA_ID_FIELD_VALID] & (1 << 1)) {
-		modes = adev->id[ATA_ID_PIO_MODES] & 0x03;
-		modes <<= 3;
-		modes |= 0x7;
-		return modes;
+	if (id[ATA_ID_FIELD_VALID] & (1 << 1)) {
+		pio_mask = id[ATA_ID_PIO_MODES] & 0x03;
+		pio_mask <<= 3;
+		pio_mask |= 0x7;
+	} else {
+		/* If word 64 isn't valid then Word 51 high byte holds
+		 * the PIO timing number for the maximum. Turn it into
+		 * a mask.
+		 */
+		pio_mask = (2 << (id[ATA_ID_OLD_PIO_MODES] & 0xFF)) - 1 ;
+
+		/* But wait.. there's more. Design your standards by
+		 * committee and you too can get a free iordy field to
+		 * process. However its the speeds not the modes that
+		 * are supported... Note drivers using the timing API
+		 * will get this right anyway
+		 */
 	}
 
-	/* If word 64 isn't valid then Word 51 high byte holds the PIO timing
-	   number for the maximum. Turn it into a mask and return it */
-	modes = (2 << ((adev->id[ATA_ID_OLD_PIO_MODES] >> 8) & 0xFF)) - 1 ;
-	return modes;
-	/* But wait.. there's more. Design your standards by committee and
-	   you too can get a free iordy field to process. However its the 
-	   speeds not the modes that are supported... Note drivers using the
-	   timing API will get this right anyway */
+	mwdma_mask = id[ATA_ID_MWDMA_MODES] & 0x07;
+
+	udma_mask = 0;
+	if (id[ATA_ID_FIELD_VALID] & (1 << 2))
+		udma_mask = id[ATA_ID_UDMA_MODES] & 0xff;
+
+	return ata_pack_xfermask(pio_mask, mwdma_mask, udma_mask);
 }
 
-struct ata_exec_internal_arg {
-	unsigned int err_mask;
-	struct ata_taskfile *tf;
-	struct completion *waiting;
-};
-
-int ata_qc_complete_internal(struct ata_queued_cmd *qc)
+/**
+ *	ata_port_queue_task - Queue port_task
+ *	@ap: The ata_port to queue port_task for
+ *
+ *	Schedule @fn(@data) for execution after @delay jiffies using
+ *	port_task.  There is one port_task per port and it's the
+ *	user(low level driver)'s responsibility to make sure that only
+ *	one task is active at any given time.
+ *
+ *	libata core layer takes care of synchronization between
+ *	port_task and EH.  ata_port_queue_task() may be ignored for EH
+ *	synchronization.
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *), void *data,
+			 unsigned long delay)
 {
-	struct ata_exec_internal_arg *arg = qc->private_data;
-	struct completion *waiting = arg->waiting;
+	int rc;
 
-	if (!(qc->err_mask & ~AC_ERR_DEV))
-		qc->ap->ops->tf_read(qc->ap, arg->tf);
-	arg->err_mask = qc->err_mask;
-	arg->waiting = NULL;
+	if (ap->flags & ATA_FLAG_FLUSH_PORT_TASK)
+		return;
+
+	PREPARE_WORK(&ap->port_task, fn, data);
+
+	if (!delay)
+		rc = queue_work(ata_wq, &ap->port_task);
+	else
+		rc = queue_delayed_work(ata_wq, &ap->port_task, delay);
+
+	/* rc == 0 means that another user is using port task */
+	WARN_ON(rc == 0);
+}
+
+/**
+ *	ata_port_flush_task - Flush port_task
+ *	@ap: The ata_port to flush port_task for
+ *
+ *	After this function completes, port_task is guranteed not to
+ *	be running or scheduled.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep)
+ */
+void ata_port_flush_task(struct ata_port *ap)
+{
+	unsigned long flags;
+
+	DPRINTK("ENTER\n");
+
+	spin_lock_irqsave(&ap->host_set->lock, flags);
+	ap->flags |= ATA_FLAG_FLUSH_PORT_TASK;
+	spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+	DPRINTK("flush #1\n");
+	flush_workqueue(ata_wq);
+
+	/*
+	 * At this point, if a task is running, it's guaranteed to see
+	 * the FLUSH flag; thus, it will never queue pio tasks again.
+	 * Cancel and flush.
+	 */
+	if (!cancel_delayed_work(&ap->port_task)) {
+		DPRINTK("flush #2\n");
+		flush_workqueue(ata_wq);
+	}
+
+	spin_lock_irqsave(&ap->host_set->lock, flags);
+	ap->flags &= ~ATA_FLAG_FLUSH_PORT_TASK;
+	spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+	DPRINTK("EXIT\n");
+}
+
+void ata_qc_complete_internal(struct ata_queued_cmd *qc)
+{
+	struct completion *waiting = qc->private_data;
+
+	qc->ap->ops->tf_read(qc->ap, &qc->tf);
 	complete(waiting);
-
-	return 0;
 }
 
 /**
@@ -1125,7 +938,7 @@
 	struct ata_queued_cmd *qc;
 	DECLARE_COMPLETION(wait);
 	unsigned long flags;
-	struct ata_exec_internal_arg arg;
+	unsigned int err_mask;
 
 	spin_lock_irqsave(&ap->host_set->lock, flags);
 
@@ -1139,13 +952,12 @@
 		qc->nsect = buflen / ATA_SECT_SIZE;
 	}
 
-	arg.waiting = &wait;
-	arg.tf = tf;
-	qc->private_data = &arg;
+	qc->private_data = &wait;
 	qc->complete_fn = ata_qc_complete_internal;
 
-	if (ata_qc_issue(qc))
-		goto issue_fail;
+	qc->err_mask = ata_qc_issue(qc);
+	if (qc->err_mask)
+		ata_qc_complete(qc);
 
 	spin_unlock_irqrestore(&ap->host_set->lock, flags);
 
@@ -1158,8 +970,8 @@
 		 * before the caller cleans up, it will result in a
 		 * spurious interrupt.  We can live with that.
 		 */
-		if (arg.waiting) {
-			qc->err_mask = AC_ERR_OTHER;
+		if (qc->flags & ATA_QCFLAG_ACTIVE) {
+			qc->err_mask = AC_ERR_TIMEOUT;
 			ata_qc_complete(qc);
 			printk(KERN_WARNING "ata%u: qc timeout (cmd 0x%x)\n",
 			       ap->id, command);
@@ -1168,12 +980,12 @@
 		spin_unlock_irqrestore(&ap->host_set->lock, flags);
 	}
 
-	return arg.err_mask;
+	*tf = qc->tf;
+	err_mask = qc->err_mask;
 
- issue_fail:
 	ata_qc_free(qc);
-	spin_unlock_irqrestore(&ap->host_set->lock, flags);
-	return AC_ERR_OTHER;
+
+	return err_mask;
 }
 
 /**
@@ -1210,73 +1022,78 @@
 }
 
 /**
- *	ata_dev_identify - obtain IDENTIFY x DEVICE page
- *	@ap: port on which device we wish to probe resides
- *	@device: device bus address, starting at zero
+ *	ata_dev_read_id - Read ID data from the specified device
+ *	@ap: port on which target device resides
+ *	@dev: target device
+ *	@p_class: pointer to class of the target device (may be changed)
+ *	@post_reset: is this read ID post-reset?
+ *	@p_id: read IDENTIFY page (newly allocated)
  *
- *	Following bus reset, we issue the IDENTIFY [PACKET] DEVICE
- *	command, and read back the 512-byte device information page.
- *	The device information page is fed to us via the standard
- *	PIO-IN protocol, but we hand-code it here. (TODO: investigate
- *	using standard PIO-IN paths)
- *
- *	After reading the device information page, we use several
- *	bits of information from it to initialize data structures
- *	that will be used during the lifetime of the ata_device.
- *	Other data from the info page is used to disqualify certain
- *	older ATA devices we do not wish to support.
+ *	Read ID data from the specified device.  ATA_CMD_ID_ATA is
+ *	performed on ATA devices and ATA_CMD_ID_ATAPI on ATAPI
+ *	devices.  This function also takes care of EDD signature
+ *	misreporting (to be removed once EDD support is gone) and
+ *	issues ATA_CMD_INIT_DEV_PARAMS for pre-ATA4 drives.
  *
  *	LOCKING:
- *	Inherited from caller.  Some functions called by this function
- *	obtain the host_set lock.
+ *	Kernel thread context (may sleep)
+ *
+ *	RETURNS:
+ *	0 on success, -errno otherwise.
  */
-
-static void ata_dev_identify(struct ata_port *ap, unsigned int device)
+static int ata_dev_read_id(struct ata_port *ap, struct ata_device *dev,
+			   unsigned int *p_class, int post_reset, u16 **p_id)
 {
-	struct ata_device *dev = &ap->device[device];
-	unsigned int major_version;
-	u16 tmp;
-	unsigned long xfer_modes;
+	unsigned int class = *p_class;
 	unsigned int using_edd;
 	struct ata_taskfile tf;
-	unsigned int err_mask;
+	unsigned int err_mask = 0;
+	u16 *id;
+	const char *reason;
 	int rc;
 
-	if (!ata_dev_present(dev)) {
-		DPRINTK("ENTER/EXIT (host %u, dev %u) -- nodev\n",
-			ap->id, device);
-		return;
-	}
+	DPRINTK("ENTER, host %u, dev %u\n", ap->id, dev->devno);
 
-	if (ap->flags & (ATA_FLAG_SRST | ATA_FLAG_SATA_RESET))
+	if (ap->ops->probe_reset ||
+	    ap->flags & (ATA_FLAG_SRST | ATA_FLAG_SATA_RESET))
 		using_edd = 0;
 	else
 		using_edd = 1;
 
-	DPRINTK("ENTER, host %u, dev %u\n", ap->id, device);
+	ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */
 
-	assert (dev->class == ATA_DEV_ATA || dev->class == ATA_DEV_ATAPI ||
-		dev->class == ATA_DEV_NONE);
+	id = kmalloc(sizeof(id[0]) * ATA_ID_WORDS, GFP_KERNEL);
+	if (id == NULL) {
+		rc = -ENOMEM;
+		reason = "out of memory";
+		goto err_out;
+	}
 
-	ata_dev_select(ap, device, 1, 1); /* select device 0/1 */
+ retry:
+	ata_tf_init(ap, &tf, dev->devno);
 
-retry:
-	ata_tf_init(ap, &tf, device);
-
-	if (dev->class == ATA_DEV_ATA) {
+	switch (class) {
+	case ATA_DEV_ATA:
 		tf.command = ATA_CMD_ID_ATA;
-		DPRINTK("do ATA identify\n");
-	} else {
+		break;
+	case ATA_DEV_ATAPI:
 		tf.command = ATA_CMD_ID_ATAPI;
-		DPRINTK("do ATAPI identify\n");
+		break;
+	default:
+		rc = -ENODEV;
+		reason = "unsupported class";
+		goto err_out;
 	}
 
 	tf.protocol = ATA_PROT_PIO;
 
 	err_mask = ata_exec_internal(ap, dev, &tf, DMA_FROM_DEVICE,
-				     dev->id, sizeof(dev->id));
+				     id, sizeof(id[0]) * ATA_ID_WORDS);
 
 	if (err_mask) {
+		rc = -EIO;
+		reason = "I/O error";
+
 		if (err_mask & ~AC_ERR_DEV)
 			goto err_out;
 
@@ -1291,56 +1108,26 @@
 		 * ATA software reset (SRST, the default) does not appear
 		 * to have this problem.
 		 */
-		if ((using_edd) && (dev->class == ATA_DEV_ATA)) {
+		if ((using_edd) && (class == ATA_DEV_ATA)) {
 			u8 err = tf.feature;
 			if (err & ATA_ABORTED) {
-				dev->class = ATA_DEV_ATAPI;
+				class = ATA_DEV_ATAPI;
 				goto retry;
 			}
 		}
 		goto err_out;
 	}
 
-	swap_buf_le16(dev->id, ATA_ID_WORDS);
+	swap_buf_le16(id, ATA_ID_WORDS);
 
-	/* print device capabilities */
-	printk(KERN_DEBUG "ata%u: dev %u cfg "
-	       "49:%04x 82:%04x 83:%04x 84:%04x 85:%04x 86:%04x 87:%04x 88:%04x\n",
-	       ap->id, device, dev->id[49],
-	       dev->id[82], dev->id[83], dev->id[84],
-	       dev->id[85], dev->id[86], dev->id[87],
-	       dev->id[88]);
-
-	/*
-	 * common ATA, ATAPI feature tests
-	 */
-
-	/* we require DMA support (bits 8 of word 49) */
-	if (!ata_id_has_dma(dev->id)) {
-		printk(KERN_DEBUG "ata%u: no dma\n", ap->id);
-		goto err_out_nosup;
+	/* sanity check */
+	if ((class == ATA_DEV_ATA) != ata_id_is_ata(id)) {
+		rc = -EINVAL;
+		reason = "device reports illegal type";
+		goto err_out;
 	}
 
-	/* quick-n-dirty find max transfer mode; for printk only */
-	xfer_modes = dev->id[ATA_ID_UDMA_MODES];
-	if (!xfer_modes)
-		xfer_modes = (dev->id[ATA_ID_MWDMA_MODES]) << ATA_SHIFT_MWDMA;
-	if (!xfer_modes)
-		xfer_modes = ata_pio_modes(dev);
-
-	ata_dump_id(dev);
-
-	/* ATA-specific feature tests */
-	if (dev->class == ATA_DEV_ATA) {
-		if (!ata_id_is_ata(dev->id))	/* sanity check */
-			goto err_out_nosup;
-
-		/* get major version */
-		tmp = dev->id[ATA_ID_MAJOR_VER];
-		for (major_version = 14; major_version >= 1; major_version--)
-			if (tmp & (1 << major_version))
-				break;
-
+	if (post_reset && class == ATA_DEV_ATA) {
 		/*
 		 * The exact sequence expected by certain pre-ATA4 drives is:
 		 * SRST RESET
@@ -1349,122 +1136,195 @@
 		 * anything else..
 		 * Some drives were very specific about that exact sequence.
 		 */
-		if (major_version < 4 || (!ata_id_has_lba(dev->id))) {
-			ata_dev_init_params(ap, dev);
+		if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) {
+			err_mask = ata_dev_init_params(ap, dev);
+			if (err_mask) {
+				rc = -EIO;
+				reason = "INIT_DEV_PARAMS failed";
+				goto err_out;
+			}
 
 			/* current CHS translation info (id[53-58]) might be
 			 * changed. reread the identify device info.
 			 */
-			ata_dev_reread_id(ap, dev);
+			post_reset = 0;
+			goto retry;
 		}
+	}
 
-		if (ata_id_has_lba(dev->id)) {
+	*p_class = class;
+	*p_id = id;
+	return 0;
+
+ err_out:
+	printk(KERN_WARNING "ata%u: dev %u failed to IDENTIFY (%s)\n",
+	       ap->id, dev->devno, reason);
+	kfree(id);
+	return rc;
+}
+
+static inline u8 ata_dev_knobble(const struct ata_port *ap,
+				 struct ata_device *dev)
+{
+	return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id)));
+}
+
+/**
+ *	ata_dev_configure - Configure the specified ATA/ATAPI device
+ *	@ap: Port on which target device resides
+ *	@dev: Target device to configure
+ *	@print_info: Enable device info printout
+ *
+ *	Configure @dev according to @dev->id.  Generic and low-level
+ *	driver specific fixups are also applied.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep)
+ *
+ *	RETURNS:
+ *	0 on success, -errno otherwise
+ */
+static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev,
+			     int print_info)
+{
+	const u16 *id = dev->id;
+	unsigned int xfer_mask;
+	int i, rc;
+
+	if (!ata_dev_present(dev)) {
+		DPRINTK("ENTER/EXIT (host %u, dev %u) -- nodev\n",
+			ap->id, dev->devno);
+		return 0;
+	}
+
+	DPRINTK("ENTER, host %u, dev %u\n", ap->id, dev->devno);
+
+	/* print device capabilities */
+	if (print_info)
+		printk(KERN_DEBUG "ata%u: dev %u cfg 49:%04x 82:%04x 83:%04x "
+		       "84:%04x 85:%04x 86:%04x 87:%04x 88:%04x\n",
+		       ap->id, dev->devno, id[49], id[82], id[83],
+		       id[84], id[85], id[86], id[87], id[88]);
+
+	/* initialize to-be-configured parameters */
+	dev->flags = 0;
+	dev->max_sectors = 0;
+	dev->cdb_len = 0;
+	dev->n_sectors = 0;
+	dev->cylinders = 0;
+	dev->heads = 0;
+	dev->sectors = 0;
+
+	/*
+	 * common ATA, ATAPI feature tests
+	 */
+
+	/* we require DMA support (bits 8 of word 49) */
+	if (!ata_id_has_dma(id)) {
+		printk(KERN_DEBUG "ata%u: no dma\n", ap->id);
+		rc = -EINVAL;
+		goto err_out_nosup;
+	}
+
+	/* find max transfer mode; for printk only */
+	xfer_mask = ata_id_xfermask(id);
+
+	ata_dump_id(id);
+
+	/* ATA-specific feature tests */
+	if (dev->class == ATA_DEV_ATA) {
+		dev->n_sectors = ata_id_n_sectors(id);
+
+		if (ata_id_has_lba(id)) {
+			const char *lba_desc;
+
+			lba_desc = "LBA";
 			dev->flags |= ATA_DFLAG_LBA;
-
-			if (ata_id_has_lba48(dev->id)) {
+			if (ata_id_has_lba48(id)) {
 				dev->flags |= ATA_DFLAG_LBA48;
-				dev->n_sectors = ata_id_u64(dev->id, 100);
-			} else {
-				dev->n_sectors = ata_id_u32(dev->id, 60);
+				lba_desc = "LBA48";
 			}
 
 			/* print device info to dmesg */
-			printk(KERN_INFO "ata%u: dev %u ATA-%d, max %s, %Lu sectors:%s\n",
-			       ap->id, device,
-			       major_version,
-			       ata_mode_string(xfer_modes),
-			       (unsigned long long)dev->n_sectors,
-			       dev->flags & ATA_DFLAG_LBA48 ? " LBA48" : " LBA");
-		} else { 
+			if (print_info)
+				printk(KERN_INFO "ata%u: dev %u ATA-%d, "
+				       "max %s, %Lu sectors: %s\n",
+				       ap->id, dev->devno,
+				       ata_id_major_version(id),
+				       ata_mode_string(xfer_mask),
+				       (unsigned long long)dev->n_sectors,
+				       lba_desc);
+		} else {
 			/* CHS */
 
 			/* Default translation */
-			dev->cylinders	= dev->id[1];
-			dev->heads	= dev->id[3];
-			dev->sectors	= dev->id[6];
-			dev->n_sectors	= dev->cylinders * dev->heads * dev->sectors;
+			dev->cylinders	= id[1];
+			dev->heads	= id[3];
+			dev->sectors	= id[6];
 
-			if (ata_id_current_chs_valid(dev->id)) {
+			if (ata_id_current_chs_valid(id)) {
 				/* Current CHS translation is valid. */
-				dev->cylinders = dev->id[54];
-				dev->heads     = dev->id[55];
-				dev->sectors   = dev->id[56];
-				
-				dev->n_sectors = ata_id_u32(dev->id, 57);
+				dev->cylinders = id[54];
+				dev->heads     = id[55];
+				dev->sectors   = id[56];
 			}
 
 			/* print device info to dmesg */
-			printk(KERN_INFO "ata%u: dev %u ATA-%d, max %s, %Lu sectors: CHS %d/%d/%d\n",
-			       ap->id, device,
-			       major_version,
-			       ata_mode_string(xfer_modes),
-			       (unsigned long long)dev->n_sectors,
-			       (int)dev->cylinders, (int)dev->heads, (int)dev->sectors);
-
+			if (print_info)
+				printk(KERN_INFO "ata%u: dev %u ATA-%d, "
+				       "max %s, %Lu sectors: CHS %u/%u/%u\n",
+				       ap->id, dev->devno,
+				       ata_id_major_version(id),
+				       ata_mode_string(xfer_mask),
+				       (unsigned long long)dev->n_sectors,
+				       dev->cylinders, dev->heads, dev->sectors);
 		}
 
-		ap->host->max_cmd_len = 16;
+		dev->cdb_len = 16;
 	}
 
 	/* ATAPI-specific feature tests */
 	else if (dev->class == ATA_DEV_ATAPI) {
-		if (ata_id_is_ata(dev->id))		/* sanity check */
-			goto err_out_nosup;
-
-		rc = atapi_cdb_len(dev->id);
+		rc = atapi_cdb_len(id);
 		if ((rc < 12) || (rc > ATAPI_CDB_LEN)) {
 			printk(KERN_WARNING "ata%u: unsupported CDB len\n", ap->id);
+			rc = -EINVAL;
 			goto err_out_nosup;
 		}
-		ap->cdb_len = (unsigned int) rc;
-		ap->host->max_cmd_len = (unsigned char) ap->cdb_len;
+		dev->cdb_len = (unsigned int) rc;
 
 		/* print device info to dmesg */
-		printk(KERN_INFO "ata%u: dev %u ATAPI, max %s\n",
-		       ap->id, device,
-		       ata_mode_string(xfer_modes));
+		if (print_info)
+			printk(KERN_INFO "ata%u: dev %u ATAPI, max %s\n",
+			       ap->id, dev->devno, ata_mode_string(xfer_mask));
 	}
 
-	DPRINTK("EXIT, drv_stat = 0x%x\n", ata_chk_status(ap));
-	return;
+	ap->host->max_cmd_len = 0;
+	for (i = 0; i < ATA_MAX_DEVICES; i++)
+		ap->host->max_cmd_len = max_t(unsigned int,
+					      ap->host->max_cmd_len,
+					      ap->device[i].cdb_len);
 
-err_out_nosup:
-	printk(KERN_WARNING "ata%u: dev %u not supported, ignoring\n",
-	       ap->id, device);
-err_out:
-	dev->class++;	/* converts ATA_DEV_xxx into ATA_DEV_xxx_UNSUP */
-	DPRINTK("EXIT, err\n");
-}
-
-
-static inline u8 ata_dev_knobble(const struct ata_port *ap)
-{
-	return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(ap->device->id)));
-}
-
-/**
- * 	ata_dev_config - Run device specific handlers and check for
- * 			 SATA->PATA bridges
- * 	@ap: Bus
- * 	@i:  Device
- *
- * 	LOCKING:
- */
-
-void ata_dev_config(struct ata_port *ap, unsigned int i)
-{
 	/* limit bridge transfers to udma5, 200 sectors */
-	if (ata_dev_knobble(ap)) {
-		printk(KERN_INFO "ata%u(%u): applying bridge limits\n",
-			ap->id, ap->device->devno);
+	if (ata_dev_knobble(ap, dev)) {
+		if (print_info)
+			printk(KERN_INFO "ata%u(%u): applying bridge limits\n",
+			       ap->id, dev->devno);
 		ap->udma_mask &= ATA_UDMA5;
-		ap->host->max_sectors = ATA_MAX_SECTORS;
-		ap->host->hostt->max_sectors = ATA_MAX_SECTORS;
-		ap->device[i].flags |= ATA_DFLAG_LOCK_SECTORS;
+		dev->max_sectors = ATA_MAX_SECTORS;
 	}
 
 	if (ap->ops->dev_config)
-		ap->ops->dev_config(ap, &ap->device[i]);
+		ap->ops->dev_config(ap, dev);
+
+	DPRINTK("EXIT, drv_stat = 0x%x\n", ata_chk_status(ap));
+	return 0;
+
+err_out_nosup:
+	printk(KERN_WARNING "ata%u: dev %u not supported, ignoring\n",
+	       ap->id, dev->devno);
+	DPRINTK("EXIT, err\n");
+	return rc;
 }
 
 /**
@@ -1484,21 +1344,59 @@
 
 static int ata_bus_probe(struct ata_port *ap)
 {
-	unsigned int i, found = 0;
+	unsigned int classes[ATA_MAX_DEVICES];
+	unsigned int i, rc, found = 0;
 
-	ap->ops->phy_reset(ap);
-	if (ap->flags & ATA_FLAG_PORT_DISABLED)
-		goto err_out;
+	ata_port_probe(ap);
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		ata_dev_identify(ap, i);
-		if (ata_dev_present(&ap->device[i])) {
-			found = 1;
-			ata_dev_config(ap,i);
+	/* reset and determine device classes */
+	for (i = 0; i < ATA_MAX_DEVICES; i++)
+		classes[i] = ATA_DEV_UNKNOWN;
+
+	if (ap->ops->probe_reset) {
+		rc = ap->ops->probe_reset(ap, classes);
+		if (rc) {
+			printk("ata%u: reset failed (errno=%d)\n", ap->id, rc);
+			return rc;
 		}
+	} else {
+		ap->ops->phy_reset(ap);
+
+		if (!(ap->flags & ATA_FLAG_PORT_DISABLED))
+			for (i = 0; i < ATA_MAX_DEVICES; i++)
+				classes[i] = ap->device[i].class;
+
+		ata_port_probe(ap);
 	}
 
-	if ((!found) || (ap->flags & ATA_FLAG_PORT_DISABLED))
+	for (i = 0; i < ATA_MAX_DEVICES; i++)
+		if (classes[i] == ATA_DEV_UNKNOWN)
+			classes[i] = ATA_DEV_NONE;
+
+	/* read IDENTIFY page and configure devices */
+	for (i = 0; i < ATA_MAX_DEVICES; i++) {
+		struct ata_device *dev = &ap->device[i];
+
+		dev->class = classes[i];
+
+		if (!ata_dev_present(dev))
+			continue;
+
+		WARN_ON(dev->id != NULL);
+		if (ata_dev_read_id(ap, dev, &dev->class, 1, &dev->id)) {
+			dev->class = ATA_DEV_NONE;
+			continue;
+		}
+
+		if (ata_dev_configure(ap, dev, 1)) {
+			dev->class++;	/* disable device */
+			continue;
+		}
+
+		found = 1;
+	}
+
+	if (!found)
 		goto err_out_disable;
 
 	ata_set_mode(ap);
@@ -1509,7 +1407,6 @@
 
 err_out_disable:
 	ap->ops->port_disable(ap);
-err_out:
 	return -1;
 }
 
@@ -1530,6 +1427,41 @@
 }
 
 /**
+ *	sata_print_link_status - Print SATA link status
+ *	@ap: SATA port to printk link status about
+ *
+ *	This function prints link speed and status of a SATA link.
+ *
+ *	LOCKING:
+ *	None.
+ */
+static void sata_print_link_status(struct ata_port *ap)
+{
+	u32 sstatus, tmp;
+	const char *speed;
+
+	if (!ap->ops->scr_read)
+		return;
+
+	sstatus = scr_read(ap, SCR_STATUS);
+
+	if (sata_dev_present(ap)) {
+		tmp = (sstatus >> 4) & 0xf;
+		if (tmp & (1 << 0))
+			speed = "1.5";
+		else if (tmp & (1 << 1))
+			speed = "3.0";
+		else
+			speed = "<unknown>";
+		printk(KERN_INFO "ata%u: SATA link up %s Gbps (SStatus %X)\n",
+		       ap->id, speed, sstatus);
+	} else {
+		printk(KERN_INFO "ata%u: SATA link down (SStatus %X)\n",
+		       ap->id, sstatus);
+	}
+}
+
+/**
  *	__sata_phy_reset - Wake/reset a low-level SATA PHY
  *	@ap: SATA port associated with target SATA PHY.
  *
@@ -1563,27 +1495,14 @@
 			break;
 	} while (time_before(jiffies, timeout));
 
-	/* TODO: phy layer with polling, timeouts, etc. */
-	sstatus = scr_read(ap, SCR_STATUS);
-	if (sata_dev_present(ap)) {
-		const char *speed;
-		u32 tmp;
+	/* print link status */
+	sata_print_link_status(ap);
 
-		tmp = (sstatus >> 4) & 0xf;
-		if (tmp & (1 << 0))
-			speed = "1.5";
-		else if (tmp & (1 << 1))
-			speed = "3.0";
-		else
-			speed = "<unknown>";
-		printk(KERN_INFO "ata%u: SATA link up %s Gbps (SStatus %X)\n",
-		       ap->id, speed, sstatus);
+	/* TODO: phy layer with polling, timeouts, etc. */
+	if (sata_dev_present(ap))
 		ata_port_probe(ap);
-	} else {
-		printk(KERN_INFO "ata%u: SATA link down (SStatus %X)\n",
-		       ap->id, sstatus);
+	else
 		ata_port_disable(ap);
-	}
 
 	if (ap->flags & ATA_FLAG_PORT_DISABLED)
 		return;
@@ -1756,9 +1675,9 @@
 	ata_timing_quantize(t, t, T, UT);
 
 	/*
-	 * Even in DMA/UDMA modes we still use PIO access for IDENTIFY, S.M.A.R.T
-	 * and some other commands. We have to ensure that the DMA cycle timing is
-	 * slower/equal than the fastest PIO timing.
+	 * Even in DMA/UDMA modes we still use PIO access for IDENTIFY,
+	 * S.M.A.R.T * and some other commands. We have to ensure that the
+	 * DMA cycle timing is slower/equal than the fastest PIO timing.
 	 */
 
 	if (speed > XFER_PIO_4) {
@@ -1767,7 +1686,7 @@
 	}
 
 	/*
-	 * Lenghten active & recovery time so that cycle time is correct.
+	 * Lengthen active & recovery time so that cycle time is correct.
 	 */
 
 	if (t->act8b + t->rec8b < t->cyc8b) {
@@ -1783,31 +1702,8 @@
 	return 0;
 }
 
-static const struct {
-	unsigned int shift;
-	u8 base;
-} xfer_mode_classes[] = {
-	{ ATA_SHIFT_UDMA,	XFER_UDMA_0 },
-	{ ATA_SHIFT_MWDMA,	XFER_MW_DMA_0 },
-	{ ATA_SHIFT_PIO,	XFER_PIO_0 },
-};
-
-static u8 base_from_shift(unsigned int shift)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(xfer_mode_classes); i++)
-		if (xfer_mode_classes[i].shift == shift)
-			return xfer_mode_classes[i].base;
-
-	return 0xff;
-}
-
 static void ata_dev_set_mode(struct ata_port *ap, struct ata_device *dev)
 {
-	int ofs, idx;
-	u8 base;
-
 	if (!ata_dev_present(dev) || (ap->flags & ATA_FLAG_PORT_DISABLED))
 		return;
 
@@ -1816,65 +1712,58 @@
 
 	ata_dev_set_xfermode(ap, dev);
 
-	base = base_from_shift(dev->xfer_shift);
-	ofs = dev->xfer_mode - base;
-	idx = ofs + dev->xfer_shift;
-	WARN_ON(idx >= ARRAY_SIZE(xfer_mode_str));
+	if (ata_dev_revalidate(ap, dev, 0)) {
+		printk(KERN_ERR "ata%u: failed to revalidate after set "
+		       "xfermode, disabled\n", ap->id);
+		ata_port_disable(ap);
+	}
 
-	DPRINTK("idx=%d xfer_shift=%u, xfer_mode=0x%x, base=0x%x, offset=%d\n",
-		idx, dev->xfer_shift, (int)dev->xfer_mode, (int)base, ofs);
+	DPRINTK("xfer_shift=%u, xfer_mode=0x%x\n",
+		dev->xfer_shift, (int)dev->xfer_mode);
 
 	printk(KERN_INFO "ata%u: dev %u configured for %s\n",
-		ap->id, dev->devno, xfer_mode_str[idx]);
+	       ap->id, dev->devno,
+	       ata_mode_string(ata_xfer_mode2mask(dev->xfer_mode)));
 }
 
 static int ata_host_set_pio(struct ata_port *ap)
 {
-	unsigned int mask;
-	int x, i;
-	u8 base, xfer_mode;
-
-	mask = ata_get_mode_mask(ap, ATA_SHIFT_PIO);
-	x = fgb(mask);
-	if (x < 0) {
-		printk(KERN_WARNING "ata%u: no PIO support\n", ap->id);
-		return -1;
-	}
-
-	base = base_from_shift(ATA_SHIFT_PIO);
-	xfer_mode = base + x;
-
-	DPRINTK("base 0x%x xfer_mode 0x%x mask 0x%x x %d\n",
-		(int)base, (int)xfer_mode, mask, x);
-
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		struct ata_device *dev = &ap->device[i];
-		if (ata_dev_present(dev)) {
-			dev->pio_mode = xfer_mode;
-			dev->xfer_mode = xfer_mode;
-			dev->xfer_shift = ATA_SHIFT_PIO;
-			if (ap->ops->set_piomode)
-				ap->ops->set_piomode(ap, dev);
-		}
-	}
-
-	return 0;
-}
-
-static void ata_host_set_dma(struct ata_port *ap, u8 xfer_mode,
-			    unsigned int xfer_shift)
-{
 	int i;
 
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
 		struct ata_device *dev = &ap->device[i];
-		if (ata_dev_present(dev)) {
-			dev->dma_mode = xfer_mode;
-			dev->xfer_mode = xfer_mode;
-			dev->xfer_shift = xfer_shift;
-			if (ap->ops->set_dmamode)
-				ap->ops->set_dmamode(ap, dev);
+
+		if (!ata_dev_present(dev))
+			continue;
+
+		if (!dev->pio_mode) {
+			printk(KERN_WARNING "ata%u: no PIO support\n", ap->id);
+			return -1;
 		}
+
+		dev->xfer_mode = dev->pio_mode;
+		dev->xfer_shift = ATA_SHIFT_PIO;
+		if (ap->ops->set_piomode)
+			ap->ops->set_piomode(ap, dev);
+	}
+
+	return 0;
+}
+
+static void ata_host_set_dma(struct ata_port *ap)
+{
+	int i;
+
+	for (i = 0; i < ATA_MAX_DEVICES; i++) {
+		struct ata_device *dev = &ap->device[i];
+
+		if (!ata_dev_present(dev) || !dev->dma_mode)
+			continue;
+
+		dev->xfer_mode = dev->dma_mode;
+		dev->xfer_shift = ata_xfer_mode2shift(dev->dma_mode);
+		if (ap->ops->set_dmamode)
+			ap->ops->set_dmamode(ap, dev);
 	}
 }
 
@@ -1886,32 +1775,37 @@
  *
  *	LOCKING:
  *	PCI/etc. bus probe sem.
- *
  */
 static void ata_set_mode(struct ata_port *ap)
 {
-	unsigned int xfer_shift;
-	u8 xfer_mode;
-	int rc;
+	int i, rc;
 
-	/* step 1: always set host PIO timings */
+	/* step 1: calculate xfer_mask */
+	for (i = 0; i < ATA_MAX_DEVICES; i++) {
+		struct ata_device *dev = &ap->device[i];
+		unsigned int xfer_mask;
+
+		if (!ata_dev_present(dev))
+			continue;
+
+		xfer_mask = ata_dev_xfermask(ap, dev);
+
+		dev->pio_mode = ata_xfer_mask2mode(xfer_mask & ATA_MASK_PIO);
+		dev->dma_mode = ata_xfer_mask2mode(xfer_mask & (ATA_MASK_MWDMA |
+								ATA_MASK_UDMA));
+	}
+
+	/* step 2: always set host PIO timings */
 	rc = ata_host_set_pio(ap);
 	if (rc)
 		goto err_out;
 
-	/* step 2: choose the best data xfer mode */
-	xfer_mode = xfer_shift = 0;
-	rc = ata_choose_xfer_mode(ap, &xfer_mode, &xfer_shift);
-	if (rc)
-		goto err_out;
-
-	/* step 3: if that xfer mode isn't PIO, set host DMA timings */
-	if (xfer_shift != ATA_SHIFT_PIO)
-		ata_host_set_dma(ap, xfer_mode, xfer_shift);
+	/* step 3: set host DMA timings */
+	ata_host_set_dma(ap);
 
 	/* step 4: update devices' xfer mode */
-	ata_dev_set_mode(ap, &ap->device[0]);
-	ata_dev_set_mode(ap, &ap->device[1]);
+	for (i = 0; i < ATA_MAX_DEVICES; i++)
+		ata_dev_set_mode(ap, &ap->device[i]);
 
 	if (ap->flags & ATA_FLAG_PORT_DISABLED)
 		return;
@@ -1926,6 +1820,26 @@
 }
 
 /**
+ *	ata_tf_to_host - issue ATA taskfile to host controller
+ *	@ap: port to which command is being issued
+ *	@tf: ATA taskfile register set
+ *
+ *	Issues ATA taskfile register set to ATA host controller,
+ *	with proper synchronization with interrupt handler and
+ *	other threads.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+static inline void ata_tf_to_host(struct ata_port *ap,
+				  const struct ata_taskfile *tf)
+{
+	ap->ops->tf_load(ap, tf);
+	ap->ops->exec_command(ap, tf);
+}
+
+/**
  *	ata_busy_sleep - sleep until BSY clears, or timeout
  *	@ap: port containing status register to be polled
  *	@tmout_pat: impatience timeout
@@ -1935,12 +1849,10 @@
  *	or a timeout occurs.
  *
  *	LOCKING: None.
- *
  */
 
-static unsigned int ata_busy_sleep (struct ata_port *ap,
-				    unsigned long tmout_pat,
-			    	    unsigned long tmout)
+unsigned int ata_busy_sleep (struct ata_port *ap,
+			     unsigned long tmout_pat, unsigned long tmout)
 {
 	unsigned long timer_start, timeout;
 	u8 status;
@@ -2159,9 +2071,9 @@
 	/*
 	 * determine by signature whether we have ATA or ATAPI devices
 	 */
-	err = ata_dev_try_classify(ap, 0);
+	ap->device[0].class = ata_dev_try_classify(ap, 0, &err);
 	if ((slave_possible) && (err != 0x81))
-		ata_dev_try_classify(ap, 1);
+		ap->device[1].class = ata_dev_try_classify(ap, 1, &err);
 
 	/* re-enable interrupts */
 	if (ap->ioaddr.ctl_addr)	/* FIXME: hack. create a hook instead */
@@ -2196,11 +2108,446 @@
 	DPRINTK("EXIT\n");
 }
 
-static void ata_pr_blacklisted(const struct ata_port *ap,
-			       const struct ata_device *dev)
+static int sata_phy_resume(struct ata_port *ap)
 {
-	printk(KERN_WARNING "ata%u: dev %u is on DMA blacklist, disabling DMA\n",
-		ap->id, dev->devno);
+	unsigned long timeout = jiffies + (HZ * 5);
+	u32 sstatus;
+
+	scr_write_flush(ap, SCR_CONTROL, 0x300);
+
+	/* Wait for phy to become ready, if necessary. */
+	do {
+		msleep(200);
+		sstatus = scr_read(ap, SCR_STATUS);
+		if ((sstatus & 0xf) != 1)
+			return 0;
+	} while (time_before(jiffies, timeout));
+
+	return -1;
+}
+
+/**
+ *	ata_std_probeinit - initialize probing
+ *	@ap: port to be probed
+ *
+ *	@ap is about to be probed.  Initialize it.  This function is
+ *	to be used as standard callback for ata_drive_probe_reset().
+ *
+ *	NOTE!!! Do not use this function as probeinit if a low level
+ *	driver implements only hardreset.  Just pass NULL as probeinit
+ *	in that case.  Using this function is probably okay but doing
+ *	so makes reset sequence different from the original
+ *	->phy_reset implementation and Jeff nervous.  :-P
+ */
+extern void ata_std_probeinit(struct ata_port *ap)
+{
+	if (ap->flags & ATA_FLAG_SATA && ap->ops->scr_read) {
+		sata_phy_resume(ap);
+		if (sata_dev_present(ap))
+			ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+	}
+}
+
+/**
+ *	ata_std_softreset - reset host port via ATA SRST
+ *	@ap: port to reset
+ *	@verbose: fail verbosely
+ *	@classes: resulting classes of attached devices
+ *
+ *	Reset host port using ATA SRST.  This function is to be used
+ *	as standard callback for ata_drive_*_reset() functions.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep)
+ *
+ *	RETURNS:
+ *	0 on success, -errno otherwise.
+ */
+int ata_std_softreset(struct ata_port *ap, int verbose, unsigned int *classes)
+{
+	unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
+	unsigned int devmask = 0, err_mask;
+	u8 err;
+
+	DPRINTK("ENTER\n");
+
+	if (ap->ops->scr_read && !sata_dev_present(ap)) {
+		classes[0] = ATA_DEV_NONE;
+		goto out;
+	}
+
+	/* determine if device 0/1 are present */
+	if (ata_devchk(ap, 0))
+		devmask |= (1 << 0);
+	if (slave_possible && ata_devchk(ap, 1))
+		devmask |= (1 << 1);
+
+	/* select device 0 again */
+	ap->ops->dev_select(ap, 0);
+
+	/* issue bus reset */
+	DPRINTK("about to softreset, devmask=%x\n", devmask);
+	err_mask = ata_bus_softreset(ap, devmask);
+	if (err_mask) {
+		if (verbose)
+			printk(KERN_ERR "ata%u: SRST failed (err_mask=0x%x)\n",
+			       ap->id, err_mask);
+		else
+			DPRINTK("EXIT, softreset failed (err_mask=0x%x)\n",
+				err_mask);
+		return -EIO;
+	}
+
+	/* determine by signature whether we have ATA or ATAPI devices */
+	classes[0] = ata_dev_try_classify(ap, 0, &err);
+	if (slave_possible && err != 0x81)
+		classes[1] = ata_dev_try_classify(ap, 1, &err);
+
+ out:
+	DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]);
+	return 0;
+}
+
+/**
+ *	sata_std_hardreset - reset host port via SATA phy reset
+ *	@ap: port to reset
+ *	@verbose: fail verbosely
+ *	@class: resulting class of attached device
+ *
+ *	SATA phy-reset host port using DET bits of SControl register.
+ *	This function is to be used as standard callback for
+ *	ata_drive_*_reset().
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep)
+ *
+ *	RETURNS:
+ *	0 on success, -errno otherwise.
+ */
+int sata_std_hardreset(struct ata_port *ap, int verbose, unsigned int *class)
+{
+	DPRINTK("ENTER\n");
+
+	/* Issue phy wake/reset */
+	scr_write_flush(ap, SCR_CONTROL, 0x301);
+
+	/*
+	 * Couldn't find anything in SATA I/II specs, but AHCI-1.1
+	 * 10.4.2 says at least 1 ms.
+	 */
+	msleep(1);
+
+	/* Bring phy back */
+	sata_phy_resume(ap);
+
+	/* TODO: phy layer with polling, timeouts, etc. */
+	if (!sata_dev_present(ap)) {
+		*class = ATA_DEV_NONE;
+		DPRINTK("EXIT, link offline\n");
+		return 0;
+	}
+
+	if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
+		if (verbose)
+			printk(KERN_ERR "ata%u: COMRESET failed "
+			       "(device not ready)\n", ap->id);
+		else
+			DPRINTK("EXIT, device not ready\n");
+		return -EIO;
+	}
+
+	ap->ops->dev_select(ap, 0);	/* probably unnecessary */
+
+	*class = ata_dev_try_classify(ap, 0, NULL);
+
+	DPRINTK("EXIT, class=%u\n", *class);
+	return 0;
+}
+
+/**
+ *	ata_std_postreset - standard postreset callback
+ *	@ap: the target ata_port
+ *	@classes: classes of attached devices
+ *
+ *	This function is invoked after a successful reset.  Note that
+ *	the device might have been reset more than once using
+ *	different reset methods before postreset is invoked.
+ *
+ *	This function is to be used as standard callback for
+ *	ata_drive_*_reset().
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep)
+ */
+void ata_std_postreset(struct ata_port *ap, unsigned int *classes)
+{
+	DPRINTK("ENTER\n");
+
+	/* set cable type if it isn't already set */
+	if (ap->cbl == ATA_CBL_NONE && ap->flags & ATA_FLAG_SATA)
+		ap->cbl = ATA_CBL_SATA;
+
+	/* print link status */
+	if (ap->cbl == ATA_CBL_SATA)
+		sata_print_link_status(ap);
+
+	/* re-enable interrupts */
+	if (ap->ioaddr.ctl_addr)	/* FIXME: hack. create a hook instead */
+		ata_irq_on(ap);
+
+	/* is double-select really necessary? */
+	if (classes[0] != ATA_DEV_NONE)
+		ap->ops->dev_select(ap, 1);
+	if (classes[1] != ATA_DEV_NONE)
+		ap->ops->dev_select(ap, 0);
+
+	/* bail out if no device is present */
+	if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) {
+		DPRINTK("EXIT, no device\n");
+		return;
+	}
+
+	/* set up device control */
+	if (ap->ioaddr.ctl_addr) {
+		if (ap->flags & ATA_FLAG_MMIO)
+			writeb(ap->ctl, (void __iomem *) ap->ioaddr.ctl_addr);
+		else
+			outb(ap->ctl, ap->ioaddr.ctl_addr);
+	}
+
+	DPRINTK("EXIT\n");
+}
+
+/**
+ *	ata_std_probe_reset - standard probe reset method
+ *	@ap: prot to perform probe-reset
+ *	@classes: resulting classes of attached devices
+ *
+ *	The stock off-the-shelf ->probe_reset method.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep)
+ *
+ *	RETURNS:
+ *	0 on success, -errno otherwise.
+ */
+int ata_std_probe_reset(struct ata_port *ap, unsigned int *classes)
+{
+	ata_reset_fn_t hardreset;
+
+	hardreset = NULL;
+	if (ap->flags & ATA_FLAG_SATA && ap->ops->scr_read)
+		hardreset = sata_std_hardreset;
+
+	return ata_drive_probe_reset(ap, ata_std_probeinit,
+				     ata_std_softreset, hardreset,
+				     ata_std_postreset, classes);
+}
+
+static int do_probe_reset(struct ata_port *ap, ata_reset_fn_t reset,
+			  ata_postreset_fn_t postreset,
+			  unsigned int *classes)
+{
+	int i, rc;
+
+	for (i = 0; i < ATA_MAX_DEVICES; i++)
+		classes[i] = ATA_DEV_UNKNOWN;
+
+	rc = reset(ap, 0, classes);
+	if (rc)
+		return rc;
+
+	/* If any class isn't ATA_DEV_UNKNOWN, consider classification
+	 * is complete and convert all ATA_DEV_UNKNOWN to
+	 * ATA_DEV_NONE.
+	 */
+	for (i = 0; i < ATA_MAX_DEVICES; i++)
+		if (classes[i] != ATA_DEV_UNKNOWN)
+			break;
+
+	if (i < ATA_MAX_DEVICES)
+		for (i = 0; i < ATA_MAX_DEVICES; i++)
+			if (classes[i] == ATA_DEV_UNKNOWN)
+				classes[i] = ATA_DEV_NONE;
+
+	if (postreset)
+		postreset(ap, classes);
+
+	return classes[0] != ATA_DEV_UNKNOWN ? 0 : -ENODEV;
+}
+
+/**
+ *	ata_drive_probe_reset - Perform probe reset with given methods
+ *	@ap: port to reset
+ *	@probeinit: probeinit method (can be NULL)
+ *	@softreset: softreset method (can be NULL)
+ *	@hardreset: hardreset method (can be NULL)
+ *	@postreset: postreset method (can be NULL)
+ *	@classes: resulting classes of attached devices
+ *
+ *	Reset the specified port and classify attached devices using
+ *	given methods.  This function prefers softreset but tries all
+ *	possible reset sequences to reset and classify devices.  This
+ *	function is intended to be used for constructing ->probe_reset
+ *	callback by low level drivers.
+ *
+ *	Reset methods should follow the following rules.
+ *
+ *	- Return 0 on sucess, -errno on failure.
+ *	- If classification is supported, fill classes[] with
+ *	  recognized class codes.
+ *	- If classification is not supported, leave classes[] alone.
+ *	- If verbose is non-zero, print error message on failure;
+ *	  otherwise, shut up.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep)
+ *
+ *	RETURNS:
+ *	0 on success, -EINVAL if no reset method is avaliable, -ENODEV
+ *	if classification fails, and any error code from reset
+ *	methods.
+ */
+int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit,
+			  ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+			  ata_postreset_fn_t postreset, unsigned int *classes)
+{
+	int rc = -EINVAL;
+
+	if (probeinit)
+		probeinit(ap);
+
+	if (softreset) {
+		rc = do_probe_reset(ap, softreset, postreset, classes);
+		if (rc == 0)
+			return 0;
+	}
+
+	if (!hardreset)
+		return rc;
+
+	rc = do_probe_reset(ap, hardreset, postreset, classes);
+	if (rc == 0 || rc != -ENODEV)
+		return rc;
+
+	if (softreset)
+		rc = do_probe_reset(ap, softreset, postreset, classes);
+
+	return rc;
+}
+
+/**
+ *	ata_dev_same_device - Determine whether new ID matches configured device
+ *	@ap: port on which the device to compare against resides
+ *	@dev: device to compare against
+ *	@new_class: class of the new device
+ *	@new_id: IDENTIFY page of the new device
+ *
+ *	Compare @new_class and @new_id against @dev and determine
+ *	whether @dev is the device indicated by @new_class and
+ *	@new_id.
+ *
+ *	LOCKING:
+ *	None.
+ *
+ *	RETURNS:
+ *	1 if @dev matches @new_class and @new_id, 0 otherwise.
+ */
+static int ata_dev_same_device(struct ata_port *ap, struct ata_device *dev,
+			       unsigned int new_class, const u16 *new_id)
+{
+	const u16 *old_id = dev->id;
+	unsigned char model[2][41], serial[2][21];
+	u64 new_n_sectors;
+
+	if (dev->class != new_class) {
+		printk(KERN_INFO
+		       "ata%u: dev %u class mismatch %d != %d\n",
+		       ap->id, dev->devno, dev->class, new_class);
+		return 0;
+	}
+
+	ata_id_c_string(old_id, model[0], ATA_ID_PROD_OFS, sizeof(model[0]));
+	ata_id_c_string(new_id, model[1], ATA_ID_PROD_OFS, sizeof(model[1]));
+	ata_id_c_string(old_id, serial[0], ATA_ID_SERNO_OFS, sizeof(serial[0]));
+	ata_id_c_string(new_id, serial[1], ATA_ID_SERNO_OFS, sizeof(serial[1]));
+	new_n_sectors = ata_id_n_sectors(new_id);
+
+	if (strcmp(model[0], model[1])) {
+		printk(KERN_INFO
+		       "ata%u: dev %u model number mismatch '%s' != '%s'\n",
+		       ap->id, dev->devno, model[0], model[1]);
+		return 0;
+	}
+
+	if (strcmp(serial[0], serial[1])) {
+		printk(KERN_INFO
+		       "ata%u: dev %u serial number mismatch '%s' != '%s'\n",
+		       ap->id, dev->devno, serial[0], serial[1]);
+		return 0;
+	}
+
+	if (dev->class == ATA_DEV_ATA && dev->n_sectors != new_n_sectors) {
+		printk(KERN_INFO
+		       "ata%u: dev %u n_sectors mismatch %llu != %llu\n",
+		       ap->id, dev->devno, (unsigned long long)dev->n_sectors,
+		       (unsigned long long)new_n_sectors);
+		return 0;
+	}
+
+	return 1;
+}
+
+/**
+ *	ata_dev_revalidate - Revalidate ATA device
+ *	@ap: port on which the device to revalidate resides
+ *	@dev: device to revalidate
+ *	@post_reset: is this revalidation after reset?
+ *
+ *	Re-read IDENTIFY page and make sure @dev is still attached to
+ *	the port.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep)
+ *
+ *	RETURNS:
+ *	0 on success, negative errno otherwise
+ */
+int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev,
+		       int post_reset)
+{
+	unsigned int class;
+	u16 *id;
+	int rc;
+
+	if (!ata_dev_present(dev))
+		return -ENODEV;
+
+	class = dev->class;
+	id = NULL;
+
+	/* allocate & read ID data */
+	rc = ata_dev_read_id(ap, dev, &class, post_reset, &id);
+	if (rc)
+		goto fail;
+
+	/* is the device still there? */
+	if (!ata_dev_same_device(ap, dev, class, id)) {
+		rc = -ENODEV;
+		goto fail;
+	}
+
+	kfree(dev->id);
+	dev->id = id;
+
+	/* configure device according to the new ID */
+	return ata_dev_configure(ap, dev, 0);
+
+ fail:
+	printk(KERN_ERR "ata%u: dev %u revalidation failed (errno=%d)\n",
+	       ap->id, dev->devno, rc);
+	kfree(id);
+	return rc;
 }
 
 static const char * const ata_dma_blacklist [] = {
@@ -2237,151 +2584,57 @@
 
 static int ata_dma_blacklisted(const struct ata_device *dev)
 {
-	unsigned char model_num[40];
-	char *s;
-	unsigned int len;
+	unsigned char model_num[41];
 	int i;
 
-	ata_dev_id_string(dev->id, model_num, ATA_ID_PROD_OFS,
-			  sizeof(model_num));
-	s = &model_num[0];
-	len = strnlen(s, sizeof(model_num));
-
-	/* ATAPI specifies that empty space is blank-filled; remove blanks */
-	while ((len > 0) && (s[len - 1] == ' ')) {
-		len--;
-		s[len] = 0;
-	}
+	ata_id_c_string(dev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num));
 
 	for (i = 0; i < ARRAY_SIZE(ata_dma_blacklist); i++)
-		if (!strncmp(ata_dma_blacklist[i], s, len))
+		if (!strcmp(ata_dma_blacklist[i], model_num))
 			return 1;
 
 	return 0;
 }
 
-static unsigned int ata_get_mode_mask(const struct ata_port *ap, int shift)
-{
-	const struct ata_device *master, *slave;
-	unsigned int mask;
-
-	master = &ap->device[0];
-	slave = &ap->device[1];
-
-	assert (ata_dev_present(master) || ata_dev_present(slave));
-
-	if (shift == ATA_SHIFT_UDMA) {
-		mask = ap->udma_mask;
-		if (ata_dev_present(master)) {
-			mask &= (master->id[ATA_ID_UDMA_MODES] & 0xff);
-			if (ata_dma_blacklisted(master)) {
-				mask = 0;
-				ata_pr_blacklisted(ap, master);
-			}
-		}
-		if (ata_dev_present(slave)) {
-			mask &= (slave->id[ATA_ID_UDMA_MODES] & 0xff);
-			if (ata_dma_blacklisted(slave)) {
-				mask = 0;
-				ata_pr_blacklisted(ap, slave);
-			}
-		}
-	}
-	else if (shift == ATA_SHIFT_MWDMA) {
-		mask = ap->mwdma_mask;
-		if (ata_dev_present(master)) {
-			mask &= (master->id[ATA_ID_MWDMA_MODES] & 0x07);
-			if (ata_dma_blacklisted(master)) {
-				mask = 0;
-				ata_pr_blacklisted(ap, master);
-			}
-		}
-		if (ata_dev_present(slave)) {
-			mask &= (slave->id[ATA_ID_MWDMA_MODES] & 0x07);
-			if (ata_dma_blacklisted(slave)) {
-				mask = 0;
-				ata_pr_blacklisted(ap, slave);
-			}
-		}
-	}
-	else if (shift == ATA_SHIFT_PIO) {
-		mask = ap->pio_mask;
-		if (ata_dev_present(master)) {
-			/* spec doesn't return explicit support for
-			 * PIO0-2, so we fake it
-			 */
-			u16 tmp_mode = master->id[ATA_ID_PIO_MODES] & 0x03;
-			tmp_mode <<= 3;
-			tmp_mode |= 0x7;
-			mask &= tmp_mode;
-		}
-		if (ata_dev_present(slave)) {
-			/* spec doesn't return explicit support for
-			 * PIO0-2, so we fake it
-			 */
-			u16 tmp_mode = slave->id[ATA_ID_PIO_MODES] & 0x03;
-			tmp_mode <<= 3;
-			tmp_mode |= 0x7;
-			mask &= tmp_mode;
-		}
-	}
-	else {
-		mask = 0xffffffff; /* shut up compiler warning */
-		BUG();
-	}
-
-	return mask;
-}
-
-/* find greatest bit */
-static int fgb(u32 bitmap)
-{
-	unsigned int i;
-	int x = -1;
-
-	for (i = 0; i < 32; i++)
-		if (bitmap & (1 << i))
-			x = i;
-
-	return x;
-}
-
 /**
- *	ata_choose_xfer_mode - attempt to find best transfer mode
- *	@ap: Port for which an xfer mode will be selected
- *	@xfer_mode_out: (output) SET FEATURES - XFER MODE code
- *	@xfer_shift_out: (output) bit shift that selects this mode
+ *	ata_dev_xfermask - Compute supported xfermask of the given device
+ *	@ap: Port on which the device to compute xfermask for resides
+ *	@dev: Device to compute xfermask for
  *
- *	Based on host and device capabilities, determine the
- *	maximum transfer mode that is amenable to all.
+ *	Compute supported xfermask of @dev.  This function is
+ *	responsible for applying all known limits including host
+ *	controller limits, device blacklist, etc...
  *
  *	LOCKING:
- *	PCI/etc. bus probe sem.
+ *	None.
  *
  *	RETURNS:
- *	Zero on success, negative on error.
+ *	Computed xfermask.
  */
-
-static int ata_choose_xfer_mode(const struct ata_port *ap,
-				u8 *xfer_mode_out,
-				unsigned int *xfer_shift_out)
+static unsigned int ata_dev_xfermask(struct ata_port *ap,
+				     struct ata_device *dev)
 {
-	unsigned int mask, shift;
-	int x, i;
+	unsigned long xfer_mask;
+	int i;
 
-	for (i = 0; i < ARRAY_SIZE(xfer_mode_classes); i++) {
-		shift = xfer_mode_classes[i].shift;
-		mask = ata_get_mode_mask(ap, shift);
+	xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask,
+				      ap->udma_mask);
 
-		x = fgb(mask);
-		if (x >= 0) {
-			*xfer_mode_out = xfer_mode_classes[i].base + x;
-			*xfer_shift_out = shift;
-			return 0;
-		}
+	/* use port-wide xfermask for now */
+	for (i = 0; i < ATA_MAX_DEVICES; i++) {
+		struct ata_device *d = &ap->device[i];
+		if (!ata_dev_present(d))
+			continue;
+		xfer_mask &= ata_id_xfermask(d->id);
+		if (ata_dma_blacklisted(d))
+			xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
 	}
 
-	return -1;
+	if (ata_dma_blacklisted(dev))
+		printk(KERN_WARNING "ata%u: dev %u is on DMA blacklist, "
+		       "disabling DMA\n", ap->id, dev->devno);
+
+	return xfer_mask;
 }
 
 /**
@@ -2420,63 +2673,28 @@
 }
 
 /**
- *	ata_dev_reread_id - Reread the device identify device info
- *	@ap: port where the device is
- *	@dev: device to reread the identify device info
- *
- *	LOCKING:
- */
-
-static void ata_dev_reread_id(struct ata_port *ap, struct ata_device *dev)
-{
-	struct ata_taskfile tf;
-
-	ata_tf_init(ap, &tf, dev->devno);
-
-	if (dev->class == ATA_DEV_ATA) {
-		tf.command = ATA_CMD_ID_ATA;
-		DPRINTK("do ATA identify\n");
-	} else {
-		tf.command = ATA_CMD_ID_ATAPI;
-		DPRINTK("do ATAPI identify\n");
-	}
-
-	tf.flags |= ATA_TFLAG_DEVICE;
-	tf.protocol = ATA_PROT_PIO;
-
-	if (ata_exec_internal(ap, dev, &tf, DMA_FROM_DEVICE,
-			      dev->id, sizeof(dev->id)))
-		goto err_out;
-
-	swap_buf_le16(dev->id, ATA_ID_WORDS);
-
-	ata_dump_id(dev);
-
-	DPRINTK("EXIT\n");
-
-	return;
-err_out:
-	printk(KERN_ERR "ata%u: failed to reread ID, disabled\n", ap->id);
-	ata_port_disable(ap);
-}
-
-/**
  *	ata_dev_init_params - Issue INIT DEV PARAMS command
  *	@ap: Port associated with device @dev
  *	@dev: Device to which command will be sent
  *
  *	LOCKING:
+ *	Kernel thread context (may sleep)
+ *
+ *	RETURNS:
+ *	0 on success, AC_ERR_* mask otherwise.
  */
 
-static void ata_dev_init_params(struct ata_port *ap, struct ata_device *dev)
+static unsigned int ata_dev_init_params(struct ata_port *ap,
+					struct ata_device *dev)
 {
 	struct ata_taskfile tf;
+	unsigned int err_mask;
 	u16 sectors = dev->id[6];
 	u16 heads   = dev->id[3];
 
 	/* Number of sectors per track 1-255. Number of heads 1-16 */
 	if (sectors < 1 || sectors > 255 || heads < 1 || heads > 16)
-		return;
+		return 0;
 
 	/* set up init dev params taskfile */
 	DPRINTK("init dev params \n");
@@ -2488,13 +2706,10 @@
 	tf.nsect = sectors;
 	tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 1 */
 
-	if (ata_exec_internal(ap, dev, &tf, DMA_NONE, NULL, 0)) {
-		printk(KERN_ERR "ata%u: failed to init parameters, disabled\n",
-		       ap->id);
-		ata_port_disable(ap);
-	}
+	err_mask = ata_exec_internal(ap, dev, &tf, DMA_NONE, NULL, 0);
 
-	DPRINTK("EXIT\n");
+	DPRINTK("EXIT, err_mask=%x\n", err_mask);
+	return err_mask;
 }
 
 /**
@@ -2514,11 +2729,11 @@
 	int dir = qc->dma_dir;
 	void *pad_buf = NULL;
 
-	assert(qc->flags & ATA_QCFLAG_DMAMAP);
-	assert(sg != NULL);
+	WARN_ON(!(qc->flags & ATA_QCFLAG_DMAMAP));
+	WARN_ON(sg == NULL);
 
 	if (qc->flags & ATA_QCFLAG_SINGLE)
-		assert(qc->n_elem <= 1);
+		WARN_ON(qc->n_elem > 1);
 
 	VPRINTK("unmapping %u sg elements\n", qc->n_elem);
 
@@ -2573,8 +2788,8 @@
 	struct scatterlist *sg;
 	unsigned int idx;
 
-	assert(qc->__sg != NULL);
-	assert(qc->n_elem > 0 || qc->pad_len > 0);
+	WARN_ON(qc->__sg == NULL);
+	WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
 
 	idx = 0;
 	ata_for_each_sg(sg, qc) {
@@ -2727,7 +2942,7 @@
 		void *pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ);
 		struct scatterlist *psg = &qc->pad_sgent;
 
-		assert(qc->dev->class == ATA_DEV_ATAPI);
+		WARN_ON(qc->dev->class != ATA_DEV_ATAPI);
 
 		memset(pad_buf, 0, ATA_DMA_PAD_SZ);
 
@@ -2791,7 +3006,7 @@
 	int n_elem, pre_n_elem, dir, trim_sg = 0;
 
 	VPRINTK("ENTER, ata%u\n", ap->id);
-	assert(qc->flags & ATA_QCFLAG_SG);
+	WARN_ON(!(qc->flags & ATA_QCFLAG_SG));
 
 	/* we must lengthen transfers to end on a 32-bit boundary */
 	qc->pad_len = lsg->length & 3;
@@ -2800,7 +3015,7 @@
 		struct scatterlist *psg = &qc->pad_sgent;
 		unsigned int offset;
 
-		assert(qc->dev->class == ATA_DEV_ATAPI);
+		WARN_ON(qc->dev->class != ATA_DEV_ATAPI);
 
 		memset(pad_buf, 0, ATA_DMA_PAD_SZ);
 
@@ -2876,7 +3091,7 @@
 }
 
 /**
- *	ata_pio_poll -
+ *	ata_pio_poll - poll using PIO, depending on current state
  *	@ap: the target ata_port
  *
  *	LOCKING:
@@ -2894,7 +3109,7 @@
 	unsigned int reg_state = HSM_ST_UNKNOWN;
 
 	qc = ata_qc_from_tag(ap, ap->active_tag);
-	assert(qc != NULL);
+	WARN_ON(qc == NULL);
 
 	switch (ap->hsm_task_state) {
 	case HSM_ST:
@@ -2915,7 +3130,7 @@
 	status = ata_chk_status(ap);
 	if (status & ATA_BUSY) {
 		if (time_after(jiffies, ap->pio_task_timeout)) {
-			qc->err_mask |= AC_ERR_ATA_BUS;
+			qc->err_mask |= AC_ERR_TIMEOUT;
 			ap->hsm_task_state = HSM_ST_TMOUT;
 			return 0;
 		}
@@ -2962,7 +3177,7 @@
 	}
 
 	qc = ata_qc_from_tag(ap, ap->active_tag);
-	assert(qc != NULL);
+	WARN_ON(qc == NULL);
 
 	drv_stat = ata_wait_idle(ap);
 	if (!ata_ok(drv_stat)) {
@@ -2973,7 +3188,7 @@
 
 	ap->hsm_task_state = HSM_ST_IDLE;
 
-	assert(qc->err_mask == 0);
+	WARN_ON(qc->err_mask);
 	ata_poll_qc_complete(qc);
 
 	/* another command may start at this point */
@@ -2983,7 +3198,7 @@
 
 
 /**
- *	swap_buf_le16 - swap halves of 16-words in place
+ *	swap_buf_le16 - swap halves of 16-bit words in place
  *	@buf:  Buffer to swap
  *	@buf_words:  Number of 16-bit words in buffer.
  *
@@ -3293,7 +3508,7 @@
 err_out:
 	printk(KERN_INFO "ata%u: dev %u: ATAPI check failed\n",
 	      ap->id, dev->devno);
-	qc->err_mask |= AC_ERR_ATA_BUS;
+	qc->err_mask |= AC_ERR_HSM;
 	ap->hsm_task_state = HSM_ST_ERR;
 }
 
@@ -3330,7 +3545,7 @@
 	}
 
 	qc = ata_qc_from_tag(ap, ap->active_tag);
-	assert(qc != NULL);
+	WARN_ON(qc == NULL);
 
 	/* check error */
 	if (status & (ATA_ERR | ATA_DF)) {
@@ -3351,7 +3566,7 @@
 	} else {
 		/* handle BSY=0, DRQ=0 as error */
 		if ((status & ATA_DRQ) == 0) {
-			qc->err_mask |= AC_ERR_ATA_BUS;
+			qc->err_mask |= AC_ERR_HSM;
 			ap->hsm_task_state = HSM_ST_ERR;
 			return;
 		}
@@ -3365,7 +3580,7 @@
 	struct ata_queued_cmd *qc;
 
 	qc = ata_qc_from_tag(ap, ap->active_tag);
-	assert(qc != NULL);
+	WARN_ON(qc == NULL);
 
 	if (qc->tf.command != ATA_CMD_PACKET)
 		printk(KERN_WARNING "ata%u: PIO error\n", ap->id);
@@ -3373,7 +3588,7 @@
 	/* make sure qc->err_mask is available to 
 	 * know what's wrong and recover
 	 */
-	assert(qc->err_mask);
+	WARN_ON(qc->err_mask == 0);
 
 	ap->hsm_task_state = HSM_ST_IDLE;
 
@@ -3414,12 +3629,84 @@
 	}
 
 	if (timeout)
-		queue_delayed_work(ata_wq, &ap->pio_task, timeout);
+		ata_port_queue_task(ap, ata_pio_task, ap, timeout);
 	else if (!qc_completed)
 		goto fsm_start;
 }
 
 /**
+ *	atapi_packet_task - Write CDB bytes to hardware
+ *	@_data: Port to which ATAPI device is attached.
+ *
+ *	When device has indicated its readiness to accept
+ *	a CDB, this function is called.  Send the CDB.
+ *	If DMA is to be performed, exit immediately.
+ *	Otherwise, we are in polling mode, so poll
+ *	status under operation succeeds or fails.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep)
+ */
+
+static void atapi_packet_task(void *_data)
+{
+	struct ata_port *ap = _data;
+	struct ata_queued_cmd *qc;
+	u8 status;
+
+	qc = ata_qc_from_tag(ap, ap->active_tag);
+	WARN_ON(qc == NULL);
+	WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
+
+	/* sleep-wait for BSY to clear */
+	DPRINTK("busy wait\n");
+	if (ata_busy_sleep(ap, ATA_TMOUT_CDB_QUICK, ATA_TMOUT_CDB)) {
+		qc->err_mask |= AC_ERR_TIMEOUT;
+		goto err_out;
+	}
+
+	/* make sure DRQ is set */
+	status = ata_chk_status(ap);
+	if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ) {
+		qc->err_mask |= AC_ERR_HSM;
+		goto err_out;
+	}
+
+	/* send SCSI cdb */
+	DPRINTK("send cdb\n");
+	WARN_ON(qc->dev->cdb_len < 12);
+
+	if (qc->tf.protocol == ATA_PROT_ATAPI_DMA ||
+	    qc->tf.protocol == ATA_PROT_ATAPI_NODATA) {
+		unsigned long flags;
+
+		/* Once we're done issuing command and kicking bmdma,
+		 * irq handler takes over.  To not lose irq, we need
+		 * to clear NOINTR flag before sending cdb, but
+		 * interrupt handler shouldn't be invoked before we're
+		 * finished.  Hence, the following locking.
+		 */
+		spin_lock_irqsave(&ap->host_set->lock, flags);
+		ap->flags &= ~ATA_FLAG_NOINTR;
+		ata_data_xfer(ap, qc->cdb, qc->dev->cdb_len, 1);
+		if (qc->tf.protocol == ATA_PROT_ATAPI_DMA)
+			ap->ops->bmdma_start(qc);	/* initiate bmdma */
+		spin_unlock_irqrestore(&ap->host_set->lock, flags);
+	} else {
+		ata_data_xfer(ap, qc->cdb, qc->dev->cdb_len, 1);
+
+		/* PIO commands are handled by polling */
+		ap->hsm_task_state = HSM_ST;
+		ata_port_queue_task(ap, ata_pio_task, ap, 0);
+	}
+
+	return;
+
+err_out:
+	ata_poll_qc_complete(qc);
+}
+
+/**
  *	ata_qc_timeout - Handle timeout of queued command
  *	@qc: Command that timed out
  *
@@ -3447,15 +3734,9 @@
 
 	DPRINTK("ENTER\n");
 
-	spin_lock_irqsave(&host_set->lock, flags);
+	ap->hsm_task_state = HSM_ST_IDLE;
 
-	/* hack alert!  We cannot use the supplied completion
-	 * function from inside the ->eh_strategy_handler() thread.
-	 * libata is the only user of ->eh_strategy_handler() in
-	 * any kernel, so the default scsi_done() assumes it is
-	 * not being called from the SCSI EH.
-	 */
-	qc->scsidone = scsi_finish_command;
+	spin_lock_irqsave(&host_set->lock, flags);
 
 	switch (qc->tf.protocol) {
 
@@ -3480,12 +3761,13 @@
 
 		/* complete taskfile transaction */
 		qc->err_mask |= ac_err_mask(drv_stat);
-		ata_qc_complete(qc);
 		break;
 	}
 
 	spin_unlock_irqrestore(&host_set->lock, flags);
 
+	ata_eh_qc_complete(qc);
+
 	DPRINTK("EXIT\n");
 }
 
@@ -3510,20 +3792,10 @@
 
 void ata_eng_timeout(struct ata_port *ap)
 {
-	struct ata_queued_cmd *qc;
-
 	DPRINTK("ENTER\n");
 
-	qc = ata_qc_from_tag(ap, ap->active_tag);
-	if (qc)
-		ata_qc_timeout(qc);
-	else {
-		printk(KERN_ERR "ata%u: BUG: timeout without command\n",
-		       ap->id);
-		goto out;
-	}
+	ata_qc_timeout(ata_qc_from_tag(ap, ap->active_tag));
 
-out:
 	DPRINTK("EXIT\n");
 }
 
@@ -3579,21 +3851,6 @@
 	return qc;
 }
 
-static void __ata_qc_complete(struct ata_queued_cmd *qc)
-{
-	struct ata_port *ap = qc->ap;
-	unsigned int tag;
-
-	qc->flags = 0;
-	tag = qc->tag;
-	if (likely(ata_tag_valid(tag))) {
-		if (tag == ap->active_tag)
-			ap->active_tag = ATA_TAG_POISON;
-		qc->tag = ATA_TAG_POISON;
-		clear_bit(tag, &ap->qactive);
-	}
-}
-
 /**
  *	ata_qc_free - free unused ata_queued_cmd
  *	@qc: Command to complete
@@ -3606,29 +3863,25 @@
  */
 void ata_qc_free(struct ata_queued_cmd *qc)
 {
-	assert(qc != NULL);	/* ata_qc_from_tag _might_ return NULL */
+	struct ata_port *ap = qc->ap;
+	unsigned int tag;
 
-	__ata_qc_complete(qc);
+	WARN_ON(qc == NULL);	/* ata_qc_from_tag _might_ return NULL */
+
+	qc->flags = 0;
+	tag = qc->tag;
+	if (likely(ata_tag_valid(tag))) {
+		if (tag == ap->active_tag)
+			ap->active_tag = ATA_TAG_POISON;
+		qc->tag = ATA_TAG_POISON;
+		clear_bit(tag, &ap->qactive);
+	}
 }
 
-/**
- *	ata_qc_complete - Complete an active ATA command
- *	@qc: Command to complete
- *	@err_mask: ATA Status register contents
- *
- *	Indicate to the mid and upper layers that an ATA
- *	command has completed, with either an ok or not-ok status.
- *
- *	LOCKING:
- *	spin_lock_irqsave(host_set lock)
- */
-
-void ata_qc_complete(struct ata_queued_cmd *qc)
+void __ata_qc_complete(struct ata_queued_cmd *qc)
 {
-	int rc;
-
-	assert(qc != NULL);	/* ata_qc_from_tag _might_ return NULL */
-	assert(qc->flags & ATA_QCFLAG_ACTIVE);
+	WARN_ON(qc == NULL);	/* ata_qc_from_tag _might_ return NULL */
+	WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
 
 	if (likely(qc->flags & ATA_QCFLAG_DMAMAP))
 		ata_sg_clean(qc);
@@ -3640,17 +3893,7 @@
 	qc->flags &= ~ATA_QCFLAG_ACTIVE;
 
 	/* call completion callback */
-	rc = qc->complete_fn(qc);
-
-	/* if callback indicates not to complete command (non-zero),
-	 * return immediately
-	 */
-	if (rc != 0)
-		return;
-
-	__ata_qc_complete(qc);
-
-	VPRINTK("EXIT\n");
+	qc->complete_fn(qc);
 }
 
 static inline int ata_should_dma_map(struct ata_queued_cmd *qc)
@@ -3690,20 +3933,20 @@
  *	spin_lock_irqsave(host_set lock)
  *
  *	RETURNS:
- *	Zero on success, negative on error.
+ *	Zero on success, AC_ERR_* mask on failure
  */
 
-int ata_qc_issue(struct ata_queued_cmd *qc)
+unsigned int ata_qc_issue(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
 
 	if (ata_should_dma_map(qc)) {
 		if (qc->flags & ATA_QCFLAG_SG) {
 			if (ata_sg_setup(qc))
-				goto err_out;
+				goto sg_err;
 		} else if (qc->flags & ATA_QCFLAG_SINGLE) {
 			if (ata_sg_setup_one(qc))
-				goto err_out;
+				goto sg_err;
 		}
 	} else {
 		qc->flags &= ~ATA_QCFLAG_DMAMAP;
@@ -3716,8 +3959,9 @@
 
 	return ap->ops->qc_issue(qc);
 
-err_out:
-	return -1;
+sg_err:
+	qc->flags &= ~ATA_QCFLAG_DMAMAP;
+	return AC_ERR_SYSTEM;
 }
 
 
@@ -3736,10 +3980,10 @@
  *	spin_lock_irqsave(host_set lock)
  *
  *	RETURNS:
- *	Zero on success, negative on error.
+ *	Zero on success, AC_ERR_* mask on failure
  */
 
-int ata_qc_issue_prot(struct ata_queued_cmd *qc)
+unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
 
@@ -3760,31 +4004,31 @@
 		ata_qc_set_polling(qc);
 		ata_tf_to_host(ap, &qc->tf);
 		ap->hsm_task_state = HSM_ST;
-		queue_work(ata_wq, &ap->pio_task);
+		ata_port_queue_task(ap, ata_pio_task, ap, 0);
 		break;
 
 	case ATA_PROT_ATAPI:
 		ata_qc_set_polling(qc);
 		ata_tf_to_host(ap, &qc->tf);
-		queue_work(ata_wq, &ap->packet_task);
+		ata_port_queue_task(ap, atapi_packet_task, ap, 0);
 		break;
 
 	case ATA_PROT_ATAPI_NODATA:
 		ap->flags |= ATA_FLAG_NOINTR;
 		ata_tf_to_host(ap, &qc->tf);
-		queue_work(ata_wq, &ap->packet_task);
+		ata_port_queue_task(ap, atapi_packet_task, ap, 0);
 		break;
 
 	case ATA_PROT_ATAPI_DMA:
 		ap->flags |= ATA_FLAG_NOINTR;
 		ap->ops->tf_load(ap, &qc->tf);	 /* load tf registers */
 		ap->ops->bmdma_setup(qc);	    /* set up bmdma */
-		queue_work(ata_wq, &ap->packet_task);
+		ata_port_queue_task(ap, atapi_packet_task, ap, 0);
 		break;
 
 	default:
 		WARN_ON(1);
-		return -1;
+		return AC_ERR_SYSTEM;
 	}
 
 	return 0;
@@ -4147,91 +4391,6 @@
 	return IRQ_RETVAL(handled);
 }
 
-/**
- *	atapi_packet_task - Write CDB bytes to hardware
- *	@_data: Port to which ATAPI device is attached.
- *
- *	When device has indicated its readiness to accept
- *	a CDB, this function is called.  Send the CDB.
- *	If DMA is to be performed, exit immediately.
- *	Otherwise, we are in polling mode, so poll
- *	status under operation succeeds or fails.
- *
- *	LOCKING:
- *	Kernel thread context (may sleep)
- */
-
-static void atapi_packet_task(void *_data)
-{
-	struct ata_port *ap = _data;
-	struct ata_queued_cmd *qc;
-	u8 status;
-
-	qc = ata_qc_from_tag(ap, ap->active_tag);
-	assert(qc != NULL);
-	assert(qc->flags & ATA_QCFLAG_ACTIVE);
-
-	/* sleep-wait for BSY to clear */
-	DPRINTK("busy wait\n");
-	if (ata_busy_sleep(ap, ATA_TMOUT_CDB_QUICK, ATA_TMOUT_CDB)) {
-		qc->err_mask |= AC_ERR_ATA_BUS;
-		goto err_out;
-	}
-
-	/* make sure DRQ is set */
-	status = ata_chk_status(ap);
-	if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ) {
-		qc->err_mask |= AC_ERR_ATA_BUS;
-		goto err_out;
-	}
-
-	/* send SCSI cdb */
-	DPRINTK("send cdb\n");
-	assert(ap->cdb_len >= 12);
-
-	if (qc->tf.protocol == ATA_PROT_ATAPI_DMA ||
-	    qc->tf.protocol == ATA_PROT_ATAPI_NODATA) {
-		unsigned long flags;
-
-		/* Once we're done issuing command and kicking bmdma,
-		 * irq handler takes over.  To not lose irq, we need
-		 * to clear NOINTR flag before sending cdb, but
-		 * interrupt handler shouldn't be invoked before we're
-		 * finished.  Hence, the following locking.
-		 */
-		spin_lock_irqsave(&ap->host_set->lock, flags);
-		ap->flags &= ~ATA_FLAG_NOINTR;
-		ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1);
-		if (qc->tf.protocol == ATA_PROT_ATAPI_DMA)
-			ap->ops->bmdma_start(qc);	/* initiate bmdma */
-		spin_unlock_irqrestore(&ap->host_set->lock, flags);
-	} else {
-		ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1);
-
-		/* PIO commands are handled by polling */
-		ap->hsm_task_state = HSM_ST;
-		queue_work(ata_wq, &ap->pio_task);
-	}
-
-	return;
-
-err_out:
-	ata_poll_qc_complete(qc);
-}
-
-
-/**
- *	ata_port_start - Set port up for dma.
- *	@ap: Port to initialize
- *
- *	Called just after data structures for each port are
- *	initialized.  Allocates space for PRD table.
- *
- *	May be used as the port_start() entry in ata_port_operations.
- *
- *	LOCKING:
- *	Inherited from caller.
- */
 
 /*
  * Execute a 'simple' command, that only consists of the opcode 'cmd' itself,
@@ -4284,6 +4443,8 @@
 
 /**
  *	ata_device_resume - wakeup a previously suspended devices
+ *	@ap: port the device is connected to
+ *	@dev: the device to resume
  *
  *	Kick the drive back into action, by sending it an idle immediate
  *	command and making sure its transfer mode matches between drive
@@ -4306,10 +4467,11 @@
 
 /**
  *	ata_device_suspend - prepare a device for suspend
+ *	@ap: port the device is connected to
+ *	@dev: the device to suspend
  *
  *	Flush the cache on the drive, if appropriate, then issue a
  *	standbynow command.
- *
  */
 int ata_device_suspend(struct ata_port *ap, struct ata_device *dev)
 {
@@ -4323,6 +4485,19 @@
 	return 0;
 }
 
+/**
+ *	ata_port_start - Set port up for dma.
+ *	@ap: Port to initialize
+ *
+ *	Called just after data structures for each port are
+ *	initialized.  Allocates space for PRD table.
+ *
+ *	May be used as the port_start() entry in ata_port_operations.
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+
 int ata_port_start (struct ata_port *ap)
 {
 	struct device *dev = ap->host_set->dev;
@@ -4436,8 +4611,8 @@
 	ap->active_tag = ATA_TAG_POISON;
 	ap->last_ctl = 0xFF;
 
-	INIT_WORK(&ap->packet_task, atapi_packet_task, ap);
-	INIT_WORK(&ap->pio_task, ata_pio_task, ap);
+	INIT_WORK(&ap->port_task, NULL, NULL);
+	INIT_LIST_HEAD(&ap->eh_done_q);
 
 	for (i = 0; i < ATA_MAX_DEVICES; i++)
 		ap->device[i].devno = i;
@@ -4579,9 +4754,9 @@
 
 		ap = host_set->ports[i];
 
-		DPRINTK("ata%u: probe begin\n", ap->id);
+		DPRINTK("ata%u: bus probe begin\n", ap->id);
 		rc = ata_bus_probe(ap);
-		DPRINTK("ata%u: probe end\n", ap->id);
+		DPRINTK("ata%u: bus probe end\n", ap->id);
 
 		if (rc) {
 			/* FIXME: do something useful here?
@@ -4605,7 +4780,7 @@
 	}
 
 	/* probes are done, now scan each port's disk(s) */
-	DPRINTK("probe begin\n");
+	DPRINTK("host probe begin\n");
 	for (i = 0; i < count; i++) {
 		struct ata_port *ap = host_set->ports[i];
 
@@ -4691,11 +4866,14 @@
 int ata_scsi_release(struct Scsi_Host *host)
 {
 	struct ata_port *ap = (struct ata_port *) &host->hostdata[0];
+	int i;
 
 	DPRINTK("ENTER\n");
 
 	ap->ops->port_disable(ap);
 	ata_host_remove(ap, 0);
+	for (i = 0; i < ATA_MAX_DEVICES; i++)
+		kfree(ap->device[i].id);
 
 	DPRINTK("EXIT\n");
 	return 1;
@@ -4727,32 +4905,6 @@
 	ioaddr->command_addr = ioaddr->cmd_addr + ATA_REG_CMD;
 }
 
-static struct ata_probe_ent *
-ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port)
-{
-	struct ata_probe_ent *probe_ent;
-
-	probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
-	if (!probe_ent) {
-		printk(KERN_ERR DRV_NAME "(%s): out of memory\n",
-		       kobject_name(&(dev->kobj)));
-		return NULL;
-	}
-
-	INIT_LIST_HEAD(&probe_ent->node);
-	probe_ent->dev = dev;
-
-	probe_ent->sht = port->sht;
-	probe_ent->host_flags = port->host_flags;
-	probe_ent->pio_mask = port->pio_mask;
-	probe_ent->mwdma_mask = port->mwdma_mask;
-	probe_ent->udma_mask = port->udma_mask;
-	probe_ent->port_ops = port->port_ops;
-
-	return probe_ent;
-}
-
-
 
 #ifdef CONFIG_PCI
 
@@ -4764,256 +4916,6 @@
 }
 
 /**
- *	ata_pci_init_native_mode - Initialize native-mode driver
- *	@pdev:  pci device to be initialized
- *	@port:  array[2] of pointers to port info structures.
- *	@ports: bitmap of ports present
- *
- *	Utility function which allocates and initializes an
- *	ata_probe_ent structure for a standard dual-port
- *	PIO-based IDE controller.  The returned ata_probe_ent
- *	structure can be passed to ata_device_add().  The returned
- *	ata_probe_ent structure should then be freed with kfree().
- *
- *	The caller need only pass the address of the primary port, the
- *	secondary will be deduced automatically. If the device has non
- *	standard secondary port mappings this function can be called twice,
- *	once for each interface.
- */
-
-struct ata_probe_ent *
-ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int ports)
-{
-	struct ata_probe_ent *probe_ent =
-		ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
-	int p = 0;
-
-	if (!probe_ent)
-		return NULL;
-
-	probe_ent->irq = pdev->irq;
-	probe_ent->irq_flags = SA_SHIRQ;
-	probe_ent->private_data = port[0]->private_data;
-
-	if (ports & ATA_PORT_PRIMARY) {
-		probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 0);
-		probe_ent->port[p].altstatus_addr =
-		probe_ent->port[p].ctl_addr =
-			pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS;
-		probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4);
-		ata_std_ports(&probe_ent->port[p]);
-		p++;
-	}
-
-	if (ports & ATA_PORT_SECONDARY) {
-		probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 2);
-		probe_ent->port[p].altstatus_addr =
-		probe_ent->port[p].ctl_addr =
-			pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS;
-		probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4) + 8;
-		ata_std_ports(&probe_ent->port[p]);
-		p++;
-	}
-
-	probe_ent->n_ports = p;
-	return probe_ent;
-}
-
-static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev, struct ata_port_info *port, int port_num)
-{
-	struct ata_probe_ent *probe_ent;
-
-	probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port);
-	if (!probe_ent)
-		return NULL;
-
-	probe_ent->legacy_mode = 1;
-	probe_ent->n_ports = 1;
-	probe_ent->hard_port_no = port_num;
-	probe_ent->private_data = port->private_data;
-
-	switch(port_num)
-	{
-		case 0:
-			probe_ent->irq = 14;
-			probe_ent->port[0].cmd_addr = 0x1f0;
-			probe_ent->port[0].altstatus_addr =
-			probe_ent->port[0].ctl_addr = 0x3f6;
-			break;
-		case 1:
-			probe_ent->irq = 15;
-			probe_ent->port[0].cmd_addr = 0x170;
-			probe_ent->port[0].altstatus_addr =
-			probe_ent->port[0].ctl_addr = 0x376;
-			break;
-	}
-	probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4) + 8 * port_num;
-	ata_std_ports(&probe_ent->port[0]);
-	return probe_ent;
-}
-
-/**
- *	ata_pci_init_one - Initialize/register PCI IDE host controller
- *	@pdev: Controller to be initialized
- *	@port_info: Information from low-level host driver
- *	@n_ports: Number of ports attached to host controller
- *
- *	This is a helper function which can be called from a driver's
- *	xxx_init_one() probe function if the hardware uses traditional
- *	IDE taskfile registers.
- *
- *	This function calls pci_enable_device(), reserves its register
- *	regions, sets the dma mask, enables bus master mode, and calls
- *	ata_device_add()
- *
- *	LOCKING:
- *	Inherited from PCI layer (may sleep).
- *
- *	RETURNS:
- *	Zero on success, negative on errno-based value on error.
- */
-
-int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
-		      unsigned int n_ports)
-{
-	struct ata_probe_ent *probe_ent = NULL, *probe_ent2 = NULL;
-	struct ata_port_info *port[2];
-	u8 tmp8, mask;
-	unsigned int legacy_mode = 0;
-	int disable_dev_on_err = 1;
-	int rc;
-
-	DPRINTK("ENTER\n");
-
-	port[0] = port_info[0];
-	if (n_ports > 1)
-		port[1] = port_info[1];
-	else
-		port[1] = port[0];
-
-	if ((port[0]->host_flags & ATA_FLAG_NO_LEGACY) == 0
-	    && (pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
-		/* TODO: What if one channel is in native mode ... */
-		pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8);
-		mask = (1 << 2) | (1 << 0);
-		if ((tmp8 & mask) != mask)
-			legacy_mode = (1 << 3);
-	}
-
-	/* FIXME... */
-	if ((!legacy_mode) && (n_ports > 2)) {
-		printk(KERN_ERR "ata: BUG: native mode, n_ports > 2\n");
-		n_ports = 2;
-		/* For now */
-	}
-
-	/* FIXME: Really for ATA it isn't safe because the device may be
-	   multi-purpose and we want to leave it alone if it was already
-	   enabled. Secondly for shared use as Arjan says we want refcounting
-	   
-	   Checking dev->is_enabled is insufficient as this is not set at
-	   boot for the primary video which is BIOS enabled
-         */
-         
-	rc = pci_enable_device(pdev);
-	if (rc)
-		return rc;
-
-	rc = pci_request_regions(pdev, DRV_NAME);
-	if (rc) {
-		disable_dev_on_err = 0;
-		goto err_out;
-	}
-
-	/* FIXME: Should use platform specific mappers for legacy port ranges */
-	if (legacy_mode) {
-		if (!request_region(0x1f0, 8, "libata")) {
-			struct resource *conflict, res;
-			res.start = 0x1f0;
-			res.end = 0x1f0 + 8 - 1;
-			conflict = ____request_resource(&ioport_resource, &res);
-			if (!strcmp(conflict->name, "libata"))
-				legacy_mode |= (1 << 0);
-			else {
-				disable_dev_on_err = 0;
-				printk(KERN_WARNING "ata: 0x1f0 IDE port busy\n");
-			}
-		} else
-			legacy_mode |= (1 << 0);
-
-		if (!request_region(0x170, 8, "libata")) {
-			struct resource *conflict, res;
-			res.start = 0x170;
-			res.end = 0x170 + 8 - 1;
-			conflict = ____request_resource(&ioport_resource, &res);
-			if (!strcmp(conflict->name, "libata"))
-				legacy_mode |= (1 << 1);
-			else {
-				disable_dev_on_err = 0;
-				printk(KERN_WARNING "ata: 0x170 IDE port busy\n");
-			}
-		} else
-			legacy_mode |= (1 << 1);
-	}
-
-	/* we have legacy mode, but all ports are unavailable */
-	if (legacy_mode == (1 << 3)) {
-		rc = -EBUSY;
-		goto err_out_regions;
-	}
-
-	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
-	if (rc)
-		goto err_out_regions;
-	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
-	if (rc)
-		goto err_out_regions;
-
-	if (legacy_mode) {
-		if (legacy_mode & (1 << 0))
-			probe_ent = ata_pci_init_legacy_port(pdev, port[0], 0);
-		if (legacy_mode & (1 << 1))
-			probe_ent2 = ata_pci_init_legacy_port(pdev, port[1], 1);
-	} else {
-		if (n_ports == 2)
-			probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
-		else
-			probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY);
-	}
-	if (!probe_ent && !probe_ent2) {
-		rc = -ENOMEM;
-		goto err_out_regions;
-	}
-
-	pci_set_master(pdev);
-
-	/* FIXME: check ata_device_add return */
-	if (legacy_mode) {
-		if (legacy_mode & (1 << 0))
-			ata_device_add(probe_ent);
-		if (legacy_mode & (1 << 1))
-			ata_device_add(probe_ent2);
-	} else
-		ata_device_add(probe_ent);
-
-	kfree(probe_ent);
-	kfree(probe_ent2);
-
-	return 0;
-
-err_out_regions:
-	if (legacy_mode & (1 << 0))
-		release_region(0x1f0, 8);
-	if (legacy_mode & (1 << 1))
-		release_region(0x170, 8);
-	pci_release_regions(pdev);
-err_out:
-	if (disable_dev_on_err)
-		pci_disable_device(pdev);
-	return rc;
-}
-
-/**
  *	ata_pci_remove_one - PCI layer callback for device removal
  *	@pdev: PCI device that was removed
  *
@@ -5143,7 +5045,7 @@
 EXPORT_SYMBOL_GPL(ata_host_set_remove);
 EXPORT_SYMBOL_GPL(ata_sg_init);
 EXPORT_SYMBOL_GPL(ata_sg_init_one);
-EXPORT_SYMBOL_GPL(ata_qc_complete);
+EXPORT_SYMBOL_GPL(__ata_qc_complete);
 EXPORT_SYMBOL_GPL(ata_qc_issue_prot);
 EXPORT_SYMBOL_GPL(ata_eng_timeout);
 EXPORT_SYMBOL_GPL(ata_tf_load);
@@ -5169,18 +5071,30 @@
 EXPORT_SYMBOL_GPL(sata_phy_reset);
 EXPORT_SYMBOL_GPL(__sata_phy_reset);
 EXPORT_SYMBOL_GPL(ata_bus_reset);
+EXPORT_SYMBOL_GPL(ata_std_probeinit);
+EXPORT_SYMBOL_GPL(ata_std_softreset);
+EXPORT_SYMBOL_GPL(sata_std_hardreset);
+EXPORT_SYMBOL_GPL(ata_std_postreset);
+EXPORT_SYMBOL_GPL(ata_std_probe_reset);
+EXPORT_SYMBOL_GPL(ata_drive_probe_reset);
+EXPORT_SYMBOL_GPL(ata_dev_revalidate);
 EXPORT_SYMBOL_GPL(ata_port_disable);
 EXPORT_SYMBOL_GPL(ata_ratelimit);
+EXPORT_SYMBOL_GPL(ata_busy_sleep);
+EXPORT_SYMBOL_GPL(ata_port_queue_task);
 EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
 EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
+EXPORT_SYMBOL_GPL(ata_scsi_timed_out);
 EXPORT_SYMBOL_GPL(ata_scsi_error);
 EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
 EXPORT_SYMBOL_GPL(ata_scsi_release);
 EXPORT_SYMBOL_GPL(ata_host_intr);
 EXPORT_SYMBOL_GPL(ata_dev_classify);
-EXPORT_SYMBOL_GPL(ata_dev_id_string);
-EXPORT_SYMBOL_GPL(ata_dev_config);
+EXPORT_SYMBOL_GPL(ata_id_string);
+EXPORT_SYMBOL_GPL(ata_id_c_string);
 EXPORT_SYMBOL_GPL(ata_scsi_simulate);
+EXPORT_SYMBOL_GPL(ata_eh_qc_complete);
+EXPORT_SYMBOL_GPL(ata_eh_qc_retry);
 
 EXPORT_SYMBOL_GPL(ata_pio_need_iordy);
 EXPORT_SYMBOL_GPL(ata_timing_compute);
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index 59503c9..ccedb45 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -151,7 +151,7 @@
 	struct scsi_sense_hdr sshdr;
 	enum dma_data_direction data_dir;
 
-	if (NULL == (void *)arg)
+	if (arg == NULL)
 		return -EINVAL;
 
 	if (copy_from_user(args, arg, sizeof(args)))
@@ -201,7 +201,7 @@
 	/* Need code to retrieve data from check condition? */
 
 	if ((argbuf)
-	 && copy_to_user((void *)(arg + sizeof(args)), argbuf, argsize))
+	 && copy_to_user(arg + sizeof(args), argbuf, argsize))
 		rc = -EFAULT;
 error:
 	if (argbuf)
@@ -228,7 +228,7 @@
 	u8 args[7];
 	struct scsi_sense_hdr sshdr;
 
-	if (NULL == (void *)arg)
+	if (arg == NULL)
 		return -EINVAL;
 
 	if (copy_from_user(args, arg, sizeof(args)))
@@ -553,7 +553,7 @@
 	/*
 	 * Read the controller registers.
 	 */
-	assert(NULL != qc->ap->ops->tf_read);
+	WARN_ON(qc->ap->ops->tf_read == NULL);
 	qc->ap->ops->tf_read(qc->ap, tf);
 
 	/*
@@ -628,7 +628,7 @@
 	/*
 	 * Read the controller registers.
 	 */
-	assert(NULL != qc->ap->ops->tf_read);
+	WARN_ON(qc->ap->ops->tf_read == NULL);
 	qc->ap->ops->tf_read(qc->ap, tf);
 
 	/*
@@ -684,23 +684,23 @@
 	if (sdev->id < ATA_MAX_DEVICES) {
 		struct ata_port *ap;
 		struct ata_device *dev;
+		unsigned int max_sectors;
 
 		ap = (struct ata_port *) &sdev->host->hostdata[0];
 		dev = &ap->device[sdev->id];
 
-		/* TODO: 1024 is an arbitrary number, not the
+		/* TODO: 2048 is an arbitrary number, not the
 		 * hardware maximum.  This should be increased to
 		 * 65534 when Jens Axboe's patch for dynamically
 		 * determining max_sectors is merged.
 		 */
-		if ((dev->flags & ATA_DFLAG_LBA48) &&
-		    ((dev->flags & ATA_DFLAG_LOCK_SECTORS) == 0)) {
-			/*
-			 * do not overwrite sdev->host->max_sectors, since
-			 * other drives on this host may not support LBA48
-			 */
-			blk_queue_max_sectors(sdev->request_queue, 2048);
-		}
+		max_sectors = ATA_MAX_SECTORS;
+		if (dev->flags & ATA_DFLAG_LBA48)
+			max_sectors = 2048;
+		if (dev->max_sectors)
+			max_sectors = dev->max_sectors;
+
+		blk_queue_max_sectors(sdev->request_queue, max_sectors);
 
 		/*
 		 * SATA DMA transfers must be multiples of 4 byte, so
@@ -717,6 +717,47 @@
 }
 
 /**
+ *	ata_scsi_timed_out - SCSI layer time out callback
+ *	@cmd: timed out SCSI command
+ *
+ *	Handles SCSI layer timeout.  We race with normal completion of
+ *	the qc for @cmd.  If the qc is already gone, we lose and let
+ *	the scsi command finish (EH_HANDLED).  Otherwise, the qc has
+ *	timed out and EH should be invoked.  Prevent ata_qc_complete()
+ *	from finishing it by setting EH_SCHEDULED and return
+ *	EH_NOT_HANDLED.
+ *
+ *	LOCKING:
+ *	Called from timer context
+ *
+ *	RETURNS:
+ *	EH_HANDLED or EH_NOT_HANDLED
+ */
+enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
+{
+	struct Scsi_Host *host = cmd->device->host;
+	struct ata_port *ap = (struct ata_port *) &host->hostdata[0];
+	unsigned long flags;
+	struct ata_queued_cmd *qc;
+	enum scsi_eh_timer_return ret = EH_HANDLED;
+
+	DPRINTK("ENTER\n");
+
+	spin_lock_irqsave(&ap->host_set->lock, flags);
+	qc = ata_qc_from_tag(ap, ap->active_tag);
+	if (qc) {
+		WARN_ON(qc->scsicmd != cmd);
+		qc->flags |= ATA_QCFLAG_EH_SCHEDULED;
+		qc->err_mask |= AC_ERR_TIMEOUT;
+		ret = EH_NOT_HANDLED;
+	}
+	spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+	DPRINTK("EXIT, ret=%d\n", ret);
+	return ret;
+}
+
+/**
  *	ata_scsi_error - SCSI layer error handler callback
  *	@host: SCSI host on which error occurred
  *
@@ -732,23 +773,84 @@
 int ata_scsi_error(struct Scsi_Host *host)
 {
 	struct ata_port *ap;
+	unsigned long flags;
 
 	DPRINTK("ENTER\n");
 
 	ap = (struct ata_port *) &host->hostdata[0];
+
+	spin_lock_irqsave(&ap->host_set->lock, flags);
+	WARN_ON(ap->flags & ATA_FLAG_IN_EH);
+	ap->flags |= ATA_FLAG_IN_EH;
+	WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL);
+	spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+	ata_port_flush_task(ap);
+
 	ap->ops->eng_timeout(ap);
 
-	/* TODO: this is per-command; when queueing is supported
-	 * this code will either change or move to a more
-	 * appropriate place
-	 */
-	host->host_failed--;
-	INIT_LIST_HEAD(&host->eh_cmd_q);
+	WARN_ON(host->host_failed || !list_empty(&host->eh_cmd_q));
+
+	scsi_eh_flush_done_q(&ap->eh_done_q);
+
+	spin_lock_irqsave(&ap->host_set->lock, flags);
+	ap->flags &= ~ATA_FLAG_IN_EH;
+	spin_unlock_irqrestore(&ap->host_set->lock, flags);
 
 	DPRINTK("EXIT\n");
 	return 0;
 }
 
+static void ata_eh_scsidone(struct scsi_cmnd *scmd)
+{
+	/* nada */
+}
+
+static void __ata_eh_qc_complete(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct scsi_cmnd *scmd = qc->scsicmd;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ap->host_set->lock, flags);
+	qc->scsidone = ata_eh_scsidone;
+	__ata_qc_complete(qc);
+	WARN_ON(ata_tag_valid(qc->tag));
+	spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+	scsi_eh_finish_cmd(scmd, &ap->eh_done_q);
+}
+
+/**
+ *	ata_eh_qc_complete - Complete an active ATA command from EH
+ *	@qc: Command to complete
+ *
+ *	Indicate to the mid and upper layers that an ATA command has
+ *	completed.  To be used from EH.
+ */
+void ata_eh_qc_complete(struct ata_queued_cmd *qc)
+{
+	struct scsi_cmnd *scmd = qc->scsicmd;
+	scmd->retries = scmd->allowed;
+	__ata_eh_qc_complete(qc);
+}
+
+/**
+ *	ata_eh_qc_retry - Tell midlayer to retry an ATA command after EH
+ *	@qc: Command to retry
+ *
+ *	Indicate to the mid and upper layers that an ATA command
+ *	should be retried.  To be used from EH.
+ *
+ *	SCSI midlayer limits the number of retries to scmd->allowed.
+ *	This function might need to adjust scmd->retries for commands
+ *	which get retried due to unrelated NCQ failures.
+ */
+void ata_eh_qc_retry(struct ata_queued_cmd *qc)
+{
+	__ata_eh_qc_complete(qc);
+}
+
 /**
  *	ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command
  *	@qc: Storage for translated ATA taskfile
@@ -985,9 +1087,13 @@
 	if (dev->flags & ATA_DFLAG_LBA) {
 		tf->flags |= ATA_TFLAG_LBA;
 
-		if (dev->flags & ATA_DFLAG_LBA48) {
-			if (n_block > (64 * 1024))
-				goto invalid_fld;
+		if (lba_28_ok(block, n_block)) {
+			/* use LBA28 */
+			tf->command = ATA_CMD_VERIFY;
+			tf->device |= (block >> 24) & 0xf;
+		} else if (lba_48_ok(block, n_block)) {
+			if (!(dev->flags & ATA_DFLAG_LBA48))
+				goto out_of_range;
 
 			/* use LBA48 */
 			tf->flags |= ATA_TFLAG_LBA48;
@@ -998,15 +1104,9 @@
 			tf->hob_lbah = (block >> 40) & 0xff;
 			tf->hob_lbam = (block >> 32) & 0xff;
 			tf->hob_lbal = (block >> 24) & 0xff;
-		} else {
-			if (n_block > 256)
-				goto invalid_fld;
-
-			/* use LBA28 */
-			tf->command = ATA_CMD_VERIFY;
-
-			tf->device |= (block >> 24) & 0xf;
-		}
+		} else
+			/* request too large even for LBA48 */
+			goto out_of_range;
 
 		tf->nsect = n_block & 0xff;
 
@@ -1019,8 +1119,8 @@
 		/* CHS */
 		u32 sect, head, cyl, track;
 
-		if (n_block > 256)
-			goto invalid_fld;
+		if (!lba_28_ok(block, n_block))
+			goto out_of_range;
 
 		/* Convert LBA to CHS */
 		track = (u32)block / dev->sectors;
@@ -1139,9 +1239,11 @@
 	if (dev->flags & ATA_DFLAG_LBA) {
 		tf->flags |= ATA_TFLAG_LBA;
 
-		if (dev->flags & ATA_DFLAG_LBA48) {
-			/* The request -may- be too large for LBA48. */
-			if ((block >> 48) || (n_block > 65536))
+		if (lba_28_ok(block, n_block)) {
+			/* use LBA28 */
+			tf->device |= (block >> 24) & 0xf;
+		} else if (lba_48_ok(block, n_block)) {
+			if (!(dev->flags & ATA_DFLAG_LBA48))
 				goto out_of_range;
 
 			/* use LBA48 */
@@ -1152,15 +1254,9 @@
 			tf->hob_lbah = (block >> 40) & 0xff;
 			tf->hob_lbam = (block >> 32) & 0xff;
 			tf->hob_lbal = (block >> 24) & 0xff;
-		} else { 
-			/* use LBA28 */
-
-			/* The request -may- be too large for LBA28. */
-			if ((block >> 28) || (n_block > 256))
-				goto out_of_range;
-
-			tf->device |= (block >> 24) & 0xf;
-		}
+		} else
+			/* request too large even for LBA48 */
+			goto out_of_range;
 
 		if (unlikely(ata_rwcmd_protocol(qc) < 0))
 			goto invalid_fld;
@@ -1178,7 +1274,7 @@
 		u32 sect, head, cyl, track;
 
 		/* The request -may- be too large for CHS addressing. */
-		if ((block >> 28) || (n_block > 256))
+		if (!lba_28_ok(block, n_block))
 			goto out_of_range;
 
 		if (unlikely(ata_rwcmd_protocol(qc) < 0))
@@ -1225,7 +1321,7 @@
 	return 1;
 }
 
-static int ata_scsi_qc_complete(struct ata_queued_cmd *qc)
+static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
 {
 	struct scsi_cmnd *cmd = qc->scsicmd;
 	u8 *cdb = cmd->cmnd;
@@ -1262,7 +1358,7 @@
 
 	qc->scsidone(cmd);
 
-	return 0;
+	ata_qc_free(qc);
 }
 
 /**
@@ -1328,8 +1424,9 @@
 		goto early_finish;
 
 	/* select device, send command to hardware */
-	if (ata_qc_issue(qc))
-		goto err_did;
+	qc->err_mask = ata_qc_issue(qc);
+	if (qc->err_mask)
+		ata_qc_complete(qc);
 
 	VPRINTK("EXIT\n");
 	return;
@@ -1472,8 +1569,8 @@
 
 	if (buflen > 35) {
 		memcpy(&rbuf[8], "ATA     ", 8);
-		ata_dev_id_string(args->id, &rbuf[16], ATA_ID_PROD_OFS, 16);
-		ata_dev_id_string(args->id, &rbuf[32], ATA_ID_FW_REV_OFS, 4);
+		ata_id_string(args->id, &rbuf[16], ATA_ID_PROD_OFS, 16);
+		ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV_OFS, 4);
 		if (rbuf[32] == 0 || rbuf[32] == ' ')
 			memcpy(&rbuf[32], "n/a ", 4);
 	}
@@ -1547,8 +1644,8 @@
 	memcpy(rbuf, hdr, sizeof(hdr));
 
 	if (buflen > (ATA_SERNO_LEN + 4 - 1))
-		ata_dev_id_string(args->id, (unsigned char *) &rbuf[4],
-				  ATA_ID_SERNO_OFS, ATA_SERNO_LEN);
+		ata_id_string(args->id, (unsigned char *) &rbuf[4],
+			      ATA_ID_SERNO_OFS, ATA_SERNO_LEN);
 
 	return 0;
 }
@@ -1713,15 +1810,12 @@
 	if (!ata_id_has_fua(id))
 		return 0;
 
-	model[40] = '\0';
-	fw[8] = '\0';
+	ata_id_c_string(id, model, ATA_ID_PROD_OFS, sizeof(model));
+	ata_id_c_string(id, fw, ATA_ID_FW_REV_OFS, sizeof(fw));
 
-	ata_dev_id_string(id, model, ATA_ID_PROD_OFS, sizeof(model) - 1);
-	ata_dev_id_string(id, fw, ATA_ID_FW_REV_OFS, sizeof(fw) - 1);
-
-	if (strncmp(model, "Maxtor", 6))
+	if (strcmp(model, "Maxtor"))
 		return 1;
-	if (strncmp(fw, "BANC1G10", 8))
+	if (strcmp(fw, "BANC1G10"))
 		return 1;
 
 	return 0; /* blacklisted */
@@ -2015,7 +2109,7 @@
 	done(cmd);
 }
 
-static int atapi_sense_complete(struct ata_queued_cmd *qc)
+static void atapi_sense_complete(struct ata_queued_cmd *qc)
 {
 	if (qc->err_mask && ((qc->err_mask & AC_ERR_DEV) == 0))
 		/* FIXME: not quite right; we don't want the
@@ -2026,7 +2120,7 @@
 		ata_gen_ata_desc_sense(qc);
 
 	qc->scsidone(qc->scsicmd);
-	return 0;
+	ata_qc_free(qc);
 }
 
 /* is it pointless to prefer PIO for "safety reasons"? */
@@ -2056,7 +2150,7 @@
 	ata_sg_init_one(qc, cmd->sense_buffer, sizeof(cmd->sense_buffer));
 	qc->dma_dir = DMA_FROM_DEVICE;
 
-	memset(&qc->cdb, 0, ap->cdb_len);
+	memset(&qc->cdb, 0, qc->dev->cdb_len);
 	qc->cdb[0] = REQUEST_SENSE;
 	qc->cdb[4] = SCSI_SENSE_BUFFERSIZE;
 
@@ -2075,15 +2169,14 @@
 
 	qc->complete_fn = atapi_sense_complete;
 
-	if (ata_qc_issue(qc)) {
-		qc->err_mask |= AC_ERR_OTHER;
+	qc->err_mask = ata_qc_issue(qc);
+	if (qc->err_mask)
 		ata_qc_complete(qc);
-	}
 
 	DPRINTK("EXIT\n");
 }
 
-static int atapi_qc_complete(struct ata_queued_cmd *qc)
+static void atapi_qc_complete(struct ata_queued_cmd *qc)
 {
 	struct scsi_cmnd *cmd = qc->scsicmd;
 	unsigned int err_mask = qc->err_mask;
@@ -2093,7 +2186,7 @@
 	if (unlikely(err_mask & AC_ERR_DEV)) {
 		cmd->result = SAM_STAT_CHECK_CONDITION;
 		atapi_request_sense(qc);
-		return 1;
+		return;
 	}
 
 	else if (unlikely(err_mask))
@@ -2133,7 +2226,7 @@
 	}
 
 	qc->scsidone(cmd);
-	return 0;
+	ata_qc_free(qc);
 }
 /**
  *	atapi_xlat - Initialize PACKET taskfile
@@ -2159,7 +2252,7 @@
 		if (ata_check_atapi_dma(qc))
 			using_pio = 1;
 
-	memcpy(&qc->cdb, scsicmd, qc->ap->cdb_len);
+	memcpy(&qc->cdb, scsicmd, dev->cdb_len);
 
 	qc->complete_fn = atapi_qc_complete;
 
@@ -2519,7 +2612,8 @@
 
 /**
  *	ata_scsi_simulate - simulate SCSI command on ATA device
- *	@id: current IDENTIFY data for target device.
+ *	@ap: port the device is connected to
+ *	@dev: the target device
  *	@cmd: SCSI command being sent to device.
  *	@done: SCSI command completion function.
  *
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h
index fddaf47..f4c48c9 100644
--- a/drivers/scsi/libata.h
+++ b/drivers/scsi/libata.h
@@ -45,8 +45,9 @@
 extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
 				      struct ata_device *dev);
 extern int ata_rwcmd_protocol(struct ata_queued_cmd *qc);
+extern void ata_port_flush_task(struct ata_port *ap);
 extern void ata_qc_free(struct ata_queued_cmd *qc);
-extern int ata_qc_issue(struct ata_queued_cmd *qc);
+extern unsigned int ata_qc_issue(struct ata_queued_cmd *qc);
 extern int ata_check_atapi_dma(struct ata_queued_cmd *qc);
 extern void ata_dev_select(struct ata_port *ap, unsigned int device,
                            unsigned int wait, unsigned int can_sleep);
diff --git a/drivers/scsi/pdc_adma.c b/drivers/scsi/pdc_adma.c
index e8df0c9..5f33cc9 100644
--- a/drivers/scsi/pdc_adma.c
+++ b/drivers/scsi/pdc_adma.c
@@ -131,7 +131,7 @@
 static void adma_port_stop(struct ata_port *ap);
 static void adma_phy_reset(struct ata_port *ap);
 static void adma_qc_prep(struct ata_queued_cmd *qc);
-static int adma_qc_issue(struct ata_queued_cmd *qc);
+static unsigned int adma_qc_issue(struct ata_queued_cmd *qc);
 static int adma_check_atapi_dma(struct ata_queued_cmd *qc);
 static void adma_bmdma_stop(struct ata_queued_cmd *qc);
 static u8 adma_bmdma_status(struct ata_port *ap);
@@ -143,11 +143,11 @@
 	.name			= DRV_NAME,
 	.ioctl			= ata_scsi_ioctl,
 	.queuecommand		= ata_scsi_queuecmd,
+	.eh_timed_out		= ata_scsi_timed_out,
 	.eh_strategy_handler	= ata_scsi_error,
 	.can_queue		= ATA_DEF_QUEUE,
 	.this_id		= ATA_SHT_THIS_ID,
 	.sg_tablesize		= LIBATA_MAX_PRD,
-	.max_sectors		= ATA_MAX_SECTORS,
 	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
 	.emulated		= ATA_SHT_EMULATED,
 	.use_clustering		= ENABLE_CLUSTERING,
@@ -419,7 +419,7 @@
 	writew(aPIOMD4 | aGO, chan + ADMA_CONTROL);
 }
 
-static int adma_qc_issue(struct ata_queued_cmd *qc)
+static unsigned int adma_qc_issue(struct ata_queued_cmd *qc)
 {
 	struct adma_port_priv *pp = qc->ap->private_data;
 
diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c
index 2770005..e561281 100644
--- a/drivers/scsi/sata_mv.c
+++ b/drivers/scsi/sata_mv.c
@@ -37,7 +37,7 @@
 #include <asm/io.h>
 
 #define DRV_NAME	"sata_mv"
-#define DRV_VERSION	"0.5"
+#define DRV_VERSION	"0.6"
 
 enum {
 	/* BAR's are enumerated in terms of pci_resource_start() terms */
@@ -228,7 +228,9 @@
 	MV_HP_ERRATA_50XXB2	= (1 << 2),
 	MV_HP_ERRATA_60X1B2	= (1 << 3),
 	MV_HP_ERRATA_60X1C0	= (1 << 4),
-	MV_HP_50XX		= (1 << 5),
+	MV_HP_ERRATA_XX42A0	= (1 << 5),
+	MV_HP_50XX		= (1 << 6),
+	MV_HP_GEN_IIE		= (1 << 7),
 
 	/* Port private flags (pp_flags) */
 	MV_PP_FLAG_EDMA_EN	= (1 << 0),
@@ -237,6 +239,9 @@
 
 #define IS_50XX(hpriv) ((hpriv)->hp_flags & MV_HP_50XX)
 #define IS_60XX(hpriv) (((hpriv)->hp_flags & MV_HP_50XX) == 0)
+#define IS_GEN_I(hpriv) IS_50XX(hpriv)
+#define IS_GEN_II(hpriv) IS_60XX(hpriv)
+#define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)
 
 enum {
 	/* Our DMA boundary is determined by an ePRD being unable to handle
@@ -255,6 +260,8 @@
 	chip_5080,
 	chip_604x,
 	chip_608x,
+	chip_6042,
+	chip_7042,
 };
 
 /* Command ReQuest Block: 32B */
@@ -265,6 +272,14 @@
 	u16			ata_cmd[11];
 };
 
+struct mv_crqb_iie {
+	u32			addr;
+	u32			addr_hi;
+	u32			flags;
+	u32			len;
+	u32			ata_cmd[4];
+};
+
 /* Command ResPonse Block: 8B */
 struct mv_crpb {
 	u16			id;
@@ -328,7 +343,8 @@
 static int mv_port_start(struct ata_port *ap);
 static void mv_port_stop(struct ata_port *ap);
 static void mv_qc_prep(struct ata_queued_cmd *qc);
-static int mv_qc_issue(struct ata_queued_cmd *qc);
+static void mv_qc_prep_iie(struct ata_queued_cmd *qc);
+static unsigned int mv_qc_issue(struct ata_queued_cmd *qc);
 static irqreturn_t mv_interrupt(int irq, void *dev_instance,
 				struct pt_regs *regs);
 static void mv_eng_timeout(struct ata_port *ap);
@@ -362,11 +378,11 @@
 	.name			= DRV_NAME,
 	.ioctl			= ata_scsi_ioctl,
 	.queuecommand		= ata_scsi_queuecmd,
+	.eh_timed_out		= ata_scsi_timed_out,
 	.eh_strategy_handler	= ata_scsi_error,
 	.can_queue		= MV_USE_Q_DEPTH,
 	.this_id		= ATA_SHT_THIS_ID,
 	.sg_tablesize		= MV_MAX_SG_CT / 2,
-	.max_sectors		= ATA_MAX_SECTORS,
 	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
 	.emulated		= ATA_SHT_EMULATED,
 	.use_clustering		= ATA_SHT_USE_CLUSTERING,
@@ -430,6 +446,33 @@
 	.host_stop		= mv_host_stop,
 };
 
+static const struct ata_port_operations mv_iie_ops = {
+	.port_disable		= ata_port_disable,
+
+	.tf_load		= ata_tf_load,
+	.tf_read		= ata_tf_read,
+	.check_status		= ata_check_status,
+	.exec_command		= ata_exec_command,
+	.dev_select		= ata_std_dev_select,
+
+	.phy_reset		= mv_phy_reset,
+
+	.qc_prep		= mv_qc_prep_iie,
+	.qc_issue		= mv_qc_issue,
+
+	.eng_timeout		= mv_eng_timeout,
+
+	.irq_handler		= mv_interrupt,
+	.irq_clear		= mv_irq_clear,
+
+	.scr_read		= mv_scr_read,
+	.scr_write		= mv_scr_write,
+
+	.port_start		= mv_port_start,
+	.port_stop		= mv_port_stop,
+	.host_stop		= mv_host_stop,
+};
+
 static const struct ata_port_info mv_port_info[] = {
 	{  /* chip_504x */
 		.sht		= &mv_sht,
@@ -467,6 +510,21 @@
 		.udma_mask	= 0x7f,	/* udma0-6 */
 		.port_ops	= &mv6_ops,
 	},
+	{  /* chip_6042 */
+		.sht		= &mv_sht,
+		.host_flags	= (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
+		.pio_mask	= 0x1f,	/* pio0-4 */
+		.udma_mask	= 0x7f,	/* udma0-6 */
+		.port_ops	= &mv_iie_ops,
+	},
+	{  /* chip_7042 */
+		.sht		= &mv_sht,
+		.host_flags	= (MV_COMMON_FLAGS | MV_6XXX_FLAGS |
+				   MV_FLAG_DUAL_HC),
+		.pio_mask	= 0x1f,	/* pio0-4 */
+		.udma_mask	= 0x7f,	/* udma0-6 */
+		.port_ops	= &mv_iie_ops,
+	},
 };
 
 static const struct pci_device_id mv_pci_tbl[] = {
@@ -477,6 +535,7 @@
 
 	{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6040), 0, 0, chip_604x},
 	{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6041), 0, 0, chip_604x},
+	{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6042), 0, 0, chip_6042},
 	{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6080), 0, 0, chip_608x},
 	{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6081), 0, 0, chip_608x},
 
@@ -572,8 +631,8 @@
  *      @base: port base address
  *      @pp: port private data
  *
- *      Verify the local cache of the eDMA state is accurate with an
- *      assert.
+ *      Verify the local cache of the eDMA state is accurate with a
+ *      WARN_ON.
  *
  *      LOCKING:
  *      Inherited from caller.
@@ -584,15 +643,15 @@
 		writelfl(EDMA_EN, base + EDMA_CMD_OFS);
 		pp->pp_flags |= MV_PP_FLAG_EDMA_EN;
 	}
-	assert(EDMA_EN & readl(base + EDMA_CMD_OFS));
+	WARN_ON(!(EDMA_EN & readl(base + EDMA_CMD_OFS)));
 }
 
 /**
  *      mv_stop_dma - Disable eDMA engine
  *      @ap: ATA channel to manipulate
  *
- *      Verify the local cache of the eDMA state is accurate with an
- *      assert.
+ *      Verify the local cache of the eDMA state is accurate with a
+ *      WARN_ON.
  *
  *      LOCKING:
  *      Inherited from caller.
@@ -610,7 +669,7 @@
 		writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
 		pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
 	} else {
-		assert(!(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS)));
+		WARN_ON(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS));
   	}
 
 	/* now properly wait for the eDMA to stop */
@@ -773,6 +832,33 @@
 	dma_free_coherent(dev, MV_PORT_PRIV_DMA_SZ, pp->crpb, pp->crpb_dma);
 }
 
+static void mv_edma_cfg(struct mv_host_priv *hpriv, void __iomem *port_mmio)
+{
+	u32 cfg = readl(port_mmio + EDMA_CFG_OFS);
+
+	/* set up non-NCQ EDMA configuration */
+	cfg &= ~0x1f;		/* clear queue depth */
+	cfg &= ~EDMA_CFG_NCQ;	/* clear NCQ mode */
+	cfg &= ~(1 << 9);	/* disable equeue */
+
+	if (IS_GEN_I(hpriv))
+		cfg |= (1 << 8);	/* enab config burst size mask */
+
+	else if (IS_GEN_II(hpriv))
+		cfg |= EDMA_CFG_RD_BRST_EXT | EDMA_CFG_WR_BUFF_LEN;
+
+	else if (IS_GEN_IIE(hpriv)) {
+		cfg |= (1 << 23);	/* dis RX PM port mask */
+		cfg &= ~(1 << 16);	/* dis FIS-based switching (for now) */
+		cfg &= ~(1 << 19);	/* dis 128-entry queue (for now?) */
+		cfg |= (1 << 18);	/* enab early completion */
+		cfg |= (1 << 17);	/* enab host q cache */
+		cfg |= (1 << 22);	/* enab cutthrough */
+	}
+
+	writelfl(cfg, port_mmio + EDMA_CFG_OFS);
+}
+
 /**
  *      mv_port_start - Port specific init/start routine.
  *      @ap: ATA channel to manipulate
@@ -786,6 +872,7 @@
 static int mv_port_start(struct ata_port *ap)
 {
 	struct device *dev = ap->host_set->dev;
+	struct mv_host_priv *hpriv = ap->host_set->private_data;
 	struct mv_port_priv *pp;
 	void __iomem *port_mmio = mv_ap_base(ap);
 	void *mem;
@@ -829,17 +916,26 @@
 	pp->sg_tbl = mem;
 	pp->sg_tbl_dma = mem_dma;
 
-	writelfl(EDMA_CFG_Q_DEPTH | EDMA_CFG_RD_BRST_EXT |
-		 EDMA_CFG_WR_BUFF_LEN, port_mmio + EDMA_CFG_OFS);
+	mv_edma_cfg(hpriv, port_mmio);
 
 	writel((pp->crqb_dma >> 16) >> 16, port_mmio + EDMA_REQ_Q_BASE_HI_OFS);
 	writelfl(pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK,
 		 port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
 
-	writelfl(0, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
-	writelfl(0, port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
+	if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
+		writelfl(pp->crqb_dma & 0xffffffff,
+			 port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
+	else
+		writelfl(0, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
 
 	writel((pp->crpb_dma >> 16) >> 16, port_mmio + EDMA_RSP_Q_BASE_HI_OFS);
+
+	if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
+		writelfl(pp->crpb_dma & 0xffffffff,
+			 port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
+	else
+		writelfl(0, port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
+
 	writelfl(pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK,
 		 port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
 
@@ -960,21 +1056,19 @@
 	struct ata_taskfile *tf;
 	u16 flags = 0;
 
- 	if (ATA_PROT_DMA != qc->tf.protocol) {
+ 	if (ATA_PROT_DMA != qc->tf.protocol)
 		return;
-	}
 
 	/* the req producer index should be the same as we remember it */
-	assert(((readl(mv_ap_base(qc->ap) + EDMA_REQ_Q_IN_PTR_OFS) >>
-		 EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) ==
-	       pp->req_producer);
+	WARN_ON(((readl(mv_ap_base(qc->ap) + EDMA_REQ_Q_IN_PTR_OFS) >>
+		  EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) !=
+		pp->req_producer);
 
 	/* Fill in command request block
 	 */
-	if (!(qc->tf.flags & ATA_TFLAG_WRITE)) {
+	if (!(qc->tf.flags & ATA_TFLAG_WRITE))
 		flags |= CRQB_FLAG_READ;
-	}
-	assert(MV_MAX_Q_DEPTH > qc->tag);
+	WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
 	flags |= qc->tag << CRQB_TAG_SHIFT;
 
 	pp->crqb[pp->req_producer].sg_addr =
@@ -1029,9 +1123,76 @@
 	mv_crqb_pack_cmd(cw++, tf->device, ATA_REG_DEVICE, 0);
 	mv_crqb_pack_cmd(cw++, tf->command, ATA_REG_CMD, 1);	/* last */
 
-	if (!(qc->flags & ATA_QCFLAG_DMAMAP)) {
+	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
 		return;
-	}
+	mv_fill_sg(qc);
+}
+
+/**
+ *      mv_qc_prep_iie - Host specific command preparation.
+ *      @qc: queued command to prepare
+ *
+ *      This routine simply redirects to the general purpose routine
+ *      if command is not DMA.  Else, it handles prep of the CRQB
+ *      (command request block), does some sanity checking, and calls
+ *      the SG load routine.
+ *
+ *      LOCKING:
+ *      Inherited from caller.
+ */
+static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct mv_port_priv *pp = ap->private_data;
+	struct mv_crqb_iie *crqb;
+	struct ata_taskfile *tf;
+	u32 flags = 0;
+
+ 	if (ATA_PROT_DMA != qc->tf.protocol)
+		return;
+
+	/* the req producer index should be the same as we remember it */
+	WARN_ON(((readl(mv_ap_base(qc->ap) + EDMA_REQ_Q_IN_PTR_OFS) >>
+		  EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) !=
+		pp->req_producer);
+
+	/* Fill in Gen IIE command request block
+	 */
+	if (!(qc->tf.flags & ATA_TFLAG_WRITE))
+		flags |= CRQB_FLAG_READ;
+
+	WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
+	flags |= qc->tag << CRQB_TAG_SHIFT;
+
+	crqb = (struct mv_crqb_iie *) &pp->crqb[pp->req_producer];
+	crqb->addr = cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
+	crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
+	crqb->flags = cpu_to_le32(flags);
+
+	tf = &qc->tf;
+	crqb->ata_cmd[0] = cpu_to_le32(
+			(tf->command << 16) |
+			(tf->feature << 24)
+		);
+	crqb->ata_cmd[1] = cpu_to_le32(
+			(tf->lbal << 0) |
+			(tf->lbam << 8) |
+			(tf->lbah << 16) |
+			(tf->device << 24)
+		);
+	crqb->ata_cmd[2] = cpu_to_le32(
+			(tf->hob_lbal << 0) |
+			(tf->hob_lbam << 8) |
+			(tf->hob_lbah << 16) |
+			(tf->hob_feature << 24)
+		);
+	crqb->ata_cmd[3] = cpu_to_le32(
+			(tf->nsect << 0) |
+			(tf->hob_nsect << 8)
+		);
+
+	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
+		return;
 	mv_fill_sg(qc);
 }
 
@@ -1047,7 +1208,7 @@
  *      LOCKING:
  *      Inherited from caller.
  */
-static int mv_qc_issue(struct ata_queued_cmd *qc)
+static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
 {
 	void __iomem *port_mmio = mv_ap_base(qc->ap);
 	struct mv_port_priv *pp = qc->ap->private_data;
@@ -1065,12 +1226,12 @@
 	in_ptr = readl(port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
 
 	/* the req producer index should be the same as we remember it */
-	assert(((in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) ==
-	       pp->req_producer);
+	WARN_ON(((in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) !=
+		pp->req_producer);
 	/* until we do queuing, the queue should be empty at this point */
-	assert(((in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) ==
-	       ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS) >>
-		 EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
+	WARN_ON(((in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) !=
+		((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS) >>
+		  EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
 
 	mv_inc_q_index(&pp->req_producer);	/* now incr producer index */
 
@@ -1090,7 +1251,7 @@
  *
  *      This routine is for use when the port is in DMA mode, when it
  *      will be using the CRPB (command response block) method of
- *      returning command completion information.  We assert indices
+ *      returning command completion information.  We check indices
  *      are good, grab status, and bump the response consumer index to
  *      prove that we're up to date.
  *
@@ -1106,16 +1267,16 @@
 	out_ptr = readl(port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
 
 	/* the response consumer index should be the same as we remember it */
-	assert(((out_ptr >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) ==
-	       pp->rsp_consumer);
+	WARN_ON(((out_ptr >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) !=
+		pp->rsp_consumer);
 
 	/* increment our consumer index... */
 	pp->rsp_consumer = mv_inc_q_index(&pp->rsp_consumer);
 
 	/* and, until we do NCQ, there should only be 1 CRPB waiting */
-	assert(((readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS) >>
-		 EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) ==
-	       pp->rsp_consumer);
+	WARN_ON(((readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS) >>
+		  EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) !=
+		pp->rsp_consumer);
 
 	/* write out our inc'd consumer index so EDMA knows we're caught up */
 	out_ptr &= EDMA_RSP_Q_BASE_LO_MASK;
@@ -1192,7 +1353,6 @@
 	u32 hc_irq_cause;
 	int shift, port, port0, hard_port, handled;
 	unsigned int err_mask;
-	u8 ata_status = 0;
 
 	if (hc == 0) {
 		port0 = 0;
@@ -1210,6 +1370,7 @@
 		hc,relevant,hc_irq_cause);
 
 	for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) {
+		u8 ata_status = 0;
 		ap = host_set->ports[port];
 		hard_port = port & MV_PORT_MASK;	/* range 0-3 */
 		handled = 0;	/* ensure ata_status is set if handled++ */
@@ -1681,6 +1842,12 @@
 	m2 |= hpriv->signal[port].pre;
 	m2 &= ~(1 << 16);
 
+	/* according to mvSata 3.6.1, some IIE values are fixed */
+	if (IS_GEN_IIE(hpriv)) {
+		m2 &= ~0xC30FF01F;
+		m2 |= 0x0000900F;
+	}
+
 	writel(m2, port_mmio + PHY_MODE2);
 }
 
@@ -1846,7 +2013,6 @@
 static void mv_eng_timeout(struct ata_port *ap)
 {
 	struct ata_queued_cmd *qc;
-	unsigned long flags;
 
 	printk(KERN_ERR "ata%u: Entering mv_eng_timeout\n",ap->id);
 	DPRINTK("All regs @ start of eng_timeout\n");
@@ -1861,22 +2027,8 @@
 	mv_err_intr(ap);
 	mv_stop_and_reset(ap);
 
-	if (!qc) {
-		printk(KERN_ERR "ata%u: BUG: timeout without command\n",
-		       ap->id);
-	} else {
-		/* hack alert!  We cannot use the supplied completion
-	 	 * function from inside the ->eh_strategy_handler() thread.
-	 	 * libata is the only user of ->eh_strategy_handler() in
-	 	 * any kernel, so the default scsi_done() assumes it is
-	 	 * not being called from the SCSI EH.
-	 	 */
-		spin_lock_irqsave(&ap->host_set->lock, flags);
-		qc->scsidone = scsi_finish_command;
-		qc->err_mask |= AC_ERR_OTHER;
-		ata_qc_complete(qc);
-		spin_unlock_irqrestore(&ap->host_set->lock, flags);
-	}
+	qc->err_mask |= AC_ERR_TIMEOUT;
+	ata_eh_qc_complete(qc);
 }
 
 /**
@@ -1995,6 +2147,27 @@
 		}
 		break;
 
+	case chip_7042:
+	case chip_6042:
+		hpriv->ops = &mv6xxx_ops;
+
+		hp_flags |= MV_HP_GEN_IIE;
+
+		switch (rev_id) {
+		case 0x0:
+			hp_flags |= MV_HP_ERRATA_XX42A0;
+			break;
+		case 0x1:
+			hp_flags |= MV_HP_ERRATA_60X1C0;
+			break;
+		default:
+			dev_printk(KERN_WARNING, &pdev->dev,
+			   "Applying 60X1C0 workarounds to unknown rev\n");
+			hp_flags |= MV_HP_ERRATA_60X1C0;
+			break;
+		}
+		break;
+
 	default:
 		printk(KERN_ERR DRV_NAME ": BUG: invalid board index %u\n", board_idx);
 		return 1;
diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c
index bbbb55e..caffadc 100644
--- a/drivers/scsi/sata_nv.c
+++ b/drivers/scsi/sata_nv.c
@@ -229,11 +229,11 @@
 	.name			= DRV_NAME,
 	.ioctl			= ata_scsi_ioctl,
 	.queuecommand		= ata_scsi_queuecmd,
+	.eh_timed_out		= ata_scsi_timed_out,
 	.eh_strategy_handler	= ata_scsi_error,
 	.can_queue		= ATA_DEF_QUEUE,
 	.this_id		= ATA_SHT_THIS_ID,
 	.sg_tablesize		= LIBATA_MAX_PRD,
-	.max_sectors		= ATA_MAX_SECTORS,
 	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
 	.emulated		= ATA_SHT_EMULATED,
 	.use_clustering		= ATA_SHT_USE_CLUSTERING,
diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c
index b0b0a69..84cb394 100644
--- a/drivers/scsi/sata_promise.c
+++ b/drivers/scsi/sata_promise.c
@@ -46,7 +46,7 @@
 #include "sata_promise.h"
 
 #define DRV_NAME	"sata_promise"
-#define DRV_VERSION	"1.03"
+#define DRV_VERSION	"1.04"
 
 
 enum {
@@ -58,6 +58,7 @@
 	PDC_GLOBAL_CTL		= 0x48, /* Global control/status (per port) */
 	PDC_CTLSTAT		= 0x60,	/* IDE control and status (per port) */
 	PDC_SATA_PLUG_CSR	= 0x6C, /* SATA Plug control/status reg */
+	PDC2_SATA_PLUG_CSR	= 0x60, /* SATAII Plug control/status reg */
 	PDC_SLEW_CTL		= 0x470, /* slew rate control reg */
 
 	PDC_ERR_MASK		= (1<<19) | (1<<20) | (1<<21) | (1<<22) |
@@ -67,8 +68,10 @@
 	board_20319		= 1,	/* FastTrak S150 TX4 */
 	board_20619		= 2,	/* FastTrak TX4000 */
 	board_20771		= 3,	/* FastTrak TX2300 */
+	board_2057x		= 4,	/* SATAII150 Tx2plus */
+	board_40518		= 5,	/* SATAII150 Tx4 */
 
-	PDC_HAS_PATA		= (1 << 1), /* PDC20375 has PATA */
+	PDC_HAS_PATA		= (1 << 1), /* PDC20375/20575 has PATA */
 
 	PDC_RESET		= (1 << 11), /* HDMA reset */
 
@@ -82,6 +85,10 @@
 	dma_addr_t		pkt_dma;
 };
 
+struct pdc_host_priv {
+	int			hotplug_offset;
+};
+
 static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg);
 static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
@@ -95,7 +102,8 @@
 static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
 static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
 static void pdc_irq_clear(struct ata_port *ap);
-static int pdc_qc_issue_prot(struct ata_queued_cmd *qc);
+static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc);
+static void pdc_host_stop(struct ata_host_set *host_set);
 
 
 static struct scsi_host_template pdc_ata_sht = {
@@ -103,11 +111,11 @@
 	.name			= DRV_NAME,
 	.ioctl			= ata_scsi_ioctl,
 	.queuecommand		= ata_scsi_queuecmd,
+	.eh_timed_out		= ata_scsi_timed_out,
 	.eh_strategy_handler	= ata_scsi_error,
 	.can_queue		= ATA_DEF_QUEUE,
 	.this_id		= ATA_SHT_THIS_ID,
 	.sg_tablesize		= LIBATA_MAX_PRD,
-	.max_sectors		= ATA_MAX_SECTORS,
 	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
 	.emulated		= ATA_SHT_EMULATED,
 	.use_clustering		= ATA_SHT_USE_CLUSTERING,
@@ -137,7 +145,7 @@
 	.scr_write		= pdc_sata_scr_write,
 	.port_start		= pdc_port_start,
 	.port_stop		= pdc_port_stop,
-	.host_stop		= ata_pci_host_stop,
+	.host_stop		= pdc_host_stop,
 };
 
 static const struct ata_port_operations pdc_pata_ops = {
@@ -158,7 +166,7 @@
 
 	.port_start		= pdc_port_start,
 	.port_stop		= pdc_port_stop,
-	.host_stop		= ata_pci_host_stop,
+	.host_stop		= pdc_host_stop,
 };
 
 static const struct ata_port_info pdc_port_info[] = {
@@ -201,6 +209,26 @@
 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
 		.port_ops	= &pdc_sata_ops,
 	},
+
+	/* board_2057x */
+	{
+		.sht		= &pdc_ata_sht,
+		.host_flags	= PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+		.pio_mask	= 0x1f, /* pio0-4 */
+		.mwdma_mask	= 0x07, /* mwdma0-2 */
+		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
+		.port_ops	= &pdc_sata_ops,
+	},
+
+	/* board_40518 */
+	{
+		.sht		= &pdc_ata_sht,
+		.host_flags	= PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+		.pio_mask	= 0x1f, /* pio0-4 */
+		.mwdma_mask	= 0x07, /* mwdma0-2 */
+		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
+		.port_ops	= &pdc_sata_ops,
+	},
 };
 
 static const struct pci_device_id pdc_ata_pci_tbl[] = {
@@ -217,9 +245,9 @@
 	{ PCI_VENDOR_ID_PROMISE, 0x3376, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 	  board_2037x },
 	{ PCI_VENDOR_ID_PROMISE, 0x3574, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_2037x },
+	  board_2057x },
 	{ PCI_VENDOR_ID_PROMISE, 0x3d75, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_2037x },
+	  board_2057x },
 	{ PCI_VENDOR_ID_PROMISE, 0x3d73, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 	  board_2037x },
 
@@ -227,12 +255,14 @@
 	  board_20319 },
 	{ PCI_VENDOR_ID_PROMISE, 0x3319, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 	  board_20319 },
+	{ PCI_VENDOR_ID_PROMISE, 0x3515, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_20319 },
 	{ PCI_VENDOR_ID_PROMISE, 0x3519, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 	  board_20319 },
 	{ PCI_VENDOR_ID_PROMISE, 0x3d17, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 	  board_20319 },
 	{ PCI_VENDOR_ID_PROMISE, 0x3d18, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_20319 },
+	  board_40518 },
 
 	{ PCI_VENDOR_ID_PROMISE, 0x6629, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 	  board_20619 },
@@ -261,12 +291,11 @@
 	if (rc)
 		return rc;
 
-	pp = kmalloc(sizeof(*pp), GFP_KERNEL);
+	pp = kzalloc(sizeof(*pp), GFP_KERNEL);
 	if (!pp) {
 		rc = -ENOMEM;
 		goto err_out;
 	}
-	memset(pp, 0, sizeof(*pp));
 
 	pp->pkt = dma_alloc_coherent(dev, 128, &pp->pkt_dma, GFP_KERNEL);
 	if (!pp->pkt) {
@@ -298,6 +327,16 @@
 }
 
 
+static void pdc_host_stop(struct ata_host_set *host_set)
+{
+	struct pdc_host_priv *hp = host_set->private_data;
+
+	ata_pci_host_stop(host_set);
+
+	kfree(hp);
+}
+
+
 static void pdc_reset_port(struct ata_port *ap)
 {
 	void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_CTLSTAT;
@@ -394,19 +433,6 @@
 	spin_lock_irqsave(&host_set->lock, flags);
 
 	qc = ata_qc_from_tag(ap, ap->active_tag);
-	if (!qc) {
-		printk(KERN_ERR "ata%u: BUG: timeout without command\n",
-		       ap->id);
-		goto out;
-	}
-
-	/* hack alert!  We cannot use the supplied completion
-	 * function from inside the ->eh_strategy_handler() thread.
-	 * libata is the only user of ->eh_strategy_handler() in
-	 * any kernel, so the default scsi_done() assumes it is
-	 * not being called from the SCSI EH.
-	 */
-	qc->scsidone = scsi_finish_command;
 
 	switch (qc->tf.protocol) {
 	case ATA_PROT_DMA:
@@ -414,7 +440,6 @@
 		printk(KERN_ERR "ata%u: command timeout\n", ap->id);
 		drv_stat = ata_wait_idle(ap);
 		qc->err_mask |= __ac_err_mask(drv_stat);
-		ata_qc_complete(qc);
 		break;
 
 	default:
@@ -424,12 +449,11 @@
 		       ap->id, qc->tf.command, drv_stat);
 
 		qc->err_mask |= ac_err_mask(drv_stat);
-		ata_qc_complete(qc);
 		break;
 	}
 
-out:
 	spin_unlock_irqrestore(&host_set->lock, flags);
+	ata_eh_qc_complete(qc);
 	DPRINTK("EXIT\n");
 }
 
@@ -495,14 +519,15 @@
 		VPRINTK("QUICK EXIT 2\n");
 		return IRQ_NONE;
 	}
+
+	spin_lock(&host_set->lock);
+
 	mask &= 0xffff;		/* only 16 tags possible */
 	if (!mask) {
 		VPRINTK("QUICK EXIT 3\n");
-		return IRQ_NONE;
+		goto done_irq;
 	}
 
-	spin_lock(&host_set->lock);
-
 	writel(mask, mmio_base + PDC_INT_SEQMASK);
 
 	for (i = 0; i < host_set->n_ports; i++) {
@@ -519,10 +544,10 @@
 		}
 	}
 
-        spin_unlock(&host_set->lock);
-
 	VPRINTK("EXIT\n");
 
+done_irq:
+	spin_unlock(&host_set->lock);
 	return IRQ_RETVAL(handled);
 }
 
@@ -544,7 +569,7 @@
 	readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */
 }
 
-static int pdc_qc_issue_prot(struct ata_queued_cmd *qc)
+static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc)
 {
 	switch (qc->tf.protocol) {
 	case ATA_PROT_DMA:
@@ -600,6 +625,8 @@
 static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
 {
 	void __iomem *mmio = pe->mmio_base;
+	struct pdc_host_priv *hp = pe->private_data;
+	int hotplug_offset = hp->hotplug_offset;
 	u32 tmp;
 
 	/*
@@ -614,12 +641,12 @@
 	writel(tmp, mmio + PDC_FLASH_CTL);
 
 	/* clear plug/unplug flags for all ports */
-	tmp = readl(mmio + PDC_SATA_PLUG_CSR);
-	writel(tmp | 0xff, mmio + PDC_SATA_PLUG_CSR);
+	tmp = readl(mmio + hotplug_offset);
+	writel(tmp | 0xff, mmio + hotplug_offset);
 
 	/* mask plug/unplug ints */
-	tmp = readl(mmio + PDC_SATA_PLUG_CSR);
-	writel(tmp | 0xff0000, mmio + PDC_SATA_PLUG_CSR);
+	tmp = readl(mmio + hotplug_offset);
+	writel(tmp | 0xff0000, mmio + hotplug_offset);
 
 	/* reduce TBG clock to 133 Mhz. */
 	tmp = readl(mmio + PDC_TBG_MODE);
@@ -641,6 +668,7 @@
 {
 	static int printed_version;
 	struct ata_probe_ent *probe_ent = NULL;
+	struct pdc_host_priv *hp;
 	unsigned long base;
 	void __iomem *mmio_base;
 	unsigned int board_idx = (unsigned int) ent->driver_data;
@@ -671,13 +699,12 @@
 	if (rc)
 		goto err_out_regions;
 
-	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+	probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
 	if (probe_ent == NULL) {
 		rc = -ENOMEM;
 		goto err_out_regions;
 	}
 
-	memset(probe_ent, 0, sizeof(*probe_ent));
 	probe_ent->dev = pci_dev_to_dev(pdev);
 	INIT_LIST_HEAD(&probe_ent->node);
 
@@ -688,6 +715,16 @@
 	}
 	base = (unsigned long) mmio_base;
 
+	hp = kzalloc(sizeof(*hp), GFP_KERNEL);
+	if (hp == NULL) {
+		rc = -ENOMEM;
+		goto err_out_free_ent;
+	}
+
+	/* Set default hotplug offset */
+	hp->hotplug_offset = PDC_SATA_PLUG_CSR;
+	probe_ent->private_data = hp;
+
 	probe_ent->sht		= pdc_port_info[board_idx].sht;
 	probe_ent->host_flags	= pdc_port_info[board_idx].host_flags;
 	probe_ent->pio_mask	= pdc_port_info[board_idx].pio_mask;
@@ -707,6 +744,10 @@
 
 	/* notice 4-port boards */
 	switch (board_idx) {
+	case board_40518:
+		/* Override hotplug offset for SATAII150 */
+		hp->hotplug_offset = PDC2_SATA_PLUG_CSR;
+		/* Fall through */
 	case board_20319:
        		probe_ent->n_ports = 4;
 
@@ -716,6 +757,10 @@
 		probe_ent->port[2].scr_addr = base + 0x600;
 		probe_ent->port[3].scr_addr = base + 0x700;
 		break;
+	case board_2057x:
+		/* Override hotplug offset for SATAII150 */
+		hp->hotplug_offset = PDC2_SATA_PLUG_CSR;
+		/* Fall through */
 	case board_2037x:
 		probe_ent->n_ports = 2;
 		break;
@@ -741,8 +786,10 @@
 	/* initialize adapter */
 	pdc_host_init(board_idx, probe_ent);
 
-	/* FIXME: check ata_device_add return value */
-	ata_device_add(probe_ent);
+	/* FIXME: Need any other frees than hp? */
+	if (!ata_device_add(probe_ent))
+		kfree(hp);
+
 	kfree(probe_ent);
 
 	return 0;
diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c
index 80480f0..9602f43 100644
--- a/drivers/scsi/sata_qstor.c
+++ b/drivers/scsi/sata_qstor.c
@@ -120,7 +120,7 @@
 static void qs_port_stop(struct ata_port *ap);
 static void qs_phy_reset(struct ata_port *ap);
 static void qs_qc_prep(struct ata_queued_cmd *qc);
-static int qs_qc_issue(struct ata_queued_cmd *qc);
+static unsigned int qs_qc_issue(struct ata_queued_cmd *qc);
 static int qs_check_atapi_dma(struct ata_queued_cmd *qc);
 static void qs_bmdma_stop(struct ata_queued_cmd *qc);
 static u8 qs_bmdma_status(struct ata_port *ap);
@@ -132,11 +132,11 @@
 	.name			= DRV_NAME,
 	.ioctl			= ata_scsi_ioctl,
 	.queuecommand		= ata_scsi_queuecmd,
+	.eh_timed_out		= ata_scsi_timed_out,
 	.eh_strategy_handler	= ata_scsi_error,
 	.can_queue		= ATA_DEF_QUEUE,
 	.this_id		= ATA_SHT_THIS_ID,
 	.sg_tablesize		= QS_MAX_PRD,
-	.max_sectors		= ATA_MAX_SECTORS,
 	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
 	.emulated		= ATA_SHT_EMULATED,
 	//FIXME .use_clustering		= ATA_SHT_USE_CLUSTERING,
@@ -276,8 +276,8 @@
 	unsigned int nelem;
 	u8 *prd = pp->pkt + QS_CPB_BYTES;
 
-	assert(qc->__sg != NULL);
-	assert(qc->n_elem > 0 || qc->pad_len > 0);
+	WARN_ON(qc->__sg == NULL);
+	WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
 
 	nelem = 0;
 	ata_for_each_sg(sg, qc) {
@@ -352,7 +352,7 @@
 	readl(chan + QS_CCT_CFF);          /* flush */
 }
 
-static int qs_qc_issue(struct ata_queued_cmd *qc)
+static unsigned int qs_qc_issue(struct ata_queued_cmd *qc)
 {
 	struct qs_port_priv *pp = qc->ap->private_data;
 
diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c
index 9face3c..4f2a67e 100644
--- a/drivers/scsi/sata_sil.c
+++ b/drivers/scsi/sata_sil.c
@@ -49,24 +49,30 @@
 #define DRV_VERSION	"0.9"
 
 enum {
+	/*
+	 * host flags
+	 */
 	SIL_FLAG_RERR_ON_DMA_ACT = (1 << 29),
 	SIL_FLAG_MOD15WRITE	= (1 << 30),
+	SIL_DFL_HOST_FLAGS	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+				  ATA_FLAG_MMIO,
 
+	/*
+	 * Controller IDs
+	 */
 	sil_3112		= 0,
-	sil_3112_m15w		= 1,
-	sil_3512		= 2,
-	sil_3114		= 3,
+	sil_3512		= 1,
+	sil_3114		= 2,
 
-	SIL_FIFO_R0		= 0x40,
-	SIL_FIFO_W0		= 0x41,
-	SIL_FIFO_R1		= 0x44,
-	SIL_FIFO_W1		= 0x45,
-	SIL_FIFO_R2		= 0x240,
-	SIL_FIFO_W2		= 0x241,
-	SIL_FIFO_R3		= 0x244,
-	SIL_FIFO_W3		= 0x245,
-
+	/*
+	 * Register offsets
+	 */
 	SIL_SYSCFG		= 0x48,
+
+	/*
+	 * Register bits
+	 */
+	/* SYSCFG */
 	SIL_MASK_IDE0_INT	= (1 << 22),
 	SIL_MASK_IDE1_INT	= (1 << 23),
 	SIL_MASK_IDE2_INT	= (1 << 24),
@@ -75,9 +81,12 @@
 	SIL_MASK_4PORT		= SIL_MASK_2PORT |
 				  SIL_MASK_IDE2_INT | SIL_MASK_IDE3_INT,
 
-	SIL_IDE2_BMDMA		= 0x200,
-
+	/* BMDMA/BMDMA2 */
 	SIL_INTR_STEERING	= (1 << 1),
+
+	/*
+	 * Others
+	 */
 	SIL_QUIRK_MOD15WRITE	= (1 << 0),
 	SIL_QUIRK_UDMA5MAX	= (1 << 1),
 };
@@ -90,13 +99,13 @@
 
 
 static const struct pci_device_id sil_pci_tbl[] = {
-	{ 0x1095, 0x3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w },
-	{ 0x1095, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w },
+	{ 0x1095, 0x3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+	{ 0x1095, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
 	{ 0x1095, 0x3512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3512 },
 	{ 0x1095, 0x3114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3114 },
-	{ 0x1002, 0x436e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w },
-	{ 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w },
-	{ 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w },
+	{ 0x1002, 0x436e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+	{ 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+	{ 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
 	{ }	/* terminate list */
 };
 
@@ -137,11 +146,11 @@
 	.name			= DRV_NAME,
 	.ioctl			= ata_scsi_ioctl,
 	.queuecommand		= ata_scsi_queuecmd,
+	.eh_timed_out		= ata_scsi_timed_out,
 	.eh_strategy_handler	= ata_scsi_error,
 	.can_queue		= ATA_DEF_QUEUE,
 	.this_id		= ATA_SHT_THIS_ID,
 	.sg_tablesize		= LIBATA_MAX_PRD,
-	.max_sectors		= ATA_MAX_SECTORS,
 	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
 	.emulated		= ATA_SHT_EMULATED,
 	.use_clustering		= ATA_SHT_USE_CLUSTERING,
@@ -159,7 +168,7 @@
 	.check_status		= ata_check_status,
 	.exec_command		= ata_exec_command,
 	.dev_select		= ata_std_dev_select,
-	.phy_reset		= sata_phy_reset,
+	.probe_reset		= ata_std_probe_reset,
 	.post_set_mode		= sil_post_set_mode,
 	.bmdma_setup            = ata_bmdma_setup,
 	.bmdma_start            = ata_bmdma_start,
@@ -181,19 +190,7 @@
 	/* sil_3112 */
 	{
 		.sht		= &sil_sht,
-		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-				  ATA_FLAG_SRST | ATA_FLAG_MMIO,
-		.pio_mask	= 0x1f,			/* pio0-4 */
-		.mwdma_mask	= 0x07,			/* mwdma0-2 */
-		.udma_mask	= 0x3f,			/* udma0-5 */
-		.port_ops	= &sil_ops,
-	},
-	/* sil_3112_15w - keep it sync'd w/ sil_3112 */
-	{
-		.sht		= &sil_sht,
-		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-				  ATA_FLAG_SRST | ATA_FLAG_MMIO |
-				  SIL_FLAG_MOD15WRITE,
+		.host_flags	= SIL_DFL_HOST_FLAGS | SIL_FLAG_MOD15WRITE,
 		.pio_mask	= 0x1f,			/* pio0-4 */
 		.mwdma_mask	= 0x07,			/* mwdma0-2 */
 		.udma_mask	= 0x3f,			/* udma0-5 */
@@ -202,9 +199,7 @@
 	/* sil_3512 */
 	{
 		.sht		= &sil_sht,
-		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-				  ATA_FLAG_SRST | ATA_FLAG_MMIO |
-				  SIL_FLAG_RERR_ON_DMA_ACT,
+		.host_flags	= SIL_DFL_HOST_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
 		.pio_mask	= 0x1f,			/* pio0-4 */
 		.mwdma_mask	= 0x07,			/* mwdma0-2 */
 		.udma_mask	= 0x3f,			/* udma0-5 */
@@ -213,9 +208,7 @@
 	/* sil_3114 */
 	{
 		.sht		= &sil_sht,
-		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-				  ATA_FLAG_SRST | ATA_FLAG_MMIO |
-				  SIL_FLAG_RERR_ON_DMA_ACT,
+		.host_flags	= SIL_DFL_HOST_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
 		.pio_mask	= 0x1f,			/* pio0-4 */
 		.mwdma_mask	= 0x07,			/* mwdma0-2 */
 		.udma_mask	= 0x3f,			/* udma0-5 */
@@ -229,16 +222,17 @@
 	unsigned long tf;	/* ATA taskfile register block */
 	unsigned long ctl;	/* ATA control/altstatus register block */
 	unsigned long bmdma;	/* DMA register block */
+	unsigned long fifo_cfg;	/* FIFO Valid Byte Count and Control */
 	unsigned long scr;	/* SATA control register block */
 	unsigned long sien;	/* SATA Interrupt Enable register */
 	unsigned long xfer_mode;/* data transfer mode register */
 	unsigned long sfis_cfg;	/* SATA FIS reception config register */
 } sil_port[] = {
 	/* port 0 ... */
-	{ 0x80, 0x8A, 0x00, 0x100, 0x148, 0xb4, 0x14c },
-	{ 0xC0, 0xCA, 0x08, 0x180, 0x1c8, 0xf4, 0x1cc },
-	{ 0x280, 0x28A, 0x200, 0x300, 0x348, 0x2b4, 0x34c },
-	{ 0x2C0, 0x2CA, 0x208, 0x380, 0x3c8, 0x2f4, 0x3cc },
+	{ 0x80, 0x8A, 0x00, 0x40, 0x100, 0x148, 0xb4, 0x14c },
+	{ 0xC0, 0xCA, 0x08, 0x44, 0x180, 0x1c8, 0xf4, 0x1cc },
+	{ 0x280, 0x28A, 0x200, 0x240, 0x300, 0x348, 0x2b4, 0x34c },
+	{ 0x2C0, 0x2CA, 0x208, 0x244, 0x380, 0x3c8, 0x2f4, 0x3cc },
 	/* ... port 3 */
 };
 
@@ -354,22 +348,12 @@
 static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
 {
 	unsigned int n, quirks = 0;
-	unsigned char model_num[40];
-	const char *s;
-	unsigned int len;
+	unsigned char model_num[41];
 
-	ata_dev_id_string(dev->id, model_num, ATA_ID_PROD_OFS,
-			  sizeof(model_num));
-	s = &model_num[0];
-	len = strnlen(s, sizeof(model_num));
-
-	/* ATAPI specifies that empty space is blank-filled; remove blanks */
-	while ((len > 0) && (s[len - 1] == ' '))
-		len--;
+	ata_id_c_string(dev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num));
 
 	for (n = 0; sil_blacklist[n].product; n++)
-		if (!memcmp(sil_blacklist[n].product, s,
-			    strlen(sil_blacklist[n].product))) {
+		if (!strcmp(sil_blacklist[n].product, model_num)) {
 			quirks = sil_blacklist[n].quirk;
 			break;
 		}
@@ -380,16 +364,14 @@
 	     (quirks & SIL_QUIRK_MOD15WRITE))) {
 		printk(KERN_INFO "ata%u(%u): applying Seagate errata fix (mod15write workaround)\n",
 		       ap->id, dev->devno);
-		ap->host->max_sectors = 15;
-		ap->host->hostt->max_sectors = 15;
-		dev->flags |= ATA_DFLAG_LOCK_SECTORS;
+		dev->max_sectors = 15;
 		return;
 	}
 
 	/* limit to udma5 */
 	if (quirks & SIL_QUIRK_UDMA5MAX) {
 		printk(KERN_INFO "ata%u(%u): applying Maxtor errata fix %s\n",
-		       ap->id, dev->devno, s);
+		       ap->id, dev->devno, model_num);
 		ap->udma_mask &= ATA_UDMA5;
 		return;
 	}
@@ -431,13 +413,12 @@
 	if (rc)
 		goto err_out_regions;
 
-	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+	probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
 	if (probe_ent == NULL) {
 		rc = -ENOMEM;
 		goto err_out_regions;
 	}
 
-	memset(probe_ent, 0, sizeof(*probe_ent));
 	INIT_LIST_HEAD(&probe_ent->node);
 	probe_ent->dev = pci_dev_to_dev(pdev);
 	probe_ent->port_ops = sil_port_info[ent->driver_data].port_ops;
@@ -474,19 +455,12 @@
 	if (cls) {
 		cls >>= 3;
 		cls++;  /* cls = (line_size/8)+1 */
-		writeb(cls, mmio_base + SIL_FIFO_R0);
-		writeb(cls, mmio_base + SIL_FIFO_W0);
-		writeb(cls, mmio_base + SIL_FIFO_R1);
-		writeb(cls, mmio_base + SIL_FIFO_W1);
-		if (ent->driver_data == sil_3114) {
-			writeb(cls, mmio_base + SIL_FIFO_R2);
-			writeb(cls, mmio_base + SIL_FIFO_W2);
-			writeb(cls, mmio_base + SIL_FIFO_R3);
-			writeb(cls, mmio_base + SIL_FIFO_W3);
-		}
+		for (i = 0; i < probe_ent->n_ports; i++)
+			writew(cls << 8 | cls,
+			       mmio_base + sil_port[i].fifo_cfg);
 	} else
 		dev_printk(KERN_WARNING, &pdev->dev,
-			 "cache line size not set.  Driver may not function\n");
+			   "cache line size not set.  Driver may not function\n");
 
 	/* Apply R_ERR on DMA activate FIS errata workaround */
 	if (probe_ent->host_flags & SIL_FLAG_RERR_ON_DMA_ACT) {
@@ -509,10 +483,10 @@
 		irq_mask = SIL_MASK_4PORT;
 
 		/* flip the magic "make 4 ports work" bit */
-		tmp = readl(mmio_base + SIL_IDE2_BMDMA);
+		tmp = readl(mmio_base + sil_port[2].bmdma);
 		if ((tmp & SIL_INTR_STEERING) == 0)
 			writel(tmp | SIL_INTR_STEERING,
-			       mmio_base + SIL_IDE2_BMDMA);
+			       mmio_base + sil_port[2].bmdma);
 
 	} else {
 		irq_mask = SIL_MASK_2PORT;
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index 9231301..9a53a5e 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -249,9 +249,9 @@
 static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg);
 static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
 static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
-static void sil24_phy_reset(struct ata_port *ap);
+static int sil24_probe_reset(struct ata_port *ap, unsigned int *classes);
 static void sil24_qc_prep(struct ata_queued_cmd *qc);
-static int sil24_qc_issue(struct ata_queued_cmd *qc);
+static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
 static void sil24_irq_clear(struct ata_port *ap);
 static void sil24_eng_timeout(struct ata_port *ap);
 static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
@@ -262,6 +262,7 @@
 
 static const struct pci_device_id sil24_pci_tbl[] = {
 	{ 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 },
+	{ 0x8086, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 },
 	{ 0x1095, 0x3132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3132 },
 	{ 0x1095, 0x3131, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3131 },
 	{ 0x1095, 0x3531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3131 },
@@ -280,11 +281,11 @@
 	.name			= DRV_NAME,
 	.ioctl			= ata_scsi_ioctl,
 	.queuecommand		= ata_scsi_queuecmd,
+	.eh_timed_out		= ata_scsi_timed_out,
 	.eh_strategy_handler	= ata_scsi_error,
 	.can_queue		= ATA_DEF_QUEUE,
 	.this_id		= ATA_SHT_THIS_ID,
 	.sg_tablesize		= LIBATA_MAX_PRD,
-	.max_sectors		= ATA_MAX_SECTORS,
 	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
 	.emulated		= ATA_SHT_EMULATED,
 	.use_clustering		= ATA_SHT_USE_CLUSTERING,
@@ -305,7 +306,7 @@
 
 	.tf_read		= sil24_tf_read,
 
-	.phy_reset		= sil24_phy_reset,
+	.probe_reset		= sil24_probe_reset,
 
 	.qc_prep		= sil24_qc_prep,
 	.qc_issue		= sil24_qc_issue,
@@ -335,8 +336,8 @@
 	{
 		.sht		= &sil24_sht,
 		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-				  ATA_FLAG_SRST | ATA_FLAG_MMIO |
-				  ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(4),
+				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+				  SIL24_NPORTS2FLAG(4),
 		.pio_mask	= 0x1f,			/* pio0-4 */
 		.mwdma_mask	= 0x07,			/* mwdma0-2 */
 		.udma_mask	= 0x3f,			/* udma0-5 */
@@ -346,8 +347,8 @@
 	{
 		.sht		= &sil24_sht,
 		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-				  ATA_FLAG_SRST | ATA_FLAG_MMIO |
-				  ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(2),
+				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+				  SIL24_NPORTS2FLAG(2),
 		.pio_mask	= 0x1f,			/* pio0-4 */
 		.mwdma_mask	= 0x07,			/* mwdma0-2 */
 		.udma_mask	= 0x3f,			/* udma0-5 */
@@ -357,8 +358,8 @@
 	{
 		.sht		= &sil24_sht,
 		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-				  ATA_FLAG_SRST | ATA_FLAG_MMIO |
-				  ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(1),
+				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+				  SIL24_NPORTS2FLAG(1),
 		.pio_mask	= 0x1f,			/* pio0-4 */
 		.mwdma_mask	= 0x07,			/* mwdma0-2 */
 		.udma_mask	= 0x3f,			/* udma0-5 */
@@ -370,7 +371,7 @@
 {
 	void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
 
-	if (ap->cdb_len == 16)
+	if (dev->cdb_len == 16)
 		writel(PORT_CS_CDB16, port + PORT_CTRL_STAT);
 	else
 		writel(PORT_CS_CDB16, port + PORT_CTRL_CLR);
@@ -427,14 +428,23 @@
 	*tf = pp->tf;
 }
 
-static int sil24_issue_SRST(struct ata_port *ap)
+static int sil24_softreset(struct ata_port *ap, int verbose,
+			   unsigned int *class)
 {
 	void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
 	struct sil24_port_priv *pp = ap->private_data;
 	struct sil24_prb *prb = &pp->cmd_block[0].ata.prb;
 	dma_addr_t paddr = pp->cmd_block_dma;
+	unsigned long timeout = jiffies + ATA_TMOUT_BOOT * HZ;
 	u32 irq_enable, irq_stat;
-	int cnt;
+
+	DPRINTK("ENTER\n");
+
+	if (!sata_dev_present(ap)) {
+		DPRINTK("PHY reports no device\n");
+		*class = ATA_DEV_NONE;
+		goto out;
+	}
 
 	/* temporarily turn off IRQs during SRST */
 	irq_enable = readl(port + PORT_IRQ_ENABLE_SET);
@@ -451,7 +461,7 @@
 
 	writel((u32)paddr, port + PORT_CMD_ACTIVATE);
 
-	for (cnt = 0; cnt < 100; cnt++) {
+	do {
 		irq_stat = readl(port + PORT_IRQ_STAT);
 		writel(irq_stat, port + PORT_IRQ_STAT);		/* clear irq */
 
@@ -459,36 +469,42 @@
 		if (irq_stat & (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR))
 			break;
 
-		msleep(1);
-	}
+		msleep(100);
+	} while (time_before(jiffies, timeout));
 
 	/* restore IRQs */
 	writel(irq_enable, port + PORT_IRQ_ENABLE_SET);
 
-	if (!(irq_stat & PORT_IRQ_COMPLETE))
-		return -1;
+	if (!(irq_stat & PORT_IRQ_COMPLETE)) {
+		DPRINTK("EXIT, srst failed\n");
+		return -EIO;
+	}
 
-	/* update TF */
 	sil24_update_tf(ap);
+	*class = ata_dev_classify(&pp->tf);
+
+	if (*class == ATA_DEV_UNKNOWN)
+		*class = ATA_DEV_NONE;
+
+ out:
+	DPRINTK("EXIT, class=%u\n", *class);
 	return 0;
 }
 
-static void sil24_phy_reset(struct ata_port *ap)
+static int sil24_hardreset(struct ata_port *ap, int verbose,
+			   unsigned int *class)
 {
-	struct sil24_port_priv *pp = ap->private_data;
+	unsigned int dummy_class;
 
-	__sata_phy_reset(ap);
-	if (ap->flags & ATA_FLAG_PORT_DISABLED)
-		return;
+	/* sil24 doesn't report device signature after hard reset */
+	return sata_std_hardreset(ap, verbose, &dummy_class);
+}
 
-	if (sil24_issue_SRST(ap) < 0) {
-		printk(KERN_ERR DRV_NAME
-		       " ata%u: SRST failed, disabling port\n", ap->id);
-		ap->ops->port_disable(ap);
-		return;
-	}
-
-	ap->device->class = ata_dev_classify(&pp->tf);
+static int sil24_probe_reset(struct ata_port *ap, unsigned int *classes)
+{
+	return ata_drive_probe_reset(ap, ata_std_probeinit,
+				     sil24_softreset, sil24_hardreset,
+				     ata_std_postreset, classes);
 }
 
 static inline void sil24_fill_sg(struct ata_queued_cmd *qc,
@@ -533,7 +549,7 @@
 		prb = &cb->atapi.prb;
 		sge = cb->atapi.sge;
 		memset(cb->atapi.cdb, 0, 32);
-		memcpy(cb->atapi.cdb, qc->cdb, ap->cdb_len);
+		memcpy(cb->atapi.cdb, qc->cdb, qc->dev->cdb_len);
 
 		if (qc->tf.protocol != ATA_PROT_ATAPI_NODATA) {
 			if (qc->tf.flags & ATA_TFLAG_WRITE)
@@ -557,7 +573,7 @@
 		sil24_fill_sg(qc, sge);
 }
 
-static int sil24_qc_issue(struct ata_queued_cmd *qc)
+static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
 	void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
@@ -638,23 +654,10 @@
 	struct ata_queued_cmd *qc;
 
 	qc = ata_qc_from_tag(ap, ap->active_tag);
-	if (!qc) {
-		printk(KERN_ERR "ata%u: BUG: timeout without command\n",
-		       ap->id);
-		return;
-	}
 
-	/*
-	 * hack alert!  We cannot use the supplied completion
-	 * function from inside the ->eh_strategy_handler() thread.
-	 * libata is the only user of ->eh_strategy_handler() in
-	 * any kernel, so the default scsi_done() assumes it is
-	 * not being called from the SCSI EH.
-	 */
 	printk(KERN_ERR "ata%u: command timeout\n", ap->id);
-	qc->scsidone = scsi_finish_command;
-	qc->err_mask |= AC_ERR_OTHER;
-	ata_qc_complete(qc);
+	qc->err_mask |= AC_ERR_TIMEOUT;
+	ata_eh_qc_complete(qc);
 
 	sil24_reset_controller(ap);
 }
@@ -895,6 +898,7 @@
 	probe_ent->sht		= pinfo->sht;
 	probe_ent->host_flags	= pinfo->host_flags;
 	probe_ent->pio_mask	= pinfo->pio_mask;
+	probe_ent->mwdma_mask	= pinfo->mwdma_mask;
 	probe_ent->udma_mask	= pinfo->udma_mask;
 	probe_ent->port_ops	= pinfo->port_ops;
 	probe_ent->n_ports	= SIL24_FLAG2NPORTS(pinfo->host_flags);
diff --git a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c
index 2df8c56..7fd45f8 100644
--- a/drivers/scsi/sata_sis.c
+++ b/drivers/scsi/sata_sis.c
@@ -87,11 +87,11 @@
 	.name			= DRV_NAME,
 	.ioctl			= ata_scsi_ioctl,
 	.queuecommand		= ata_scsi_queuecmd,
+	.eh_timed_out		= ata_scsi_timed_out,
 	.eh_strategy_handler	= ata_scsi_error,
 	.can_queue		= ATA_DEF_QUEUE,
 	.this_id		= ATA_SHT_THIS_ID,
 	.sg_tablesize		= ATA_MAX_PRD,
-	.max_sectors		= ATA_MAX_SECTORS,
 	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
 	.emulated		= ATA_SHT_EMULATED,
 	.use_clustering		= ATA_SHT_USE_CLUSTERING,
diff --git a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c
index d847256..4aaccd5 100644
--- a/drivers/scsi/sata_svw.c
+++ b/drivers/scsi/sata_svw.c
@@ -288,11 +288,11 @@
 	.name			= DRV_NAME,
 	.ioctl			= ata_scsi_ioctl,
 	.queuecommand		= ata_scsi_queuecmd,
+	.eh_timed_out		= ata_scsi_timed_out,
 	.eh_strategy_handler	= ata_scsi_error,
 	.can_queue		= ATA_DEF_QUEUE,
 	.this_id		= ATA_SHT_THIS_ID,
 	.sg_tablesize		= LIBATA_MAX_PRD,
-	.max_sectors		= ATA_MAX_SECTORS,
 	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
 	.emulated		= ATA_SHT_EMULATED,
 	.use_clustering		= ATA_SHT_USE_CLUSTERING,
diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c
index bc87c16..9f8a768 100644
--- a/drivers/scsi/sata_sx4.c
+++ b/drivers/scsi/sata_sx4.c
@@ -174,7 +174,7 @@
 static void pdc20621_put_to_dimm(struct ata_probe_ent *pe,
 				 void *psource, u32 offset, u32 size);
 static void pdc20621_irq_clear(struct ata_port *ap);
-static int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc);
+static unsigned int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc);
 
 
 static struct scsi_host_template pdc_sata_sht = {
@@ -182,11 +182,11 @@
 	.name			= DRV_NAME,
 	.ioctl			= ata_scsi_ioctl,
 	.queuecommand		= ata_scsi_queuecmd,
+	.eh_timed_out		= ata_scsi_timed_out,
 	.eh_strategy_handler	= ata_scsi_error,
 	.can_queue		= ATA_DEF_QUEUE,
 	.this_id		= ATA_SHT_THIS_ID,
 	.sg_tablesize		= LIBATA_MAX_PRD,
-	.max_sectors		= ATA_MAX_SECTORS,
 	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
 	.emulated		= ATA_SHT_EMULATED,
 	.use_clustering		= ATA_SHT_USE_CLUSTERING,
@@ -460,7 +460,7 @@
 	unsigned int i, idx, total_len = 0, sgt_len;
 	u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ];
 
-	assert(qc->flags & ATA_QCFLAG_DMAMAP);
+	WARN_ON(!(qc->flags & ATA_QCFLAG_DMAMAP));
 
 	VPRINTK("ata%u: ENTER\n", ap->id);
 
@@ -678,7 +678,7 @@
 	}
 }
 
-static int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc)
+static unsigned int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc)
 {
 	switch (qc->tf.protocol) {
 	case ATA_PROT_DMA:
@@ -866,26 +866,12 @@
 	spin_lock_irqsave(&host_set->lock, flags);
 
 	qc = ata_qc_from_tag(ap, ap->active_tag);
-	if (!qc) {
-		printk(KERN_ERR "ata%u: BUG: timeout without command\n",
-		       ap->id);
-		goto out;
-	}
-
-	/* hack alert!  We cannot use the supplied completion
-	 * function from inside the ->eh_strategy_handler() thread.
-	 * libata is the only user of ->eh_strategy_handler() in
-	 * any kernel, so the default scsi_done() assumes it is
-	 * not being called from the SCSI EH.
-	 */
-	qc->scsidone = scsi_finish_command;
 
 	switch (qc->tf.protocol) {
 	case ATA_PROT_DMA:
 	case ATA_PROT_NODATA:
 		printk(KERN_ERR "ata%u: command timeout\n", ap->id);
 		qc->err_mask |= __ac_err_mask(ata_wait_idle(ap));
-		ata_qc_complete(qc);
 		break;
 
 	default:
@@ -895,12 +881,11 @@
 		       ap->id, qc->tf.command, drv_stat);
 
 		qc->err_mask |= ac_err_mask(drv_stat);
-		ata_qc_complete(qc);
 		break;
 	}
 
-out:
 	spin_unlock_irqrestore(&host_set->lock, flags);
+	ata_eh_qc_complete(qc);
 	DPRINTK("EXIT\n");
 }
 
diff --git a/drivers/scsi/sata_uli.c b/drivers/scsi/sata_uli.c
index 9635ca7..37a487b 100644
--- a/drivers/scsi/sata_uli.c
+++ b/drivers/scsi/sata_uli.c
@@ -75,11 +75,11 @@
 	.name			= DRV_NAME,
 	.ioctl			= ata_scsi_ioctl,
 	.queuecommand		= ata_scsi_queuecmd,
+	.eh_timed_out		= ata_scsi_timed_out,
 	.eh_strategy_handler	= ata_scsi_error,
 	.can_queue		= ATA_DEF_QUEUE,
 	.this_id		= ATA_SHT_THIS_ID,
 	.sg_tablesize		= LIBATA_MAX_PRD,
-	.max_sectors		= ATA_MAX_SECTORS,
 	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
 	.emulated		= ATA_SHT_EMULATED,
 	.use_clustering		= ATA_SHT_USE_CLUSTERING,
diff --git a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c
index 6d5b0a7..ff65a0b 100644
--- a/drivers/scsi/sata_via.c
+++ b/drivers/scsi/sata_via.c
@@ -94,11 +94,11 @@
 	.name			= DRV_NAME,
 	.ioctl			= ata_scsi_ioctl,
 	.queuecommand		= ata_scsi_queuecmd,
+	.eh_timed_out		= ata_scsi_timed_out,
 	.eh_strategy_handler	= ata_scsi_error,
 	.can_queue		= ATA_DEF_QUEUE,
 	.this_id		= ATA_SHT_THIS_ID,
 	.sg_tablesize		= LIBATA_MAX_PRD,
-	.max_sectors		= ATA_MAX_SECTORS,
 	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
 	.emulated		= ATA_SHT_EMULATED,
 	.use_clustering		= ATA_SHT_USE_CLUSTERING,
diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c
index e484e8d..b574379 100644
--- a/drivers/scsi/sata_vsc.c
+++ b/drivers/scsi/sata_vsc.c
@@ -251,11 +251,11 @@
 	.name			= DRV_NAME,
 	.ioctl			= ata_scsi_ioctl,
 	.queuecommand		= ata_scsi_queuecmd,
+	.eh_timed_out		= ata_scsi_timed_out,
 	.eh_strategy_handler	= ata_scsi_error,
 	.can_queue		= ATA_DEF_QUEUE,
 	.this_id		= ATA_SHT_THIS_ID,
 	.sg_tablesize		= LIBATA_MAX_PRD,
-	.max_sectors		= ATA_MAX_SECTORS,
 	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
 	.emulated		= ATA_SHT_EMULATED,
 	.use_clustering		= ATA_SHT_USE_CLUSTERING,
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index ff82ccf..5d169a2 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -584,8 +584,7 @@
  *    keep a list of pending commands for final completion, and once we
  *    are ready to leave error handling we handle completion for real.
  **/
-static void scsi_eh_finish_cmd(struct scsi_cmnd *scmd,
-			       struct list_head *done_q)
+void scsi_eh_finish_cmd(struct scsi_cmnd *scmd, struct list_head *done_q)
 {
 	scmd->device->host->host_failed--;
 	scmd->eh_eflags = 0;
@@ -597,6 +596,7 @@
 	scsi_setup_cmd_retry(scmd);
 	list_move_tail(&scmd->eh_entry, done_q);
 }
+EXPORT_SYMBOL(scsi_eh_finish_cmd);
 
 /**
  * scsi_eh_get_sense - Get device sense data.
@@ -1425,7 +1425,7 @@
  * @done_q:	list_head of processed commands.
  *
  **/
-static void scsi_eh_flush_done_q(struct list_head *done_q)
+void scsi_eh_flush_done_q(struct list_head *done_q)
 {
 	struct scsi_cmnd *scmd, *next;
 
@@ -1454,6 +1454,7 @@
 		}
 	}
 }
+EXPORT_SYMBOL(scsi_eh_flush_done_q);
 
 /**
  * scsi_unjam_host - Attempt to fix a host which has a cmd that failed.
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
index 7410e09..00d7c0a 100644
--- a/drivers/serial/s3c2410.c
+++ b/drivers/serial/s3c2410.c
@@ -1066,6 +1066,8 @@
 	port->mapbase	= res->start;
 	port->membase	= S3C24XX_VA_UART + (res->start - S3C24XX_PA_UART);
 	port->irq	= platform_get_irq(platdev, 0);
+	if (port->irq < 0)
+		port->irq = 0;
 
 	ourport->clk	= clk_get(&platdev->dev, "uart");
 
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 85dacc9..b1222cd 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -10,6 +10,7 @@
 config USB_ARCH_HAS_HCD
 	boolean
 	default y if USB_ARCH_HAS_OHCI
+	default y if USB_ARCH_HAS_EHCI
 	default y if ARM				# SL-811
 	default PCI
 
@@ -22,6 +23,7 @@
 	default y if ARCH_LH7A404
 	default y if ARCH_S3C2410
 	default y if PXA27x
+	default y if ARCH_AT91RM9200
 	# PPC:
 	default y if STB03xxx
 	default y if PPC_MPC52xx
@@ -30,6 +32,13 @@
 	# more:
 	default PCI
 
+# some non-PCI hcds implement EHCI
+config USB_ARCH_HAS_EHCI
+	boolean
+	default y if PPC_83xx
+	default y if SOC_AU1200
+	default PCI
+
 # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
 config USB
 	tristate "Support for Host-side USB"
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 36e476d..bb36a1c 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -15,10 +15,9 @@
 obj-$(CONFIG_USB_UHCI_HCD)	+= host/
 obj-$(CONFIG_USB_SL811_HCD)	+= host/
 obj-$(CONFIG_ETRAX_USB_HOST)	+= host/
+obj-$(CONFIG_USB_OHCI_AT91)	+= host/
 
 obj-$(CONFIG_USB_ACM)		+= class/
-obj-$(CONFIG_USB_AUDIO)		+= class/
-obj-$(CONFIG_USB_MIDI)		+= class/
 obj-$(CONFIG_USB_PRINTER)	+= class/
 
 obj-$(CONFIG_USB_STORAGE)	+= storage/
@@ -48,6 +47,7 @@
 obj-$(CONFIG_USB_STV680)	+= media/
 obj-$(CONFIG_USB_VICAM)		+= media/
 obj-$(CONFIG_USB_W9968CF)	+= media/
+obj-$(CONFIG_USB_ZC0301)	+= media/
 
 obj-$(CONFIG_USB_CATC)		+= net/
 obj-$(CONFIG_USB_KAWETH)	+= net/
diff --git a/drivers/usb/class/Kconfig b/drivers/usb/class/Kconfig
index ef105a9..3a9102d 100644
--- a/drivers/usb/class/Kconfig
+++ b/drivers/usb/class/Kconfig
@@ -4,53 +4,6 @@
 comment "USB Device Class drivers"
 	depends on USB
 
-config OBSOLETE_OSS_USB_DRIVER
-	bool "Obsolete OSS USB drivers"
-	depends on USB && SOUND
-	help
-	  This option enables support for the obsolete USB Audio and Midi
-	  drivers that are scheduled for removal in the near future since
-	  there are ALSA drivers for the same hardware.
-
-	  Please contact Adrian Bunk <bunk@stusta.de> if you had to
-	  say Y here because of missing support in the ALSA drivers.
-
-	  If unsure, say N.
-
-config USB_AUDIO
-	tristate "USB Audio support"
-	depends on USB && SOUND && OBSOLETE_OSS_USB_DRIVER
-	help
-	  Say Y here if you want to connect USB audio equipment such as
-	  speakers to your computer's USB port. You only need this if you use
-	  the OSS sound driver; ALSA has its own option for usb audio support.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called audio.
-
-config USB_MIDI
-	tristate "USB MIDI support"
-	depends on USB && SOUND && OBSOLETE_OSS_USB_DRIVER
-	---help---
-	  Say Y here if you want to connect a USB MIDI device to your
-	  computer's USB port.  You only need this if you use the OSS
-	  sound system; USB MIDI devices are supported by ALSA's USB
-	  audio driver. This driver is for devices that comply with
-	  'Universal Serial Bus Device Class Definition for MIDI Device'.
-
-	  The following devices are known to work:
-	  * Steinberg USB2MIDI
-	  * Roland MPU64
-	  * Roland PC-300
-	  * Roland SC8850
-	  * Roland UM-1
-	  * Roland UM-2
-	  * Roland UA-100
-	  * Yamaha MU1000
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called usb-midi.
-
 config USB_ACM
 	tristate "USB Modem (CDC ACM) support"
 	depends on USB
diff --git a/drivers/usb/class/Makefile b/drivers/usb/class/Makefile
index 2294712..cc391e6 100644
--- a/drivers/usb/class/Makefile
+++ b/drivers/usb/class/Makefile
@@ -4,6 +4,4 @@
 #
 
 obj-$(CONFIG_USB_ACM)		+= cdc-acm.o
-obj-$(CONFIG_USB_AUDIO)		+= audio.o
-obj-$(CONFIG_USB_MIDI)		+= usb-midi.o
 obj-$(CONFIG_USB_PRINTER)	+= usblp.o
diff --git a/drivers/usb/class/audio.c b/drivers/usb/class/audio.c
deleted file mode 100644
index 3ad9ee8..0000000
--- a/drivers/usb/class/audio.c
+++ /dev/null
@@ -1,3869 +0,0 @@
-/*****************************************************************************/
-
-/*
- *	audio.c  --  USB Audio Class driver
- *
- *	Copyright (C) 1999, 2000, 2001, 2003, 2004
- *	    Alan Cox (alan@lxorguk.ukuu.org.uk)
- *	    Thomas Sailer (sailer@ife.ee.ethz.ch)
- *
- *	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.
- *
- * Debugging:
- * 	Use the 'lsusb' utility to dump the descriptors.
- *
- * 1999-09-07:  Alan Cox
- *		Parsing Audio descriptor patch
- * 1999-09-08:  Thomas Sailer
- *		Added OSS compatible data io functions; both parts of the
- *		driver remain to be glued together
- * 1999-09-10:  Thomas Sailer
- *		Beautified the driver. Added sample format conversions.
- *		Still not properly glued with the parsing code.
- *		The parsing code seems to have its problems btw,
- *		Since it parses all available configs but doesn't
- *		store which iface/altsetting belongs to which config.
- * 1999-09-20:  Thomas Sailer
- *		Threw out Alan's parsing code and implemented my own one.
- *		You cannot reasonnably linearly parse audio descriptors,
- *		especially the AudioClass descriptors have to be considered
- *		pointer lists. Mixer parsing untested, due to lack of device.
- *		First stab at synch pipe implementation, the Dallas USB DAC
- *		wants to use an Asynch out pipe. usb_audio_state now basically
- *		only contains lists of mixer and wave devices. We can therefore
- *		now have multiple mixer/wave devices per USB device.
- * 1999-10-28:  Thomas Sailer
- *		Converted to URB API. Fixed a taskstate/wakeup semantics mistake
- *		that made the driver consume all available CPU cycles.
- *		Now runs stable on UHCI-Acher/Fliegl/Sailer.
- * 1999-10-31:  Thomas Sailer
- *		Audio can now be unloaded if it is not in use by any mixer
- *		or dsp client (formerly you had to disconnect the audio devices
- *		from the USB port)
- *		Finally, about three months after ordering, my "Maxxtro SPK222"
- *		speakers arrived, isn't disdata a great mail order company 8-)
- *		Parse class specific endpoint descriptor of the audiostreaming
- *		interfaces and take the endpoint attributes from there.
- *		Unbelievably, the Philips USB DAC has a sampling rate range
- *		of over a decade, yet does not support the sampling rate control!
- *		No wonder it sounds so bad, has very audible sampling rate
- *		conversion distortion. Don't try to listen to it using
- *		decent headphones!
- *		"Let's make things better" -> but please Philips start with your
- *		own stuff!!!!
- * 1999-11-02:  Thomas Sailer
- *		It takes the Philips boxes several seconds to acquire synchronisation
- *		that means they won't play short sounds. Should probably maintain
- *		the ISO datastream even if there's nothing to play.
- *		Fix counting the total_bytes counter, RealPlayer G2 depends on it.
- * 1999-12-20:  Thomas Sailer
- *		Fix bad bug in conversion to per interface probing.
- *		disconnect was called multiple times for the audio device,
- *		leading to a premature freeing of the audio structures
- * 2000-05-13:  Thomas Sailer
- *		I don't remember who changed the find_format routine,
- *              but the change was completely broken for the Dallas
- *              chip. Anyway taking sampling rate into account in find_format
- *              is bad and should not be done unless there are devices with
- *              completely broken audio descriptors. Unless someone shows
- *              me such a descriptor, I will not allow find_format to
- *              take the sampling rate into account.
- *              Also, the former find_format made:
- *              - mpg123 play mono instead of stereo
- *              - sox completely fail for wav's with sample rates < 44.1kHz
- *                  for the Dallas chip.
- *              Also fix a rather long standing problem with applications that
- *              use "small" writes producing no sound at all.
- * 2000-05-15:  Thomas Sailer
- *		My fears came true, the Philips camera indeed has pretty stupid
- *              audio descriptors.
- * 2000-05-17:  Thomas Sailer
- *		Nemsoft spotted my stupid last minute change, thanks
- * 2000-05-19:  Thomas Sailer
- *		Fixed FEATURE_UNIT thinkos found thanks to the KC Technology
- *              Xtend device. Basically the driver treated FEATURE_UNIT's sourced
- *              by mono terminals as stereo.
- * 2000-05-20:  Thomas Sailer
- *		SELECTOR support (and thus selecting record channels from the mixer).
- *              Somewhat peculiar due to OSS interface limitations. Only works
- *              for channels where a "slider" is already in front of it (i.e.
- *              a MIXER unit or a FEATURE unit with volume capability).
- * 2000-11-26:  Thomas Sailer
- *              Workaround for Dallas DS4201. The DS4201 uses PCM8 as format tag for
- *              its 8 bit modes, but expects signed data (and should therefore have used PCM).
- * 2001-03-10:  Thomas Sailer
- *              provide abs function, prevent picking up a bogus kernel macro
- *              for abs. Bug report by Andrew Morton <andrewm@uow.edu.au>
- * 2001-06-16:  Bryce Nesbitt <bryce@obviously.com>
- *              Fix SNDCTL_DSP_STEREO API violation
- * 2003-04-08:	Oliver Neukum (oliver@neukum.name):
- *		Setting a configuration is done by usbcore and must not be overridden
- * 2004-02-27:  Workaround for broken synch descriptors
- * 2004-03-07:	Alan Stern <stern@rowland.harvard.edu>
- *		Add usb_ifnum_to_if() and usb_altnum_to_altsetting() support.
- *		Use the in-memory descriptors instead of reading them from the device.
- * 
- */
-
-/*
- * Strategy:
- *
- * Alan Cox and Thomas Sailer are starting to dig at opposite ends and
- * are hoping to meet in the middle, just like tunnel diggers :)
- * Alan tackles the descriptor parsing, Thomas the actual data IO and the
- * OSS compatible interface.
- *
- * Data IO implementation issues
- *
- * A mmap'able ring buffer per direction is implemented, because
- * almost every OSS app expects it. It is however impractical to
- * transmit/receive USB data directly into and out of the ring buffer,
- * due to alignment and synchronisation issues. Instead, the ring buffer
- * feeds a constant time delay line that handles the USB issues.
- *
- * Now we first try to find an alternate setting that exactly matches
- * the sample format requested by the user. If we find one, we do not
- * need to perform any sample rate conversions. If there is no matching
- * altsetting, we choose the closest one and perform sample format
- * conversions. We never do sample rate conversion; these are too
- * expensive to be performed in the kernel.
- *
- * Current status: no known HCD-specific issues.
- *
- * Generally: Due to the brokenness of the Audio Class spec
- * it seems generally impossible to write a generic Audio Class driver,
- * so a reasonable driver should implement the features that are actually
- * used.
- *
- * Parsing implementation issues
- *
- * One cannot reasonably parse the AudioClass descriptors linearly.
- * Therefore the current implementation features routines to look
- * for a specific descriptor in the descriptor list.
- *
- * How does the parsing work? First, all interfaces are searched
- * for an AudioControl class interface. If found, the config descriptor
- * that belongs to the current configuration is searched and
- * the HEADER descriptor is found. It contains a list of
- * all AudioStreaming and MIDIStreaming devices. This list is then walked,
- * and all AudioStreaming interfaces are classified into input and output
- * interfaces (according to the endpoint0 direction in altsetting1) (MIDIStreaming
- * is currently not supported). The input & output list is then used
- * to group inputs and outputs together and issued pairwise to the
- * AudioStreaming class parser. Finally, all OUTPUT_TERMINAL descriptors
- * are walked and issued to the mixer construction routine.
- *
- * The AudioStreaming parser simply enumerates all altsettings belonging
- * to the specified interface. It looks for AS_GENERAL and FORMAT_TYPE
- * class specific descriptors to extract the sample format/sample rate
- * data. Only sample format types PCM and PCM8 are supported right now, and
- * only FORMAT_TYPE_I is handled. The isochronous data endpoint needs to
- * be the first endpoint of the interface, and the optional synchronisation
- * isochronous endpoint the second one.
- *
- * Mixer construction works as follows: The various TERMINAL and UNIT
- * descriptors span a tree from the root (OUTPUT_TERMINAL) through the
- * intermediate nodes (UNITs) to the leaves (INPUT_TERMINAL). We walk
- * that tree in a depth first manner. FEATURE_UNITs may contribute volume,
- * bass and treble sliders to the mixer, MIXER_UNITs volume sliders.
- * The terminal type encoded in the INPUT_TERMINALs feeds a heuristic
- * to determine "meaningful" OSS slider numbers, however we will see
- * how well this works in practice. Other features are not used at the
- * moment, they seem less often used. Also, it seems difficult at least
- * to construct recording source switches from SELECTOR_UNITs, but
- * since there are not many USB ADC's available, we leave that for later.
- */
-
-/*****************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/module.h>
-#include <linux/sound.h>
-#include <linux/soundcard.h>
-#include <linux/list.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/bitops.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <linux/usb.h>
-
-#include "audio.h"
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.0.0"
-#define DRIVER_AUTHOR "Alan Cox <alan@lxorguk.ukuu.org.uk>, Thomas Sailer (sailer@ife.ee.ethz.ch)"
-#define DRIVER_DESC "USB Audio Class driver"
-
-#define AUDIO_DEBUG 1
-
-#define SND_DEV_DSP16   5
-
-#define dprintk(x)
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Linked list of all audio devices...
- */
-static struct list_head audiodevs = LIST_HEAD_INIT(audiodevs);
-static DECLARE_MUTEX(open_sem);
-
-/*
- * wait queue for processes wanting to open an USB audio device
- */
-static DECLARE_WAIT_QUEUE_HEAD(open_wait);
-
-
-#define MAXFORMATS        MAX_ALT
-#define DMABUFSHIFT       17  /* 128k worth of DMA buffer */
-#define NRSGBUF           (1U<<(DMABUFSHIFT-PAGE_SHIFT))
-
-/*
- * This influences:
- * - Latency
- * - Interrupt rate
- * - Synchronisation behaviour
- * Don't touch this if you don't understand all of the above.
- */
-#define DESCFRAMES  5
-#define SYNCFRAMES  DESCFRAMES
-
-#define MIXFLG_STEREOIN   1
-#define MIXFLG_STEREOOUT  2
-
-struct mixerchannel {
-	__u16 value;
-	__u16 osschannel;  /* number of the OSS channel */
-	__s16 minval, maxval;
-	__u16 slctunitid;
-	__u8 unitid;
-	__u8 selector;
-	__u8 chnum;
-	__u8 flags;
-};
-
-struct audioformat {
-	unsigned int format;
-	unsigned int sratelo;
-	unsigned int sratehi;
-	unsigned char altsetting;
-	unsigned char attributes;
-};
-
-struct dmabuf {
-	/* buffer data format */
-	unsigned int format;
-	unsigned int srate;
-	/* physical buffer */
-	unsigned char *sgbuf[NRSGBUF];
-	unsigned bufsize;
-	unsigned numfrag;
-	unsigned fragshift;
-	unsigned wrptr, rdptr;
-	unsigned total_bytes;
-	int count;
-	unsigned error; /* over/underrun */
-	wait_queue_head_t wait;
-	/* redundant, but makes calculations easier */
-	unsigned fragsize;
-	unsigned dmasize;
-	/* OSS stuff */
-	unsigned mapped:1;
-	unsigned ready:1;
-	unsigned ossfragshift;
-	int ossmaxfrags;
-	unsigned subdivision;
-};
-
-struct usb_audio_state;
-
-#define FLG_URB0RUNNING   1
-#define FLG_URB1RUNNING   2
-#define FLG_SYNC0RUNNING  4
-#define FLG_SYNC1RUNNING  8
-#define FLG_RUNNING      16
-#define FLG_CONNECTED    32
-
-struct my_data_urb {
-	struct urb *urb;
-};
-
-struct my_sync_urb {
-	struct urb *urb;
-};
-
-
-struct usb_audiodev {
-	struct list_head list;
-	struct usb_audio_state *state;
-	
-	/* soundcore stuff */
-	int dev_audio;
-
-	/* wave stuff */
-	mode_t open_mode;
-	spinlock_t lock;         /* DMA buffer access spinlock */
-
-	struct usbin {
-		int interface;           /* Interface number, -1 means not used */
-		unsigned int format;     /* USB data format */
-		unsigned int datapipe;   /* the data input pipe */
-		unsigned int syncpipe;   /* the synchronisation pipe - 0 for anything but adaptive IN mode */
-		unsigned int syncinterval;  /* P for adaptive IN mode, 0 otherwise */
-		unsigned int freqn;      /* nominal sampling rate in USB format, i.e. fs/1000 in Q10.14 */
-		unsigned int freqmax;    /* maximum sampling rate, used for buffer management */
-		unsigned int phase;      /* phase accumulator */
-		unsigned int flags;      /* see FLG_ defines */
-		
-		struct my_data_urb durb[2];  /* ISO descriptors for the data endpoint */
-		struct my_sync_urb surb[2];  /* ISO sync pipe descriptor if needed */
-		
-		struct dmabuf dma;
-	} usbin;
-
-	struct usbout {
-		int interface;           /* Interface number, -1 means not used */
-		unsigned int format;     /* USB data format */
-		unsigned int datapipe;   /* the data input pipe */
-		unsigned int syncpipe;   /* the synchronisation pipe - 0 for anything but asynchronous OUT mode */
-		unsigned int syncinterval;  /* P for asynchronous OUT mode, 0 otherwise */
-		unsigned int freqn;      /* nominal sampling rate in USB format, i.e. fs/1000 in Q10.14 */
-		unsigned int freqm;      /* momentary sampling rate in USB format, i.e. fs/1000 in Q10.14 */
-		unsigned int freqmax;    /* maximum sampling rate, used for buffer management */
-		unsigned int phase;      /* phase accumulator */
-		unsigned int flags;      /* see FLG_ defines */
-
-		struct my_data_urb durb[2];  /* ISO descriptors for the data endpoint */
-		struct my_sync_urb surb[2];  /* ISO sync pipe descriptor if needed */
-		
-		struct dmabuf dma;
-	} usbout;
-
-
-	unsigned int numfmtin, numfmtout;
-	struct audioformat fmtin[MAXFORMATS];
-	struct audioformat fmtout[MAXFORMATS];
-};  
-
-struct usb_mixerdev {
-	struct list_head list;
-	struct usb_audio_state *state;
-
-	/* soundcore stuff */
-	int dev_mixer;
-
-	unsigned char iface;  /* interface number of the AudioControl interface */
-
-	/* USB format descriptions */
-	unsigned int numch, modcnt;
-
-	/* mixch is last and gets allocated dynamically */
-	struct mixerchannel ch[0];
-};
-
-struct usb_audio_state {
-	struct list_head audiodev;
-
-	/* USB device */
-	struct usb_device *usbdev;
-
-	struct list_head audiolist;
-	struct list_head mixerlist;
-
-	unsigned count;  /* usage counter; NOTE: the usb stack is also considered a user */
-};
-
-/* private audio format extensions */
-#define AFMT_STEREO        0x80000000
-#define AFMT_ISSTEREO(x)   ((x) & AFMT_STEREO)
-#define AFMT_IS16BIT(x)    ((x) & (AFMT_S16_LE|AFMT_S16_BE|AFMT_U16_LE|AFMT_U16_BE))
-#define AFMT_ISUNSIGNED(x) ((x) & (AFMT_U8|AFMT_U16_LE|AFMT_U16_BE))
-#define AFMT_BYTESSHIFT(x) ((AFMT_ISSTEREO(x) ? 1 : 0) + (AFMT_IS16BIT(x) ? 1 : 0))
-#define AFMT_BYTES(x)      (1<<AFMT_BYTESSHFIT(x))
-
-/* --------------------------------------------------------------------- */
-
-static inline unsigned ld2(unsigned int x)
-{
-	unsigned r = 0;
-	
-	if (x >= 0x10000) {
-		x >>= 16;
-		r += 16;
-	}
-	if (x >= 0x100) {
-		x >>= 8;
-		r += 8;
-	}
-	if (x >= 0x10) {
-		x >>= 4;
-		r += 4;
-	}
-	if (x >= 4) {
-		x >>= 2;
-		r += 2;
-	}
-	if (x >= 2)
-		r++;
-	return r;
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * OSS compatible ring buffer management. The ring buffer may be mmap'ed into
- * an application address space.
- *
- * I first used the rvmalloc stuff copied from bttv. Alan Cox did not like it, so
- * we now use an array of pointers to a single page each. This saves us the
- * kernel page table manipulations, but we have to do a page table alike mechanism
- * (though only one indirection) in software.
- */
-
-static void dmabuf_release(struct dmabuf *db)
-{
-	unsigned int nr;
-	void *p;
-
-	for(nr = 0; nr < NRSGBUF; nr++) {
-		if (!(p = db->sgbuf[nr]))
-			continue;
-		ClearPageReserved(virt_to_page(p));
-		free_page((unsigned long)p);
-		db->sgbuf[nr] = NULL;
-	}
-	db->mapped = db->ready = 0;
-}
-
-static int dmabuf_init(struct dmabuf *db)
-{
-	unsigned int nr, bytepersec, bufs;
-	void *p;
-
-	/* initialize some fields */
-	db->rdptr = db->wrptr = db->total_bytes = db->count = db->error = 0;
-	/* calculate required buffer size */
-	bytepersec = db->srate << AFMT_BYTESSHIFT(db->format);
-	bufs = 1U << DMABUFSHIFT;
-	if (db->ossfragshift) {
-		if ((1000 << db->ossfragshift) < bytepersec)
-			db->fragshift = ld2(bytepersec/1000);
-		else
-			db->fragshift = db->ossfragshift;
-	} else {
-		db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1));
-		if (db->fragshift < 3)
-			db->fragshift = 3;
-	}
-	db->numfrag = bufs >> db->fragshift;
-	while (db->numfrag < 4 && db->fragshift > 3) {
-		db->fragshift--;
-		db->numfrag = bufs >> db->fragshift;
-	}
-	db->fragsize = 1 << db->fragshift;
-	if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
-		db->numfrag = db->ossmaxfrags;
-	db->dmasize = db->numfrag << db->fragshift;
-	for(nr = 0; nr < NRSGBUF; nr++) {
-		if (!db->sgbuf[nr]) {
-			p = (void *)get_zeroed_page(GFP_KERNEL);
-			if (!p)
-				return -ENOMEM;
-			db->sgbuf[nr] = p;
-			SetPageReserved(virt_to_page(p));
-		}
-		memset(db->sgbuf[nr], AFMT_ISUNSIGNED(db->format) ? 0x80 : 0, PAGE_SIZE);
-		if ((nr << PAGE_SHIFT) >= db->dmasize)
-			break;
-	}
-	db->bufsize = nr << PAGE_SHIFT;
-	db->ready = 1;
-	dprintk((KERN_DEBUG "usbaudio: dmabuf_init bytepersec %d bufs %d ossfragshift %d ossmaxfrags %d "
-	         "fragshift %d fragsize %d numfrag %d dmasize %d bufsize %d fmt 0x%x srate %d\n",
-	         bytepersec, bufs, db->ossfragshift, db->ossmaxfrags, db->fragshift, db->fragsize,
-	         db->numfrag, db->dmasize, db->bufsize, db->format, db->srate));
-	return 0;
-}
-
-static int dmabuf_mmap(struct vm_area_struct *vma, struct dmabuf *db, unsigned long start, unsigned long size, pgprot_t prot)
-{
-	unsigned int nr;
-
-	if (!db->ready || db->mapped || (start | size) & (PAGE_SIZE-1) || size > db->bufsize)
-		return -EINVAL;
-	size >>= PAGE_SHIFT;
-	for(nr = 0; nr < size; nr++)
-		if (!db->sgbuf[nr])
-			return -EINVAL;
-	db->mapped = 1;
-	for(nr = 0; nr < size; nr++) {
-		unsigned long pfn;
-
-		pfn = virt_to_phys(db->sgbuf[nr]) >> PAGE_SHIFT;
-		if (remap_pfn_range(vma, start, pfn, PAGE_SIZE, prot))
-			return -EAGAIN;
-		start += PAGE_SIZE;
-	}
-	return 0;
-}
-
-static void dmabuf_copyin(struct dmabuf *db, const void *buffer, unsigned int size)
-{
-	unsigned int pgrem, rem;
-
-	db->total_bytes += size;
-	for (;;) {
-		if (size <= 0)
-			return;
-		pgrem = ((~db->wrptr) & (PAGE_SIZE-1)) + 1;
-		if (pgrem > size)
-			pgrem = size;
-		rem = db->dmasize - db->wrptr;
-		if (pgrem > rem)
-			pgrem = rem;
-		memcpy((db->sgbuf[db->wrptr >> PAGE_SHIFT]) + (db->wrptr & (PAGE_SIZE-1)), buffer, pgrem);
-		size -= pgrem;
-		buffer += pgrem;
-		db->wrptr += pgrem;
-		if (db->wrptr >= db->dmasize)
-			db->wrptr = 0;
-	}
-}
-
-static void dmabuf_copyout(struct dmabuf *db, void *buffer, unsigned int size)
-{
-	unsigned int pgrem, rem;
-
-	db->total_bytes += size;
-	for (;;) {
-		if (size <= 0)
-			return;
-		pgrem = ((~db->rdptr) & (PAGE_SIZE-1)) + 1;
-		if (pgrem > size)
-			pgrem = size;
-		rem = db->dmasize - db->rdptr;
-		if (pgrem > rem)
-			pgrem = rem;
-		memcpy(buffer, (db->sgbuf[db->rdptr >> PAGE_SHIFT]) + (db->rdptr & (PAGE_SIZE-1)), pgrem);
-		size -= pgrem;
-		buffer += pgrem;
-		db->rdptr += pgrem;
-		if (db->rdptr >= db->dmasize)
-			db->rdptr = 0;
-	}
-}
-
-static int dmabuf_copyin_user(struct dmabuf *db, unsigned int ptr, const void __user *buffer, unsigned int size)
-{
-	unsigned int pgrem, rem;
-
-	if (!db->ready || db->mapped)
-		return -EINVAL;
-	for (;;) {
-		if (size <= 0)
-			return 0;
-		pgrem = ((~ptr) & (PAGE_SIZE-1)) + 1;
-		if (pgrem > size)
-			pgrem = size;
-		rem = db->dmasize - ptr;
-		if (pgrem > rem)
-			pgrem = rem;
-		if (copy_from_user((db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), buffer, pgrem))
-			return -EFAULT;
-		size -= pgrem;
-		buffer += pgrem;
-		ptr += pgrem;
-		if (ptr >= db->dmasize)
-			ptr = 0;
-	}
-}
-
-static int dmabuf_copyout_user(struct dmabuf *db, unsigned int ptr, void __user *buffer, unsigned int size)
-{
-	unsigned int pgrem, rem;
-
-	if (!db->ready || db->mapped)
-		return -EINVAL;
-	for (;;) {
-		if (size <= 0)
-			return 0;
-		pgrem = ((~ptr) & (PAGE_SIZE-1)) + 1;
-		if (pgrem > size)
-			pgrem = size;
-		rem = db->dmasize - ptr;
-		if (pgrem > rem)
-			pgrem = rem;
-		if (copy_to_user(buffer, (db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), pgrem))
-			return -EFAULT;
-		size -= pgrem;
-		buffer += pgrem;
-		ptr += pgrem;
-		if (ptr >= db->dmasize)
-			ptr = 0;
-	}
-}
-
-/* --------------------------------------------------------------------- */
-/*
- * USB I/O code. We do sample format conversion if necessary
- */
-
-static void usbin_stop(struct usb_audiodev *as)
-{
-	struct usbin *u = &as->usbin;
-	unsigned long flags;
-	unsigned int i, notkilled = 1;
-
-	spin_lock_irqsave(&as->lock, flags);
-	u->flags &= ~FLG_RUNNING;
-	i = u->flags;
-	spin_unlock_irqrestore(&as->lock, flags);
-	while (i & (FLG_URB0RUNNING|FLG_URB1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) {
-		if (notkilled)
-			schedule_timeout_interruptible(1);
-		else
-			schedule_timeout_uninterruptible(1);
-		spin_lock_irqsave(&as->lock, flags);
-		i = u->flags;
-		spin_unlock_irqrestore(&as->lock, flags);
-		if (notkilled && signal_pending(current)) {
-			if (i & FLG_URB0RUNNING)
-				usb_kill_urb(u->durb[0].urb);
-			if (i & FLG_URB1RUNNING)
-				usb_kill_urb(u->durb[1].urb);
-			if (i & FLG_SYNC0RUNNING)
-				usb_kill_urb(u->surb[0].urb);
-			if (i & FLG_SYNC1RUNNING)
-				usb_kill_urb(u->surb[1].urb);
-			notkilled = 0;
-		}
-	}
-	set_current_state(TASK_RUNNING);
-	kfree(u->durb[0].urb->transfer_buffer);
-	kfree(u->durb[1].urb->transfer_buffer);
-	kfree(u->surb[0].urb->transfer_buffer);
-	kfree(u->surb[1].urb->transfer_buffer);
-	u->durb[0].urb->transfer_buffer = u->durb[1].urb->transfer_buffer = 
-		u->surb[0].urb->transfer_buffer = u->surb[1].urb->transfer_buffer = NULL;
-}
-
-static inline void usbin_release(struct usb_audiodev *as)
-{
-	usbin_stop(as);
-}
-
-static void usbin_disc(struct usb_audiodev *as)
-{
-	struct usbin *u = &as->usbin;
-
-	unsigned long flags;
-
-	spin_lock_irqsave(&as->lock, flags);
-	u->flags &= ~(FLG_RUNNING | FLG_CONNECTED);
-	spin_unlock_irqrestore(&as->lock, flags);
-	usbin_stop(as);
-}
-
-static void conversion(const void *ibuf, unsigned int ifmt, void *obuf, unsigned int ofmt, void *tmp, unsigned int scnt)
-{
-	unsigned int cnt, i;
-	__s16 *sp, *sp2, s;
-	unsigned char *bp;
-
-	cnt = scnt;
-	if (AFMT_ISSTEREO(ifmt))
-		cnt <<= 1;
-	sp = ((__s16 *)tmp) + cnt;
-	switch (ifmt & ~AFMT_STEREO) {
-	case AFMT_U8:
-		for (bp = ((unsigned char *)ibuf)+cnt, i = 0; i < cnt; i++) {
-			bp--;
-			sp--;
-			*sp = (*bp ^ 0x80) << 8;
-		}
-		break;
-			
-	case AFMT_S8:
-		for (bp = ((unsigned char *)ibuf)+cnt, i = 0; i < cnt; i++) {
-			bp--;
-			sp--;
-			*sp = *bp << 8;
-		}
-		break;
-		
-	case AFMT_U16_LE:
-		for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) {
-			bp -= 2;
-			sp--;
-			*sp = (bp[0] | (bp[1] << 8)) ^ 0x8000;
-		}
-		break;
-
-	case AFMT_U16_BE:
-		for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) {
-			bp -= 2;
-			sp--;
-			*sp = (bp[1] | (bp[0] << 8)) ^ 0x8000;
-		}
-		break;
-
-	case AFMT_S16_LE:
-		for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) {
-			bp -= 2;
-			sp--;
-			*sp = bp[0] | (bp[1] << 8);
-		}
-		break;
-
-	case AFMT_S16_BE:
-		for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) {
-			bp -= 2;
-			sp--;
-			*sp = bp[1] | (bp[0] << 8);
-		}
-		break;
-	}
-	if (!AFMT_ISSTEREO(ifmt) && AFMT_ISSTEREO(ofmt)) {
-		/* expand from mono to stereo */
-		for (sp = ((__s16 *)tmp)+scnt, sp2 = ((__s16 *)tmp)+2*scnt, i = 0; i < scnt; i++) {
-			sp--;
-			sp2 -= 2;
-			sp2[0] = sp2[1] = sp[0];
-		}
-	}
-	if (AFMT_ISSTEREO(ifmt) && !AFMT_ISSTEREO(ofmt)) {
-		/* contract from stereo to mono */
-		for (sp = sp2 = ((__s16 *)tmp), i = 0; i < scnt; i++, sp++, sp2 += 2)
-			sp[0] = (sp2[0] + sp2[1]) >> 1;
-	}
-	cnt = scnt;
-	if (AFMT_ISSTEREO(ofmt))
-		cnt <<= 1;
-	sp = ((__s16 *)tmp);
-	bp = ((unsigned char *)obuf);
-	switch (ofmt & ~AFMT_STEREO) {
-	case AFMT_U8:
-		for (i = 0; i < cnt; i++, sp++, bp++)
-			*bp = (*sp >> 8) ^ 0x80;
-		break;
-
-	case AFMT_S8:
-		for (i = 0; i < cnt; i++, sp++, bp++)
-			*bp = *sp >> 8;
-		break;
-
-	case AFMT_U16_LE:
-		for (i = 0; i < cnt; i++, sp++, bp += 2) {
-			s = *sp;
-			bp[0] = s;
-			bp[1] = (s >> 8) ^ 0x80;
-		}
-		break;
-
-	case AFMT_U16_BE:
-		for (i = 0; i < cnt; i++, sp++, bp += 2) {
-			s = *sp;
-			bp[1] = s;
-			bp[0] = (s >> 8) ^ 0x80;
-		}
-		break;
-
-	case AFMT_S16_LE:
-		for (i = 0; i < cnt; i++, sp++, bp += 2) {
-			s = *sp;
-			bp[0] = s;
-			bp[1] = s >> 8;
-		}
-		break;
-
-	case AFMT_S16_BE:
-		for (i = 0; i < cnt; i++, sp++, bp += 2) {
-			s = *sp;
-			bp[1] = s;
-			bp[0] = s >> 8;
-		}
-		break;
-	}
-	
-}
-
-static void usbin_convert(struct usbin *u, unsigned char *buffer, unsigned int samples)
-{
-	union {
-		__s16 s[64];
-		unsigned char b[0];
-	} tmp;
-	unsigned int scnt, maxs, ufmtsh, dfmtsh;
-
-	ufmtsh = AFMT_BYTESSHIFT(u->format);
-	dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
-	maxs = (AFMT_ISSTEREO(u->dma.format | u->format)) ? 32 : 64;
-	while (samples > 0) {
-		scnt = samples;
-		if (scnt > maxs)
-			scnt = maxs;
-		conversion(buffer, u->format, tmp.b, u->dma.format, tmp.b, scnt);
-		dmabuf_copyin(&u->dma, tmp.b, scnt << dfmtsh);
-		buffer += scnt << ufmtsh;
-		samples -= scnt;
-	}
-}		
-
-static int usbin_prepare_desc(struct usbin *u, struct urb *urb)
-{
-	unsigned int i, maxsize, offs;
-
-	maxsize = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format));
-	//printk(KERN_DEBUG "usbin_prepare_desc: maxsize %d freq 0x%x format 0x%x\n", maxsize, u->freqn, u->format);
-	for (i = offs = 0; i < DESCFRAMES; i++, offs += maxsize) {
-		urb->iso_frame_desc[i].length = maxsize;
-		urb->iso_frame_desc[i].offset = offs;
-	}
-	urb->interval = 1;
-	return 0;
-}
-
-/*
- * return value: 0 if descriptor should be restarted, -1 otherwise
- * convert sample format on the fly if necessary
- */
-static int usbin_retire_desc(struct usbin *u, struct urb *urb)
-{
-	unsigned int i, ufmtsh, dfmtsh, err = 0, cnt, scnt, dmafree;
-	unsigned char *cp;
-
-	ufmtsh = AFMT_BYTESSHIFT(u->format);
-	dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
-	for (i = 0; i < DESCFRAMES; i++) {
-		cp = ((unsigned char *)urb->transfer_buffer) + urb->iso_frame_desc[i].offset;
-		if (urb->iso_frame_desc[i].status) {
-			dprintk((KERN_DEBUG "usbin_retire_desc: frame %u status %d\n", i, urb->iso_frame_desc[i].status));
-			continue;
-		}
-		scnt = urb->iso_frame_desc[i].actual_length >> ufmtsh;
-		if (!scnt)
-			continue;
-		cnt = scnt << dfmtsh;
-		if (!u->dma.mapped) {
-			dmafree = u->dma.dmasize - u->dma.count;
-			if (cnt > dmafree) {
-				scnt = dmafree >> dfmtsh;
-				cnt = scnt << dfmtsh;
-				err++;
-			}
-		}
-		u->dma.count += cnt;
-		if (u->format == u->dma.format) {
-			/* we do not need format conversion */
-			dprintk((KERN_DEBUG "usbaudio: no sample format conversion\n"));
-			dmabuf_copyin(&u->dma, cp, cnt);
-		} else {
-			/* we need sampling format conversion */
-			dprintk((KERN_DEBUG "usbaudio: sample format conversion %x != %x\n", u->format, u->dma.format));
-			usbin_convert(u, cp, scnt);
-		}
-	}
-	if (err)
-		u->dma.error++;
-	if (u->dma.count >= (signed)u->dma.fragsize)
-		wake_up(&u->dma.wait);
-	return err ? -1 : 0;
-}
-
-static void usbin_completed(struct urb *urb, struct pt_regs *regs)
-{
-	struct usb_audiodev *as = (struct usb_audiodev *)urb->context;
-	struct usbin *u = &as->usbin;
-	unsigned long flags;
-	unsigned int mask;
-	int suret = 0;
-
-#if 0
-	printk(KERN_DEBUG "usbin_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
-#endif
-	if (urb == u->durb[0].urb)
-		mask = FLG_URB0RUNNING;
-	else if (urb == u->durb[1].urb)
-		mask = FLG_URB1RUNNING;
-	else {
-		mask = 0;
-		printk(KERN_ERR "usbin_completed: panic: unknown URB\n");
-	}
-	urb->dev = as->state->usbdev;
-	spin_lock_irqsave(&as->lock, flags);
-	if (!usbin_retire_desc(u, urb) &&
-	    u->flags & FLG_RUNNING &&
-	    !usbin_prepare_desc(u, urb) && 
-	    (suret = usb_submit_urb(urb, GFP_ATOMIC)) == 0) {
-		u->flags |= mask;
-	} else {
-		u->flags &= ~(mask | FLG_RUNNING);
-		wake_up(&u->dma.wait);
-		printk(KERN_DEBUG "usbin_completed: descriptor not restarted (usb_submit_urb: %d)\n", suret);
-	}
-	spin_unlock_irqrestore(&as->lock, flags);
-}
-
-/*
- * we output sync data
- */
-static int usbin_sync_prepare_desc(struct usbin *u, struct urb *urb)
-{
-	unsigned char *cp = urb->transfer_buffer;
-	unsigned int i, offs;
-	
-	for (i = offs = 0; i < SYNCFRAMES; i++, offs += 3, cp += 3) {
-		urb->iso_frame_desc[i].length = 3;
-		urb->iso_frame_desc[i].offset = offs;
-		cp[0] = u->freqn;
-		cp[1] = u->freqn >> 8;
-		cp[2] = u->freqn >> 16;
-	}
-	urb->interval = 1;
-	return 0;
-}
-
-/*
- * return value: 0 if descriptor should be restarted, -1 otherwise
- */
-static int usbin_sync_retire_desc(struct usbin *u, struct urb *urb)
-{
-	unsigned int i;
-	
-	for (i = 0; i < SYNCFRAMES; i++)
-		if (urb->iso_frame_desc[0].status)
-			dprintk((KERN_DEBUG "usbin_sync_retire_desc: frame %u status %d\n", i, urb->iso_frame_desc[i].status));
-	return 0;
-}
-
-static void usbin_sync_completed(struct urb *urb, struct pt_regs *regs)
-{
-	struct usb_audiodev *as = (struct usb_audiodev *)urb->context;
-	struct usbin *u = &as->usbin;
-	unsigned long flags;
-	unsigned int mask;
-	int suret = 0;
-
-#if 0
-	printk(KERN_DEBUG "usbin_sync_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
-#endif
-	if (urb == u->surb[0].urb)
-		mask = FLG_SYNC0RUNNING;
-	else if (urb == u->surb[1].urb)
-		mask = FLG_SYNC1RUNNING;
-	else {
-		mask = 0;
-		printk(KERN_ERR "usbin_sync_completed: panic: unknown URB\n");
-	}
-	urb->dev = as->state->usbdev;
-	spin_lock_irqsave(&as->lock, flags);
-	if (!usbin_sync_retire_desc(u, urb) &&
-	    u->flags & FLG_RUNNING &&
-	    !usbin_sync_prepare_desc(u, urb) && 
-	    (suret = usb_submit_urb(urb, GFP_ATOMIC)) == 0) {
-		u->flags |= mask;
-	} else {
-		u->flags &= ~(mask | FLG_RUNNING);
-		wake_up(&u->dma.wait);
-		dprintk((KERN_DEBUG "usbin_sync_completed: descriptor not restarted (usb_submit_urb: %d)\n", suret));
-	}
-	spin_unlock_irqrestore(&as->lock, flags);
-}
-
-static int usbin_start(struct usb_audiodev *as)
-{
-	struct usb_device *dev = as->state->usbdev;
-	struct usbin *u = &as->usbin;
-	struct urb *urb;
-	unsigned long flags;
-	unsigned int maxsze, bufsz;
-
-#if 0
-	printk(KERN_DEBUG "usbin_start: device %d ufmt 0x%08x dfmt 0x%08x srate %d\n",
-	       dev->devnum, u->format, u->dma.format, u->dma.srate);
-#endif
-	/* allocate USB storage if not already done */
-	spin_lock_irqsave(&as->lock, flags);
-	if (!(u->flags & FLG_CONNECTED)) {
-		spin_unlock_irqrestore(&as->lock, flags);
-		return -EIO;
-	}
-	if (!(u->flags & FLG_RUNNING)) {
-		spin_unlock_irqrestore(&as->lock, flags);
-		u->freqn = ((u->dma.srate << 11) + 62) / 125; /* this will overflow at approx 2MSPS */
-		u->freqmax = u->freqn + (u->freqn >> 2);
-		u->phase = 0;
-		maxsze = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format));
-		bufsz = DESCFRAMES * maxsze;
-		kfree(u->durb[0].urb->transfer_buffer);
-		u->durb[0].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
-		u->durb[0].urb->transfer_buffer_length = bufsz;
-		kfree(u->durb[1].urb->transfer_buffer);
-		u->durb[1].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
-		u->durb[1].urb->transfer_buffer_length = bufsz;
-		if (u->syncpipe) {
-			kfree(u->surb[0].urb->transfer_buffer);
-			u->surb[0].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
-			u->surb[0].urb->transfer_buffer_length = 3*SYNCFRAMES;
-			kfree(u->surb[1].urb->transfer_buffer);
-			u->surb[1].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
-			u->surb[1].urb->transfer_buffer_length = 3*SYNCFRAMES;
-		}
-		if (!u->durb[0].urb->transfer_buffer || !u->durb[1].urb->transfer_buffer || 
-		    (u->syncpipe && (!u->surb[0].urb->transfer_buffer || !u->surb[1].urb->transfer_buffer))) {
-			printk(KERN_ERR "usbaudio: cannot start playback device %d\n", dev->devnum);
-			return 0;
-		}
-		spin_lock_irqsave(&as->lock, flags);
-	}
-	if (u->dma.count >= u->dma.dmasize && !u->dma.mapped) {
-		spin_unlock_irqrestore(&as->lock, flags);
-		return 0;
-	}
-	u->flags |= FLG_RUNNING;
-	if (!(u->flags & FLG_URB0RUNNING)) {
-		urb = u->durb[0].urb;
-		urb->dev = dev;
-		urb->pipe = u->datapipe;
-		urb->transfer_flags = URB_ISO_ASAP;
-		urb->number_of_packets = DESCFRAMES;
-		urb->context = as;
-		urb->complete = usbin_completed;
-		if (!usbin_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_KERNEL))
-			u->flags |= FLG_URB0RUNNING;
-		else
-			u->flags &= ~FLG_RUNNING;
-	}
-	if (u->flags & FLG_RUNNING && !(u->flags & FLG_URB1RUNNING)) {
-		urb = u->durb[1].urb;
-		urb->dev = dev;
-		urb->pipe = u->datapipe;
-		urb->transfer_flags = URB_ISO_ASAP;
-		urb->number_of_packets = DESCFRAMES;
-		urb->context = as;
-		urb->complete = usbin_completed;
-		if (!usbin_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_KERNEL))
-			u->flags |= FLG_URB1RUNNING;
-		else
-			u->flags &= ~FLG_RUNNING;
-	}
-	if (u->syncpipe) {
-		if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC0RUNNING)) {
-			urb = u->surb[0].urb;
-			urb->dev = dev;
-			urb->pipe = u->syncpipe;
-			urb->transfer_flags = URB_ISO_ASAP;
-			urb->number_of_packets = SYNCFRAMES;
-			urb->context = as;
-			urb->complete = usbin_sync_completed;
-			/* stride: u->syncinterval */
-			if (!usbin_sync_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_KERNEL))
-				u->flags |= FLG_SYNC0RUNNING;
-			else
-				u->flags &= ~FLG_RUNNING;
-		}
-		if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC1RUNNING)) {
-			urb = u->surb[1].urb;
-			urb->dev = dev;
-			urb->pipe = u->syncpipe;
-			urb->transfer_flags = URB_ISO_ASAP;
-			urb->number_of_packets = SYNCFRAMES;
-			urb->context = as;
-			urb->complete = usbin_sync_completed;
-			/* stride: u->syncinterval */
-			if (!usbin_sync_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_KERNEL))
-				u->flags |= FLG_SYNC1RUNNING;
-			else
-				u->flags &= ~FLG_RUNNING;
-		}
-	}
-	spin_unlock_irqrestore(&as->lock, flags);
-	return 0;
-}
-
-static void usbout_stop(struct usb_audiodev *as)
-{
-	struct usbout *u = &as->usbout;
-	unsigned long flags;
-	unsigned int i, notkilled = 1;
-
-	spin_lock_irqsave(&as->lock, flags);
-	u->flags &= ~FLG_RUNNING;
-	i = u->flags;
-	spin_unlock_irqrestore(&as->lock, flags);
-	while (i & (FLG_URB0RUNNING|FLG_URB1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) {
-		if (notkilled)
-			schedule_timeout_interruptible(1);
-		else
-			schedule_timeout_uninterruptible(1);
-		spin_lock_irqsave(&as->lock, flags);
-		i = u->flags;
-		spin_unlock_irqrestore(&as->lock, flags);
-		if (notkilled && signal_pending(current)) {
-			if (i & FLG_URB0RUNNING)
-				usb_kill_urb(u->durb[0].urb);
-			if (i & FLG_URB1RUNNING)
-				usb_kill_urb(u->durb[1].urb);
-			if (i & FLG_SYNC0RUNNING)
-				usb_kill_urb(u->surb[0].urb);
-			if (i & FLG_SYNC1RUNNING)
-				usb_kill_urb(u->surb[1].urb);
-			notkilled = 0;
-		}
-	}
-	set_current_state(TASK_RUNNING);
-	kfree(u->durb[0].urb->transfer_buffer);
-	kfree(u->durb[1].urb->transfer_buffer);
-	kfree(u->surb[0].urb->transfer_buffer);
-	kfree(u->surb[1].urb->transfer_buffer);
-	u->durb[0].urb->transfer_buffer = u->durb[1].urb->transfer_buffer = 
-		u->surb[0].urb->transfer_buffer = u->surb[1].urb->transfer_buffer = NULL;
-}
-
-static inline void usbout_release(struct usb_audiodev *as)
-{
-	usbout_stop(as);
-}
-
-static void usbout_disc(struct usb_audiodev *as)
-{
-	struct usbout *u = &as->usbout;
-	unsigned long flags;
-
-	spin_lock_irqsave(&as->lock, flags);
-	u->flags &= ~(FLG_RUNNING | FLG_CONNECTED);
-	spin_unlock_irqrestore(&as->lock, flags);
-	usbout_stop(as);
-}
-
-static void usbout_convert(struct usbout *u, unsigned char *buffer, unsigned int samples)
-{
-	union {
-		__s16 s[64];
-		unsigned char b[0];
-	} tmp;
-	unsigned int scnt, maxs, ufmtsh, dfmtsh;
-
-	ufmtsh = AFMT_BYTESSHIFT(u->format);
-	dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
-	maxs = (AFMT_ISSTEREO(u->dma.format | u->format)) ? 32 : 64;
-	while (samples > 0) {
-		scnt = samples;
-		if (scnt > maxs)
-			scnt = maxs;
-		dmabuf_copyout(&u->dma, tmp.b, scnt << dfmtsh);
-		conversion(tmp.b, u->dma.format, buffer, u->format, tmp.b, scnt);
-		buffer += scnt << ufmtsh;
-		samples -= scnt;
-	}
-}		
-
-static int usbout_prepare_desc(struct usbout *u, struct urb *urb)
-{
-	unsigned int i, ufmtsh, dfmtsh, err = 0, cnt, scnt, offs;
-	unsigned char *cp = urb->transfer_buffer;
-
-	ufmtsh = AFMT_BYTESSHIFT(u->format);
-	dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
-	for (i = offs = 0; i < DESCFRAMES; i++) {
-		urb->iso_frame_desc[i].offset = offs;
-		u->phase = (u->phase & 0x3fff) + u->freqm;
-		scnt = u->phase >> 14;
-		if (!scnt) {
-			urb->iso_frame_desc[i].length = 0;
-			continue;
-		}
-		cnt = scnt << dfmtsh;
-		if (!u->dma.mapped) {
-			if (cnt > u->dma.count) {
-				scnt = u->dma.count >> dfmtsh;
-				cnt = scnt << dfmtsh;
-				err++;
-			}
-			u->dma.count -= cnt;
-		} else
-			u->dma.count += cnt;
-		if (u->format == u->dma.format) {
-			/* we do not need format conversion */
-			dmabuf_copyout(&u->dma, cp, cnt);
-		} else {
-			/* we need sampling format conversion */
-			usbout_convert(u, cp, scnt);
-		}
-		cnt = scnt << ufmtsh;
-		urb->iso_frame_desc[i].length = cnt;
-		offs += cnt;
-		cp += cnt;
-	}
-	urb->interval = 1;
-	if (err)
-		u->dma.error++;
-	if (u->dma.mapped) {
-		if (u->dma.count >= (signed)u->dma.fragsize)
-			wake_up(&u->dma.wait);
-	} else {
-		if ((signed)u->dma.dmasize >= u->dma.count + (signed)u->dma.fragsize)
-			wake_up(&u->dma.wait);
-	}
-	return err ? -1 : 0;
-}
-
-/*
- * return value: 0 if descriptor should be restarted, -1 otherwise
- */
-static int usbout_retire_desc(struct usbout *u, struct urb *urb)
-{
-	unsigned int i;
-
-	for (i = 0; i < DESCFRAMES; i++) {
-		if (urb->iso_frame_desc[i].status) {
-			dprintk((KERN_DEBUG "usbout_retire_desc: frame %u status %d\n", i, urb->iso_frame_desc[i].status));
-			continue;
-		}
-	}
-	return 0;
-}
-
-static void usbout_completed(struct urb *urb, struct pt_regs *regs)
-{
-	struct usb_audiodev *as = (struct usb_audiodev *)urb->context;
-	struct usbout *u = &as->usbout;
-	unsigned long flags;
-	unsigned int mask;
-	int suret = 0;
-
-#if 0
-	printk(KERN_DEBUG "usbout_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
-#endif
-	if (urb == u->durb[0].urb)
-		mask = FLG_URB0RUNNING;
-	else if (urb == u->durb[1].urb)
-		mask = FLG_URB1RUNNING;
-	else {
-		mask = 0;
-		printk(KERN_ERR "usbout_completed: panic: unknown URB\n");
-	}
-	urb->dev = as->state->usbdev;
-	spin_lock_irqsave(&as->lock, flags);
-	if (!usbout_retire_desc(u, urb) &&
-	    u->flags & FLG_RUNNING &&
-	    !usbout_prepare_desc(u, urb) && 
-	    (suret = usb_submit_urb(urb, GFP_ATOMIC)) == 0) {
-		u->flags |= mask;
-	} else {
-		u->flags &= ~(mask | FLG_RUNNING);
-		wake_up(&u->dma.wait);
-		dprintk((KERN_DEBUG "usbout_completed: descriptor not restarted (usb_submit_urb: %d)\n", suret));
-	}
-	spin_unlock_irqrestore(&as->lock, flags);
-}
-
-static int usbout_sync_prepare_desc(struct usbout *u, struct urb *urb)
-{
-	unsigned int i, offs;
-
-	for (i = offs = 0; i < SYNCFRAMES; i++, offs += 3) {
-		urb->iso_frame_desc[i].length = 3;
-		urb->iso_frame_desc[i].offset = offs;
-	}
-	urb->interval = 1;
-	return 0;
-}
-
-/*
- * return value: 0 if descriptor should be restarted, -1 otherwise
- */
-static int usbout_sync_retire_desc(struct usbout *u, struct urb *urb)
-{
-	unsigned char *cp = urb->transfer_buffer;
-	unsigned int f, i;
-
-	for (i = 0; i < SYNCFRAMES; i++, cp += 3) {
-		if (urb->iso_frame_desc[i].status) {
-			dprintk((KERN_DEBUG "usbout_sync_retire_desc: frame %u status %d\n", i, urb->iso_frame_desc[i].status));
-			continue;
-		}
-		if (urb->iso_frame_desc[i].actual_length < 3) {
-			dprintk((KERN_DEBUG "usbout_sync_retire_desc: frame %u length %d\n", i, urb->iso_frame_desc[i].actual_length));
-			continue;
-		}
-		f = cp[0] | (cp[1] << 8) | (cp[2] << 16);
-		if (abs(f - u->freqn) > (u->freqn >> 3) || f > u->freqmax) {
-			printk(KERN_WARNING "usbout_sync_retire_desc: requested frequency %u (nominal %u) out of range!\n", f, u->freqn);
-			continue;
-		}
-		u->freqm = f;
-	}
-	return 0;
-}
-
-static void usbout_sync_completed(struct urb *urb, struct pt_regs *regs)
-{
-	struct usb_audiodev *as = (struct usb_audiodev *)urb->context;
-	struct usbout *u = &as->usbout;
-	unsigned long flags;
-	unsigned int mask;
-	int suret = 0;
-
-#if 0
-	printk(KERN_DEBUG "usbout_sync_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
-#endif
-	if (urb == u->surb[0].urb)
-		mask = FLG_SYNC0RUNNING;
-	else if (urb == u->surb[1].urb)
-		mask = FLG_SYNC1RUNNING;
-	else {
-		mask = 0;
-		printk(KERN_ERR "usbout_sync_completed: panic: unknown URB\n");
-	}
-	urb->dev = as->state->usbdev;
-	spin_lock_irqsave(&as->lock, flags);
-	if (!usbout_sync_retire_desc(u, urb) &&
-	    u->flags & FLG_RUNNING &&
-	    !usbout_sync_prepare_desc(u, urb) && 
-	    (suret = usb_submit_urb(urb, GFP_ATOMIC)) == 0) {
-		u->flags |= mask;
-	} else {
-		u->flags &= ~(mask | FLG_RUNNING);
-		wake_up(&u->dma.wait);
-		dprintk((KERN_DEBUG "usbout_sync_completed: descriptor not restarted (usb_submit_urb: %d)\n", suret));
-	}
-	spin_unlock_irqrestore(&as->lock, flags);
-}
-
-static int usbout_start(struct usb_audiodev *as)
-{
-	struct usb_device *dev = as->state->usbdev;
-	struct usbout *u = &as->usbout;
-	struct urb *urb;
-	unsigned long flags;
-	unsigned int maxsze, bufsz;
-
-#if 0
-	printk(KERN_DEBUG "usbout_start: device %d ufmt 0x%08x dfmt 0x%08x srate %d\n",
-	       dev->devnum, u->format, u->dma.format, u->dma.srate);
-#endif
-	/* allocate USB storage if not already done */
-	spin_lock_irqsave(&as->lock, flags);
-	if (!(u->flags & FLG_CONNECTED)) {
-		spin_unlock_irqrestore(&as->lock, flags);
-		return -EIO;
-	}
-	if (!(u->flags & FLG_RUNNING)) {
-		spin_unlock_irqrestore(&as->lock, flags);
-		u->freqn = u->freqm = ((u->dma.srate << 11) + 62) / 125; /* this will overflow at approx 2MSPS */
-		u->freqmax = u->freqn + (u->freqn >> 2);
-		u->phase = 0;
-		maxsze = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format));
-		bufsz = DESCFRAMES * maxsze;
-		kfree(u->durb[0].urb->transfer_buffer);
-		u->durb[0].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
-		u->durb[0].urb->transfer_buffer_length = bufsz;
-		kfree(u->durb[1].urb->transfer_buffer);
-		u->durb[1].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
-		u->durb[1].urb->transfer_buffer_length = bufsz;
-		if (u->syncpipe) {
-			kfree(u->surb[0].urb->transfer_buffer);
-			u->surb[0].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
-			u->surb[0].urb->transfer_buffer_length = 3*SYNCFRAMES;
-			kfree(u->surb[1].urb->transfer_buffer);
-			u->surb[1].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
-			u->surb[1].urb->transfer_buffer_length = 3*SYNCFRAMES;
-		}
-		if (!u->durb[0].urb->transfer_buffer || !u->durb[1].urb->transfer_buffer || 
-		    (u->syncpipe && (!u->surb[0].urb->transfer_buffer || !u->surb[1].urb->transfer_buffer))) {
-			printk(KERN_ERR "usbaudio: cannot start playback device %d\n", dev->devnum);
-			return 0;
-		}
-		spin_lock_irqsave(&as->lock, flags);
-	}
-	if (u->dma.count <= 0 && !u->dma.mapped) {
-		spin_unlock_irqrestore(&as->lock, flags);
-		return 0;
-	}
-       	u->flags |= FLG_RUNNING;
-	if (!(u->flags & FLG_URB0RUNNING)) {
-		urb = u->durb[0].urb;
-		urb->dev = dev;
-		urb->pipe = u->datapipe;
-		urb->transfer_flags = URB_ISO_ASAP;
-		urb->number_of_packets = DESCFRAMES;
-		urb->context = as;
-		urb->complete = usbout_completed;
-		if (!usbout_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_ATOMIC))
-			u->flags |= FLG_URB0RUNNING;
-		else
-			u->flags &= ~FLG_RUNNING;
-	}
-	if (u->flags & FLG_RUNNING && !(u->flags & FLG_URB1RUNNING)) {
-		urb = u->durb[1].urb;
-		urb->dev = dev;
-		urb->pipe = u->datapipe;
-		urb->transfer_flags = URB_ISO_ASAP;
-		urb->number_of_packets = DESCFRAMES;
-		urb->context = as;
-		urb->complete = usbout_completed;
-		if (!usbout_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_ATOMIC))
-			u->flags |= FLG_URB1RUNNING;
-		else
-			u->flags &= ~FLG_RUNNING;
-	}
-	if (u->syncpipe) {
-		if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC0RUNNING)) {
-			urb = u->surb[0].urb;
-			urb->dev = dev;
-			urb->pipe = u->syncpipe;
-			urb->transfer_flags = URB_ISO_ASAP;
-			urb->number_of_packets = SYNCFRAMES;
-			urb->context = as;
-			urb->complete = usbout_sync_completed;
-			/* stride: u->syncinterval */
-			if (!usbout_sync_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_ATOMIC))
-				u->flags |= FLG_SYNC0RUNNING;
-			else
-				u->flags &= ~FLG_RUNNING;
-		}
-		if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC1RUNNING)) {
-			urb = u->surb[1].urb;
-			urb->dev = dev;
-			urb->pipe = u->syncpipe;
-			urb->transfer_flags = URB_ISO_ASAP;
-			urb->number_of_packets = SYNCFRAMES;
-			urb->context = as;
-			urb->complete = usbout_sync_completed;
-			/* stride: u->syncinterval */
-			if (!usbout_sync_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_ATOMIC))
-				u->flags |= FLG_SYNC1RUNNING;
-			else
-				u->flags &= ~FLG_RUNNING;
-		}
-	}
-	spin_unlock_irqrestore(&as->lock, flags);
-	return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static unsigned int format_goodness(struct audioformat *afp, unsigned int fmt, unsigned int srate)
-{
-	unsigned int g = 0;
-
-	if (srate < afp->sratelo)
-		g += afp->sratelo - srate;
-	if (srate > afp->sratehi)
-		g += srate - afp->sratehi;
-	if (AFMT_ISSTEREO(afp->format) && !AFMT_ISSTEREO(fmt))
-		g += 0x100000;
-	if (!AFMT_ISSTEREO(afp->format) && AFMT_ISSTEREO(fmt))
-		g += 0x400000;
-	if (AFMT_IS16BIT(afp->format) && !AFMT_IS16BIT(fmt))
-		g += 0x100000;
-	if (!AFMT_IS16BIT(afp->format) && AFMT_IS16BIT(fmt))
-		g += 0x400000;
-	return g;
-}
-
-static int find_format(struct audioformat *afp, unsigned int nr, unsigned int fmt, unsigned int srate)
-{
-	unsigned int i, g, gb = ~0;
-	int j = -1; /* default to failure */
-
-	/* find "best" format (according to format_goodness) */
-	for (i = 0; i < nr; i++) {
-		g = format_goodness(&afp[i], fmt, srate);
-		if (g >= gb) 
-			continue;
-		j = i;
-		gb = g;
-	}
-       	return j;
-}
-
-static int set_format_in(struct usb_audiodev *as)
-{
-	struct usb_device *dev = as->state->usbdev;
-	struct usb_host_interface *alts;
-	struct usb_interface *iface;
-	struct usbin *u = &as->usbin;
-	struct dmabuf *d = &u->dma;
-	struct audioformat *fmt;
-	unsigned int ep;
-	unsigned char data[3];
-	int fmtnr, ret;
-
-	iface = usb_ifnum_to_if(dev, u->interface);
-	if (!iface)
-		return 0;
-
-	fmtnr = find_format(as->fmtin, as->numfmtin, d->format, d->srate);
-	if (fmtnr < 0) {
-		printk(KERN_ERR "usbaudio: set_format_in(): failed to find desired format/speed combination.\n");
-		return -1;
-	}
-
-	fmt = as->fmtin + fmtnr;
-	alts = usb_altnum_to_altsetting(iface, fmt->altsetting);
-	u->format = fmt->format;
-	u->datapipe = usb_rcvisocpipe(dev, alts->endpoint[0].desc.bEndpointAddress & 0xf);
-	u->syncpipe = u->syncinterval = 0;
-	if ((alts->endpoint[0].desc.bmAttributes & 0x0c) == 0x08) {
-		if (alts->desc.bNumEndpoints < 2 ||
-		    alts->endpoint[1].desc.bmAttributes != 0x01 ||
-		    alts->endpoint[1].desc.bSynchAddress != 0 ||
-		    alts->endpoint[1].desc.bEndpointAddress != (alts->endpoint[0].desc.bSynchAddress & 0x7f)) {
-			printk(KERN_WARNING "usbaudio: device %d interface %d altsetting %d claims adaptive in "
-			       "but has invalid synch pipe; treating as asynchronous in\n",
-			       dev->devnum, u->interface, fmt->altsetting);
-		} else {
-			u->syncpipe = usb_sndisocpipe(dev, alts->endpoint[1].desc.bEndpointAddress & 0xf);
-			u->syncinterval = alts->endpoint[1].desc.bRefresh;
-		}
-	}
-	if (d->srate < fmt->sratelo)
-		d->srate = fmt->sratelo;
-	if (d->srate > fmt->sratehi)
-		d->srate = fmt->sratehi;
-	dprintk((KERN_DEBUG "usbaudio: set_format_in: usb_set_interface %u %u\n",
-			u->interface, fmt->altsetting));
-	if (usb_set_interface(dev, alts->desc.bInterfaceNumber, fmt->altsetting) < 0) {
-		printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n",
-		       dev->devnum, u->interface, fmt->altsetting);
-		return -1;
-	}
-	if (fmt->sratelo == fmt->sratehi)
-		return 0;
-	ep = usb_pipeendpoint(u->datapipe) | (u->datapipe & USB_DIR_IN);
-	/* if endpoint has pitch control, enable it */
-	if (fmt->attributes & 0x02) {
-		data[0] = 1;
-		if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
-					   PITCH_CONTROL << 8, ep, data, 1, 1000)) < 0) {
-			printk(KERN_ERR "usbaudio: failure (error %d) to set output pitch control device %d interface %u endpoint 0x%x to %u\n",
-			       ret, dev->devnum, u->interface, ep, d->srate);
-			return -1;
-		}
-	}
-	/* if endpoint has sampling rate control, set it */
-	if (fmt->attributes & 0x01) {
-		data[0] = d->srate;
-		data[1] = d->srate >> 8;
-		data[2] = d->srate >> 16;
-		if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
-					   SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
-			printk(KERN_ERR "usbaudio: failure (error %d) to set input sampling frequency device %d interface %u endpoint 0x%x to %u\n",
-			       ret, dev->devnum, u->interface, ep, d->srate);
-			return -1;
-		}
-		if ((ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
-					   SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
-			printk(KERN_ERR "usbaudio: failure (error %d) to get input sampling frequency device %d interface %u endpoint 0x%x\n",
-			       ret, dev->devnum, u->interface, ep);
-			return -1;
-		}
-		dprintk((KERN_DEBUG "usbaudio: set_format_in: device %d interface %d altsetting %d srate req: %u real %u\n",
-		        dev->devnum, u->interface, fmt->altsetting, d->srate, data[0] | (data[1] << 8) | (data[2] << 16)));
-		d->srate = data[0] | (data[1] << 8) | (data[2] << 16);
-	}
-	dprintk((KERN_DEBUG "usbaudio: set_format_in: USB format 0x%x, DMA format 0x%x srate %u\n", u->format, d->format, d->srate));
-	return 0;
-}
-
-static int set_format_out(struct usb_audiodev *as)
-{
-	struct usb_device *dev = as->state->usbdev;
-	struct usb_host_interface *alts;
-	struct usb_interface *iface;	
-	struct usbout *u = &as->usbout;
-	struct dmabuf *d = &u->dma;
-	struct audioformat *fmt;
-	unsigned int ep;
-	unsigned char data[3];
-	int fmtnr, ret;
-
-	iface = usb_ifnum_to_if(dev, u->interface);
-	if (!iface)
-		return 0;
-
-	fmtnr = find_format(as->fmtout, as->numfmtout, d->format, d->srate);
-	if (fmtnr < 0) {
-		printk(KERN_ERR "usbaudio: set_format_out(): failed to find desired format/speed combination.\n");
-		return -1;
-	}
-
-	fmt = as->fmtout + fmtnr;
-	u->format = fmt->format;
-	alts = usb_altnum_to_altsetting(iface, fmt->altsetting);
-	u->datapipe = usb_sndisocpipe(dev, alts->endpoint[0].desc.bEndpointAddress & 0xf);
-	u->syncpipe = u->syncinterval = 0;
-	if ((alts->endpoint[0].desc.bmAttributes & 0x0c) == 0x04) {
-#if 0
-		printk(KERN_DEBUG "bNumEndpoints 0x%02x endpoint[1].bmAttributes 0x%02x\n"
-		       KERN_DEBUG "endpoint[1].bSynchAddress 0x%02x endpoint[1].bEndpointAddress 0x%02x\n"
-		       KERN_DEBUG "endpoint[0].bSynchAddress 0x%02x\n", alts->bNumEndpoints,
-		       alts->endpoint[1].bmAttributes, alts->endpoint[1].bSynchAddress,
-		       alts->endpoint[1].bEndpointAddress, alts->endpoint[0].bSynchAddress);
-#endif
-		if (alts->desc.bNumEndpoints < 2 ||
-		    alts->endpoint[1].desc.bmAttributes != 0x01 ||
-		    alts->endpoint[1].desc.bSynchAddress != 0 ||
-		    alts->endpoint[1].desc.bEndpointAddress != (alts->endpoint[0].desc.bSynchAddress | 0x80)) {
-			printk(KERN_WARNING "usbaudio: device %d interface %d altsetting %d claims asynch out "
-			       "but has invalid synch pipe; treating as adaptive out\n",
-			       dev->devnum, u->interface, fmt->altsetting);
-		} else {
-			u->syncpipe = usb_rcvisocpipe(dev, alts->endpoint[1].desc.bEndpointAddress & 0xf);
-			u->syncinterval = alts->endpoint[1].desc.bRefresh;
-		}
-	}
-	if (d->srate < fmt->sratelo)
-		d->srate = fmt->sratelo;
-	if (d->srate > fmt->sratehi)
-		d->srate = fmt->sratehi;
-	dprintk((KERN_DEBUG "usbaudio: set_format_out: usb_set_interface %u %u\n",
-			u->interface, fmt->altsetting));
-	if (usb_set_interface(dev, u->interface, fmt->altsetting) < 0) {
-		printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n",
-		       dev->devnum, u->interface, fmt->altsetting);
-		return -1;
-	}
-	if (fmt->sratelo == fmt->sratehi)
-		return 0;
-	ep = usb_pipeendpoint(u->datapipe) | (u->datapipe & USB_DIR_IN);
-	/* if endpoint has pitch control, enable it */
-	if (fmt->attributes & 0x02) {
-		data[0] = 1;
-		if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
-					   PITCH_CONTROL << 8, ep, data, 1, 1000)) < 0) {
-			printk(KERN_ERR "usbaudio: failure (error %d) to set output pitch control device %d interface %u endpoint 0x%x to %u\n",
-			       ret, dev->devnum, u->interface, ep, d->srate);
-			return -1;
-		}
-	}
-	/* if endpoint has sampling rate control, set it */
-	if (fmt->attributes & 0x01) {
-		data[0] = d->srate;
-		data[1] = d->srate >> 8;
-		data[2] = d->srate >> 16;
-		if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
-					   SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
-			printk(KERN_ERR "usbaudio: failure (error %d) to set output sampling frequency device %d interface %u endpoint 0x%x to %u\n",
-			       ret, dev->devnum, u->interface, ep, d->srate);
-			return -1;
-		}
-		if ((ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
-					   SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
-			printk(KERN_ERR "usbaudio: failure (error %d) to get output sampling frequency device %d interface %u endpoint 0x%x\n",
-			       ret, dev->devnum, u->interface, ep);
-			return -1;
-		}
-		dprintk((KERN_DEBUG "usbaudio: set_format_out: device %d interface %d altsetting %d srate req: %u real %u\n",
-		        dev->devnum, u->interface, fmt->altsetting, d->srate, data[0] | (data[1] << 8) | (data[2] << 16)));
-		d->srate = data[0] | (data[1] << 8) | (data[2] << 16);
-	}
-	dprintk((KERN_DEBUG "usbaudio: set_format_out: USB format 0x%x, DMA format 0x%x srate %u\n", u->format, d->format, d->srate));
-	return 0;
-}
-
-static int set_format(struct usb_audiodev *s, unsigned int fmode, unsigned int fmt, unsigned int srate)
-{
-	int ret1 = 0, ret2 = 0;
-
-	if (!(fmode & (FMODE_READ|FMODE_WRITE)))
-		return -EINVAL;
-	if (fmode & FMODE_READ) {
-		usbin_stop(s);
-		s->usbin.dma.ready = 0;
-		if (fmt == AFMT_QUERY)
-			fmt = s->usbin.dma.format;
-		else
-			s->usbin.dma.format = fmt;
-		if (!srate)
-			srate = s->usbin.dma.srate;
-		else
-			s->usbin.dma.srate = srate;
-	}
-	if (fmode & FMODE_WRITE) {
-		usbout_stop(s);
-		s->usbout.dma.ready = 0;
-		if (fmt == AFMT_QUERY)
-			fmt = s->usbout.dma.format;
-		else
-			s->usbout.dma.format = fmt;
-		if (!srate)
-			srate = s->usbout.dma.srate;
-		else
-			s->usbout.dma.srate = srate;
-	}
-	if (fmode & FMODE_READ)
-		ret1 = set_format_in(s);
-	if (fmode & FMODE_WRITE)
-		ret2 = set_format_out(s);
-	return ret1 ? ret1 : ret2;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int wrmixer(struct usb_mixerdev *ms, unsigned mixch, unsigned value)
-{
-	struct usb_device *dev = ms->state->usbdev;
-	unsigned char data[2];
-	struct mixerchannel *ch;
-	int v1, v2, v3;
-
-	if (mixch >= ms->numch)
-		return -1;
-	ch = &ms->ch[mixch];
-	v3 = ch->maxval - ch->minval;
-	v1 = value & 0xff;
-	v2 = (value >> 8) & 0xff;
-	if (v1 > 100)
-		v1 = 100;
-	if (v2 > 100)
-		v2 = 100;
-	if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
-		v2 = v1;
-	ch->value = v1 | (v2 << 8);
-	v1 = (v1 * v3) / 100 + ch->minval;
-	v2 = (v2 * v3) / 100 + ch->minval;
-	switch (ch->selector) {
-	case 0:  /* mixer unit request */
-		data[0] = v1;
-		data[1] = v1 >> 8;
-		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-				    (ch->chnum << 8) | 1, ms->iface | (ch->unitid << 8), data, 2, 1000) < 0)
-			goto err;
-		if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
-			return 0;
-		data[0] = v2;
-		data[1] = v2 >> 8;
-		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-				    ((ch->chnum + !!(ch->flags & MIXFLG_STEREOIN)) << 8) | (1 + !!(ch->flags & MIXFLG_STEREOOUT)),
-				    ms->iface | (ch->unitid << 8), data, 2, 1000) < 0)
-			goto err;
-		return 0;
-
-		/* various feature unit controls */
-	case VOLUME_CONTROL:
-		data[0] = v1;
-		data[1] = v1 >> 8;
-		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-				    (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 2, 1000) < 0)
-			goto err;
-		if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
-			return 0;
-		data[0] = v2;
-		data[1] = v2 >> 8;
-		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-				    (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 2, 1000) < 0)
-			goto err;
-		return 0;
-                
-	case BASS_CONTROL:
-	case MID_CONTROL:
-	case TREBLE_CONTROL:
-		data[0] = v1 >> 8;
-		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-				    (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 1, 1000) < 0)
-			goto err;
-		if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
-			return 0;
-		data[0] = v2 >> 8;
-		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-				    (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 1, 1000) < 0)
-			goto err;
-		return 0;
-
-	default:
-		return -1;
-	}
-	return 0;
-
- err:
-	printk(KERN_ERR "usbaudio: mixer request device %u if %u unit %u ch %u selector %u failed\n", 
-		dev->devnum, ms->iface, ch->unitid, ch->chnum, ch->selector);
-	return -1;
-}
-
-static int get_rec_src(struct usb_mixerdev *ms)
-{
-	struct usb_device *dev = ms->state->usbdev;
-	unsigned int mask = 0, retmask = 0;
-	unsigned int i, j;
-	unsigned char buf;
-	int err = 0;
-
-	for (i = 0; i < ms->numch; i++) {
-		if (!ms->ch[i].slctunitid || (mask & (1 << i)))
-			continue;
-		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    0, ms->iface | (ms->ch[i].slctunitid << 8), &buf, 1, 1000) < 0) {
-			err = -EIO;
-			printk(KERN_ERR "usbaudio: selector read request device %u if %u unit %u failed\n", 
-			       dev->devnum, ms->iface, ms->ch[i].slctunitid & 0xff);
-			continue;
-		}
-		for (j = i; j < ms->numch; j++) {
-			if ((ms->ch[i].slctunitid ^ ms->ch[j].slctunitid) & 0xff)
-				continue;
-			mask |= 1 << j;
-			if (buf == (ms->ch[j].slctunitid >> 8))
-				retmask |= 1 << ms->ch[j].osschannel;
-		}
-	}
-	if (err)
-		return -EIO;
-	return retmask;
-}
-
-static int set_rec_src(struct usb_mixerdev *ms, int srcmask)
-{
-	struct usb_device *dev = ms->state->usbdev;
-	unsigned int mask = 0, smask, bmask;
-	unsigned int i, j;
-	unsigned char buf;
-	int err = 0;
-
-	for (i = 0; i < ms->numch; i++) {
-		if (!ms->ch[i].slctunitid || (mask & (1 << i)))
-			continue;
-		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    0, ms->iface | (ms->ch[i].slctunitid << 8), &buf, 1, 1000) < 0) {
-			err = -EIO;
-			printk(KERN_ERR "usbaudio: selector read request device %u if %u unit %u failed\n", 
-			       dev->devnum, ms->iface, ms->ch[i].slctunitid & 0xff);
-			continue;
-		}
-		/* first generate smask */
-		smask = bmask = 0;
-		for (j = i; j < ms->numch; j++) {
-			if ((ms->ch[i].slctunitid ^ ms->ch[j].slctunitid) & 0xff)
-				continue;
-			smask |= 1 << ms->ch[j].osschannel;
-			if (buf == (ms->ch[j].slctunitid >> 8))
-				bmask |= 1 << ms->ch[j].osschannel;
-			mask |= 1 << j;
-		}
-		/* check for multiple set sources */
-		j = hweight32(srcmask & smask);
-		if (j == 0)
-			continue;
-		if (j > 1)
-			srcmask &= ~bmask;
-		for (j = i; j < ms->numch; j++) {
-			if ((ms->ch[i].slctunitid ^ ms->ch[j].slctunitid) & 0xff)
-				continue;
-			if (!(srcmask & (1 << ms->ch[j].osschannel)))
-				continue;
-			buf = ms->ch[j].slctunitid >> 8;
-			if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-				    0, ms->iface | (ms->ch[j].slctunitid << 8), &buf, 1, 1000) < 0) {
-				err = -EIO;
-				printk(KERN_ERR "usbaudio: selector write request device %u if %u unit %u failed\n", 
-				       dev->devnum, ms->iface, ms->ch[j].slctunitid & 0xff);
-				continue;
-			}
-		}
-	}
-	return err ? -EIO : 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * should be called with open_sem hold, so that no new processes
- * look at the audio device to be destroyed
- */
-
-static void release(struct usb_audio_state *s)
-{
-	struct usb_audiodev *as;
-	struct usb_mixerdev *ms;
-
-	s->count--;
-	if (s->count) {
-		up(&open_sem);
-		return;
-	}
-	up(&open_sem);
-	wake_up(&open_wait);
-	while (!list_empty(&s->audiolist)) {
-		as = list_entry(s->audiolist.next, struct usb_audiodev, list);
-		list_del(&as->list);
-		usbin_release(as);
-		usbout_release(as);
-		dmabuf_release(&as->usbin.dma);
-		dmabuf_release(&as->usbout.dma);
-		usb_free_urb(as->usbin.durb[0].urb);
-		usb_free_urb(as->usbin.durb[1].urb);
-		usb_free_urb(as->usbin.surb[0].urb);
-		usb_free_urb(as->usbin.surb[1].urb);
-		usb_free_urb(as->usbout.durb[0].urb);
-		usb_free_urb(as->usbout.durb[1].urb);
-		usb_free_urb(as->usbout.surb[0].urb);
-		usb_free_urb(as->usbout.surb[1].urb);
-		kfree(as);
-	}
-	while (!list_empty(&s->mixerlist)) {
-		ms = list_entry(s->mixerlist.next, struct usb_mixerdev, list);
-		list_del(&ms->list);
-		kfree(ms);
-	}
-	kfree(s);
-}
-
-static inline int prog_dmabuf_in(struct usb_audiodev *as)
-{
-	usbin_stop(as);
-	return dmabuf_init(&as->usbin.dma);
-}
-
-static inline int prog_dmabuf_out(struct usb_audiodev *as)
-{
-	usbout_stop(as);
-	return dmabuf_init(&as->usbout.dma);
-}
-
-/* --------------------------------------------------------------------- */
-
-static int usb_audio_open_mixdev(struct inode *inode, struct file *file)
-{
-	unsigned int minor = iminor(inode);
-	struct usb_mixerdev *ms;
-	struct usb_audio_state *s;
-
-	down(&open_sem);
-	list_for_each_entry(s, &audiodevs, audiodev) {
-		list_for_each_entry(ms, &s->mixerlist, list) {
-			if (ms->dev_mixer == minor)
-				goto mixer_found;
-		}
-	}
-	up(&open_sem);
-	return -ENODEV;
-
- mixer_found:
-	if (!s->usbdev) {
-		up(&open_sem);
-		return -EIO;
-	}
-	file->private_data = ms;
-	s->count++;
-
-	up(&open_sem);
-	return nonseekable_open(inode, file);
-}
-
-static int usb_audio_release_mixdev(struct inode *inode, struct file *file)
-{
-	struct usb_mixerdev *ms = (struct usb_mixerdev *)file->private_data;
-	struct usb_audio_state *s;
-
-	lock_kernel();
-	s = ms->state;
-	down(&open_sem);
-	release(s);
-	unlock_kernel();
-	return 0;
-}
-
-static int usb_audio_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	struct usb_mixerdev *ms = (struct usb_mixerdev *)file->private_data;
-	int i, j, val;
-	int __user *user_arg = (int __user *)arg;
-
-	if (!ms->state->usbdev)
-		return -ENODEV;
-  
-	if (cmd == SOUND_MIXER_INFO) {
-		mixer_info info;
-
-		memset(&info, 0, sizeof(info));
-		strncpy(info.id, "USB_AUDIO", sizeof(info.id));
-		strncpy(info.name, "USB Audio Class Driver", sizeof(info.name));
-		info.modify_counter = ms->modcnt;
-		if (copy_to_user((void __user *)arg, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	if (cmd == SOUND_OLD_MIXER_INFO) {
-		_old_mixer_info info;
-
-		memset(&info, 0, sizeof(info));
-		strncpy(info.id, "USB_AUDIO", sizeof(info.id));
-		strncpy(info.name, "USB Audio Class Driver", sizeof(info.name));
-		if (copy_to_user((void __user *)arg, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	if (cmd == OSS_GETVERSION)
-		return put_user(SOUND_VERSION, user_arg);
-	if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
-		return -EINVAL;
-	if (_IOC_DIR(cmd) == _IOC_READ) {
-		switch (_IOC_NR(cmd)) {
-		case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
-			val = get_rec_src(ms);
-			if (val < 0)
-				return val;
-			return put_user(val, user_arg);
-
-		case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
-			for (val = i = 0; i < ms->numch; i++)
-				val |= 1 << ms->ch[i].osschannel;
-			return put_user(val, user_arg);
-
-		case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
-			for (val = i = 0; i < ms->numch; i++)
-				if (ms->ch[i].slctunitid)
-					val |= 1 << ms->ch[i].osschannel;
-			return put_user(val, user_arg);
-
-		case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
-			for (val = i = 0; i < ms->numch; i++)
-				if (ms->ch[i].flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT))
-					val |= 1 << ms->ch[i].osschannel;
-			return put_user(val, user_arg);
-			
-		case SOUND_MIXER_CAPS:
-			return put_user(SOUND_CAP_EXCL_INPUT, user_arg);
-
-		default:
-			i = _IOC_NR(cmd);
-			if (i >= SOUND_MIXER_NRDEVICES)
-				return -EINVAL;
-			for (j = 0; j < ms->numch; j++) {
-				if (ms->ch[j].osschannel == i) {
-					return put_user(ms->ch[j].value, user_arg);
-				}
-			}
-			return -EINVAL;
-		}
-	}
-	if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE)) 
-		return -EINVAL;
-	ms->modcnt++;
-	switch (_IOC_NR(cmd)) {
-	case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
-		if (get_user(val, user_arg))
-			return -EFAULT;
-		return set_rec_src(ms, val);
-
-	default:
-		i = _IOC_NR(cmd);
-		if (i >= SOUND_MIXER_NRDEVICES)
-			return -EINVAL;
-		for (j = 0; j < ms->numch && ms->ch[j].osschannel != i; j++);
-		if (j >= ms->numch)
-			return -EINVAL;
-		if (get_user(val, user_arg))
-			return -EFAULT;
-		if (wrmixer(ms, j, val))
-			return -EIO;
-		return put_user(ms->ch[j].value, user_arg);
-	}
-}
-
-static /*const*/ struct file_operations usb_mixer_fops = {
-	.owner =	THIS_MODULE,
-	.llseek =	no_llseek,
-	.ioctl =	usb_audio_ioctl_mixdev,
-	.open =		usb_audio_open_mixdev,
-	.release =	usb_audio_release_mixdev,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int drain_out(struct usb_audiodev *as, int nonblock)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	unsigned long flags;
-	int count, tmo;
-	
-	if (as->usbout.dma.mapped || !as->usbout.dma.ready)
-		return 0;
-	usbout_start(as);
-	add_wait_queue(&as->usbout.dma.wait, &wait);
-	for (;;) {
-		__set_current_state(TASK_INTERRUPTIBLE);
-		spin_lock_irqsave(&as->lock, flags);
-		count = as->usbout.dma.count;
-		spin_unlock_irqrestore(&as->lock, flags);
-		if (count <= 0)
-			break;
-		if (signal_pending(current))
-			break;
-		if (nonblock) {
-			remove_wait_queue(&as->usbout.dma.wait, &wait);
-			set_current_state(TASK_RUNNING);
-			return -EBUSY;
-		}
-		tmo = 3 * HZ * count / as->usbout.dma.srate;
-		tmo >>= AFMT_BYTESSHIFT(as->usbout.dma.format);
-		if (!schedule_timeout(tmo + 1)) {
-			printk(KERN_DEBUG "usbaudio: dma timed out??\n");
-			break;
-		}
-	}
-	remove_wait_queue(&as->usbout.dma.wait, &wait);
-	set_current_state(TASK_RUNNING);
-	if (signal_pending(current))
-		return -ERESTARTSYS;
-	return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static ssize_t usb_audio_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
-	struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t ret = 0;
-	unsigned long flags;
-	unsigned int ptr;
-	int cnt, err;
-
-	if (as->usbin.dma.mapped)
-		return -ENXIO;
-	if (!as->usbin.dma.ready && (ret = prog_dmabuf_in(as)))
-		return ret;
-	if (!access_ok(VERIFY_WRITE, buffer, count))
-		return -EFAULT;
-	add_wait_queue(&as->usbin.dma.wait, &wait);
-	while (count > 0) {
-		spin_lock_irqsave(&as->lock, flags);
-		ptr = as->usbin.dma.rdptr;
-		cnt = as->usbin.dma.count;
-		/* set task state early to avoid wakeup races */
-		if (cnt <= 0)
-			__set_current_state(TASK_INTERRUPTIBLE);
-		spin_unlock_irqrestore(&as->lock, flags);
-		if (cnt > count)
-			cnt = count;
-		if (cnt <= 0) {
-			if (usbin_start(as)) {
-				if (!ret)
-					ret = -ENODEV;
-				break;
-			}
-			if (file->f_flags & O_NONBLOCK) {
-				if (!ret)
-					ret = -EAGAIN;
-				break;
-			}
-			schedule();
-			if (signal_pending(current)) {
-				if (!ret)
-					ret = -ERESTARTSYS;
-				break;
-			}
-			continue;
-		}
-		if ((err = dmabuf_copyout_user(&as->usbin.dma, ptr, buffer, cnt))) {
-			if (!ret)
-				ret = err;
-			break;
-		}
-		ptr += cnt;
-		if (ptr >= as->usbin.dma.dmasize)
-			ptr -= as->usbin.dma.dmasize;
-		spin_lock_irqsave(&as->lock, flags);
-		as->usbin.dma.rdptr = ptr;
-		as->usbin.dma.count -= cnt;
-		spin_unlock_irqrestore(&as->lock, flags);
-		count -= cnt;
-		buffer += cnt;
-		ret += cnt;
-	}
-	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(&as->usbin.dma.wait, &wait);
-	return ret;
-}
-
-static ssize_t usb_audio_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
-	struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t ret = 0;
-	unsigned long flags;
-	unsigned int ptr;
-	unsigned int start_thr;
-	int cnt, err;
-
-	if (as->usbout.dma.mapped)
-		return -ENXIO;
-	if (!as->usbout.dma.ready && (ret = prog_dmabuf_out(as)))
-		return ret;
-	if (!access_ok(VERIFY_READ, buffer, count))
-		return -EFAULT;
-	start_thr = (as->usbout.dma.srate << AFMT_BYTESSHIFT(as->usbout.dma.format)) / (1000 / (3 * DESCFRAMES));
-	add_wait_queue(&as->usbout.dma.wait, &wait);
-	while (count > 0) {
-#if 0
-		printk(KERN_DEBUG "usb_audio_write: count %u dma: count %u rdptr %u wrptr %u dmasize %u fragsize %u flags 0x%02x taskst 0x%lx\n",
-		       count, as->usbout.dma.count, as->usbout.dma.rdptr, as->usbout.dma.wrptr, as->usbout.dma.dmasize, as->usbout.dma.fragsize,
-		       as->usbout.flags, current->state);
-#endif
-		spin_lock_irqsave(&as->lock, flags);
-		if (as->usbout.dma.count < 0) {
-			as->usbout.dma.count = 0;
-			as->usbout.dma.rdptr = as->usbout.dma.wrptr;
-		}
-		ptr = as->usbout.dma.wrptr;
-		cnt = as->usbout.dma.dmasize - as->usbout.dma.count;
-		/* set task state early to avoid wakeup races */
-		if (cnt <= 0)
-			__set_current_state(TASK_INTERRUPTIBLE);
-		spin_unlock_irqrestore(&as->lock, flags);
-		if (cnt > count)
-			cnt = count;
-		if (cnt <= 0) {
-			if (usbout_start(as)) {
-				if (!ret)
-					ret = -ENODEV;
-				break;
-			}
-			if (file->f_flags & O_NONBLOCK) {
-				if (!ret)
-					ret = -EAGAIN;
-				break;
-			}
-			schedule();
-			if (signal_pending(current)) {
-				if (!ret)
-					ret = -ERESTARTSYS;
-				break;
-			}
-			continue;
-		}
-		if ((err = dmabuf_copyin_user(&as->usbout.dma, ptr, buffer, cnt))) {
-			if (!ret)
-				ret = err;
-			break;
-		}
-		ptr += cnt;
-		if (ptr >= as->usbout.dma.dmasize)
-			ptr -= as->usbout.dma.dmasize;
-		spin_lock_irqsave(&as->lock, flags);
-		as->usbout.dma.wrptr = ptr;
-		as->usbout.dma.count += cnt;
-		spin_unlock_irqrestore(&as->lock, flags);
-		count -= cnt;
-		buffer += cnt;
-		ret += cnt;
-		if (as->usbout.dma.count >= start_thr && usbout_start(as)) {
-			if (!ret)
-				ret = -ENODEV;
-			break;
-		}
-	}
-	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(&as->usbout.dma.wait, &wait);
-	return ret;
-}
-
-/* Called without the kernel lock - fine */
-static unsigned int usb_audio_poll(struct file *file, struct poll_table_struct *wait)
-{
-	struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
-	unsigned long flags;
-	unsigned int mask = 0;
-
-	if (file->f_mode & FMODE_WRITE) {
-		if (!as->usbout.dma.ready)
-			prog_dmabuf_out(as);
-		poll_wait(file, &as->usbout.dma.wait, wait);
-	}
-	if (file->f_mode & FMODE_READ) {
-		if (!as->usbin.dma.ready)
-			prog_dmabuf_in(as);
-		poll_wait(file, &as->usbin.dma.wait, wait);
-	}
-	spin_lock_irqsave(&as->lock, flags);
-	if (file->f_mode & FMODE_READ) {
-		if (as->usbin.dma.count >= (signed)as->usbin.dma.fragsize)
-			mask |= POLLIN | POLLRDNORM;
-	}
-	if (file->f_mode & FMODE_WRITE) {
-		if (as->usbout.dma.mapped) {
-			if (as->usbout.dma.count >= (signed)as->usbout.dma.fragsize) 
-				mask |= POLLOUT | POLLWRNORM;
-		} else {
-			if ((signed)as->usbout.dma.dmasize >= as->usbout.dma.count + (signed)as->usbout.dma.fragsize)
-				mask |= POLLOUT | POLLWRNORM;
-		}
-	}
-	spin_unlock_irqrestore(&as->lock, flags);
-	return mask;
-}
-
-static int usb_audio_mmap(struct file *file, struct vm_area_struct *vma)
-{
-	struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
-	struct dmabuf *db;
-	int ret = -EINVAL;
-
-	lock_kernel();
-	if (vma->vm_flags & VM_WRITE) {
-		if ((ret = prog_dmabuf_out(as)) != 0)
-			goto out;
-		db = &as->usbout.dma;
-	} else if (vma->vm_flags & VM_READ) {
-		if ((ret = prog_dmabuf_in(as)) != 0)
-			goto out;
-		db = &as->usbin.dma;
-	} else
-		goto out;
-
-	ret = -EINVAL;
-	if (vma->vm_pgoff != 0)
-		goto out;
-
-	ret = dmabuf_mmap(vma, db,  vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot);
-out:
-	unlock_kernel();
-	return ret;
-}
-
-static int usb_audio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
-	struct usb_audio_state *s = as->state;
-	int __user *user_arg = (int __user *)arg;
-	unsigned long flags;
-	audio_buf_info abinfo;
-	count_info cinfo;
-	int val = 0;
-	int val2, mapped, ret;
-
-	if (!s->usbdev)
-		return -EIO;
-	mapped = ((file->f_mode & FMODE_WRITE) && as->usbout.dma.mapped) ||
-		((file->f_mode & FMODE_READ) && as->usbin.dma.mapped);
-#if 0
-	if (arg)
-		get_user(val, (int *)arg);
-	printk(KERN_DEBUG "usbaudio: usb_audio_ioctl cmd=%x arg=%lx *arg=%d\n", cmd, arg, val)
-#endif
-	switch (cmd) {
-	case OSS_GETVERSION:
-		return put_user(SOUND_VERSION, user_arg);
-
-	case SNDCTL_DSP_SYNC:
-		if (file->f_mode & FMODE_WRITE)
-			return drain_out(as, 0/*file->f_flags & O_NONBLOCK*/);
-		return 0;
-
-	case SNDCTL_DSP_SETDUPLEX:
-		return 0;
-
-	case SNDCTL_DSP_GETCAPS:
-		return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | 
-				DSP_CAP_MMAP | DSP_CAP_BATCH, user_arg);
-
-	case SNDCTL_DSP_RESET:
-		if (file->f_mode & FMODE_WRITE) {
-			usbout_stop(as);
-			as->usbout.dma.rdptr = as->usbout.dma.wrptr = as->usbout.dma.count = as->usbout.dma.total_bytes = 0;
-		}
-		if (file->f_mode & FMODE_READ) {
-			usbin_stop(as);
-			as->usbin.dma.rdptr = as->usbin.dma.wrptr = as->usbin.dma.count = as->usbin.dma.total_bytes = 0;
-		}
-		return 0;
-
-	case SNDCTL_DSP_SPEED:
-		if (get_user(val, user_arg))
-			return -EFAULT;
-		if (val >= 0) {
-			if (val < 4000)
-				val = 4000;
-			if (val > 100000)
-				val = 100000;
-			if (set_format(as, file->f_mode, AFMT_QUERY, val))
-				return -EIO;
-		}
-		return put_user((file->f_mode & FMODE_READ) ? 
-				as->usbin.dma.srate : as->usbout.dma.srate,
-				user_arg);
-
-	case SNDCTL_DSP_STEREO:
-		if (get_user(val, user_arg))
-			return -EFAULT;
-		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
-		if (val)
-			val2 |= AFMT_STEREO;
-		else
-			val2 &= ~AFMT_STEREO;
-		if (set_format(as, file->f_mode, val2, 0))
-			return -EIO;
-		return 0;
-
-	case SNDCTL_DSP_CHANNELS:
-		if (get_user(val, user_arg))
-			return -EFAULT;
-		if (val != 0) {
-			val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
-			if (val == 1)
-				val2 &= ~AFMT_STEREO;
-			else
-				val2 |= AFMT_STEREO;
-			if (set_format(as, file->f_mode, val2, 0))
-				return -EIO;
-		}
-		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
-		return put_user(AFMT_ISSTEREO(val2) ? 2 : 1, user_arg);
-
-	case SNDCTL_DSP_GETFMTS: /* Returns a mask */
-		return put_user(AFMT_U8 | AFMT_U16_LE | AFMT_U16_BE |
-				AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE, user_arg);
-
-	case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
-		if (get_user(val, user_arg))
-			return -EFAULT;
-		if (val != AFMT_QUERY) {
-			if (hweight32(val) != 1)
-				return -EINVAL;
-			if (!(val & (AFMT_U8 | AFMT_U16_LE | AFMT_U16_BE |
-				     AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE)))
-				return -EINVAL;
-			val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
-			val |= val2 & AFMT_STEREO;
-			if (set_format(as, file->f_mode, val, 0))
-				return -EIO;
-		}
-		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
-		return put_user(val2 & ~AFMT_STEREO, user_arg);
-
-	case SNDCTL_DSP_POST:
-		return 0;
-
-	case SNDCTL_DSP_GETTRIGGER:
-		val = 0;
-		if (file->f_mode & FMODE_READ && as->usbin.flags & FLG_RUNNING) 
-			val |= PCM_ENABLE_INPUT;
-		if (file->f_mode & FMODE_WRITE && as->usbout.flags & FLG_RUNNING) 
-			val |= PCM_ENABLE_OUTPUT;
-		return put_user(val, user_arg);
-
-	case SNDCTL_DSP_SETTRIGGER:
-		if (get_user(val, user_arg))
-			return -EFAULT;
-		if (file->f_mode & FMODE_READ) {
-			if (val & PCM_ENABLE_INPUT) {
-				if (!as->usbin.dma.ready && (ret = prog_dmabuf_in(as)))
-					return ret;
-				if (usbin_start(as))
-					return -ENODEV;
-			} else
-				usbin_stop(as);
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			if (val & PCM_ENABLE_OUTPUT) {
-				if (!as->usbout.dma.ready && (ret = prog_dmabuf_out(as)))
-					return ret;
-				if (usbout_start(as))
-					return -ENODEV;
-			} else
-				usbout_stop(as);
-		}
-		return 0;
-
-	case SNDCTL_DSP_GETOSPACE:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		if (!(as->usbout.flags & FLG_RUNNING) && (val = prog_dmabuf_out(as)) != 0)
-			return val;
-		spin_lock_irqsave(&as->lock, flags);
-		abinfo.fragsize = as->usbout.dma.fragsize;
-		abinfo.bytes = as->usbout.dma.dmasize - as->usbout.dma.count;
-		abinfo.fragstotal = as->usbout.dma.numfrag;
-		abinfo.fragments = abinfo.bytes >> as->usbout.dma.fragshift;      
-		spin_unlock_irqrestore(&as->lock, flags);
-		return copy_to_user((void __user *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
-	case SNDCTL_DSP_GETISPACE:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		if (!(as->usbin.flags & FLG_RUNNING) && (val = prog_dmabuf_in(as)) != 0)
-			return val;
-		spin_lock_irqsave(&as->lock, flags);
-		abinfo.fragsize = as->usbin.dma.fragsize;
-		abinfo.bytes = as->usbin.dma.count;
-		abinfo.fragstotal = as->usbin.dma.numfrag;
-		abinfo.fragments = abinfo.bytes >> as->usbin.dma.fragshift;      
-		spin_unlock_irqrestore(&as->lock, flags);
-		return copy_to_user((void __user *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-		
-	case SNDCTL_DSP_NONBLOCK:
-		file->f_flags |= O_NONBLOCK;
-		return 0;
-
-	case SNDCTL_DSP_GETODELAY:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		spin_lock_irqsave(&as->lock, flags);
-		val = as->usbout.dma.count;
-		spin_unlock_irqrestore(&as->lock, flags);
-		return put_user(val, user_arg);
-
-	case SNDCTL_DSP_GETIPTR:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		spin_lock_irqsave(&as->lock, flags);
-		cinfo.bytes = as->usbin.dma.total_bytes;
-		cinfo.blocks = as->usbin.dma.count >> as->usbin.dma.fragshift;
-		cinfo.ptr = as->usbin.dma.wrptr;
-		if (as->usbin.dma.mapped)
-			as->usbin.dma.count &= as->usbin.dma.fragsize-1;
-		spin_unlock_irqrestore(&as->lock, flags);
-		if (copy_to_user((void __user *)arg, &cinfo, sizeof(cinfo)))
-			return -EFAULT;
-		return 0;
-
-	case SNDCTL_DSP_GETOPTR:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		spin_lock_irqsave(&as->lock, flags);
-		cinfo.bytes = as->usbout.dma.total_bytes;
-		cinfo.blocks = as->usbout.dma.count >> as->usbout.dma.fragshift;
-		cinfo.ptr = as->usbout.dma.rdptr;
-		if (as->usbout.dma.mapped)
-			as->usbout.dma.count &= as->usbout.dma.fragsize-1;
-		spin_unlock_irqrestore(&as->lock, flags);
-		if (copy_to_user((void __user *)arg, &cinfo, sizeof(cinfo)))
-			return -EFAULT;
-		return 0;
-
-       case SNDCTL_DSP_GETBLKSIZE:
-		if (file->f_mode & FMODE_WRITE) {
-			if ((val = prog_dmabuf_out(as)))
-				return val;
-			return put_user(as->usbout.dma.fragsize, user_arg);
-		}
-		if ((val = prog_dmabuf_in(as)))
-			return val;
-		return put_user(as->usbin.dma.fragsize, user_arg);
-
-	case SNDCTL_DSP_SETFRAGMENT:
-		if (get_user(val, user_arg))
-			return -EFAULT;
-		if (file->f_mode & FMODE_READ) {
-			as->usbin.dma.ossfragshift = val & 0xffff;
-			as->usbin.dma.ossmaxfrags = (val >> 16) & 0xffff;
-			if (as->usbin.dma.ossfragshift < 4)
-				as->usbin.dma.ossfragshift = 4;
-			if (as->usbin.dma.ossfragshift > 15)
-				as->usbin.dma.ossfragshift = 15;
-			if (as->usbin.dma.ossmaxfrags < 4)
-				as->usbin.dma.ossmaxfrags = 4;
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			as->usbout.dma.ossfragshift = val & 0xffff;
-			as->usbout.dma.ossmaxfrags = (val >> 16) & 0xffff;
-			if (as->usbout.dma.ossfragshift < 4)
-				as->usbout.dma.ossfragshift = 4;
-			if (as->usbout.dma.ossfragshift > 15)
-				as->usbout.dma.ossfragshift = 15;
-			if (as->usbout.dma.ossmaxfrags < 4)
-				as->usbout.dma.ossmaxfrags = 4;
-		}
-		return 0;
-
-	case SNDCTL_DSP_SUBDIVIDE:
-		if ((file->f_mode & FMODE_READ && as->usbin.dma.subdivision) ||
-		    (file->f_mode & FMODE_WRITE && as->usbout.dma.subdivision))
-			return -EINVAL;
-		if (get_user(val, user_arg))
-			return -EFAULT;
-		if (val != 1 && val != 2 && val != 4)
-			return -EINVAL;
-		if (file->f_mode & FMODE_READ)
-			as->usbin.dma.subdivision = val;
-		if (file->f_mode & FMODE_WRITE)
-			as->usbout.dma.subdivision = val;
-		return 0;
-
-	case SOUND_PCM_READ_RATE:
-		return put_user((file->f_mode & FMODE_READ) ? 
-				as->usbin.dma.srate : as->usbout.dma.srate,
-				user_arg);
-
-	case SOUND_PCM_READ_CHANNELS:
-		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
-		return put_user(AFMT_ISSTEREO(val2) ? 2 : 1, user_arg);
-
-	case SOUND_PCM_READ_BITS:
-		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
-		return put_user(AFMT_IS16BIT(val2) ? 16 : 8, user_arg);
-
-	case SOUND_PCM_WRITE_FILTER:
-	case SNDCTL_DSP_SETSYNCRO:
-	case SOUND_PCM_READ_FILTER:
-		return -EINVAL;
-	}
-	dprintk((KERN_DEBUG "usbaudio: usb_audio_ioctl - no command found\n"));
-	return -ENOIOCTLCMD;
-}
-
-static int usb_audio_open(struct inode *inode, struct file *file)
-{
-	unsigned int minor = iminor(inode);
-	DECLARE_WAITQUEUE(wait, current);
-	struct usb_audiodev *as;
-	struct usb_audio_state *s;
-
-	for (;;) {
-		down(&open_sem);
-		list_for_each_entry(s, &audiodevs, audiodev) {
-			list_for_each_entry(as, &s->audiolist, list) {
-				if (!((as->dev_audio ^ minor) & ~0xf))
-					goto device_found;
-			}
-		}
-		up(&open_sem);
-		return -ENODEV;
-
-	device_found:
-		if (!s->usbdev) {
-			up(&open_sem);
-			return -EIO;
-		}
-		/* wait for device to become free */
-		if (!(as->open_mode & file->f_mode))
-			break;
-		if (file->f_flags & O_NONBLOCK) {
-			up(&open_sem);
-			return -EBUSY;
-		}
-		__set_current_state(TASK_INTERRUPTIBLE);
-		add_wait_queue(&open_wait, &wait);
-		up(&open_sem);
-		schedule();
-		__set_current_state(TASK_RUNNING);
-		remove_wait_queue(&open_wait, &wait);
-		if (signal_pending(current))
-			return -ERESTARTSYS;
-	}
-	if (file->f_mode & FMODE_READ)
-		as->usbin.dma.ossfragshift = as->usbin.dma.ossmaxfrags = as->usbin.dma.subdivision = 0;
-	if (file->f_mode & FMODE_WRITE)
-		as->usbout.dma.ossfragshift = as->usbout.dma.ossmaxfrags = as->usbout.dma.subdivision = 0;
-	if (set_format(as, file->f_mode, ((minor & 0xf) == SND_DEV_DSP16) ? AFMT_S16_LE : AFMT_U8 /* AFMT_ULAW */, 8000)) {
-		up(&open_sem);
-		return -EIO;
-	}
-	file->private_data = as;
-	as->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-	s->count++;
-	up(&open_sem);
-	return nonseekable_open(inode, file);
-}
-
-static int usb_audio_release(struct inode *inode, struct file *file)
-{
-	struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
-	struct usb_audio_state *s;
-	struct usb_device *dev;
-
-	lock_kernel();
-	s = as->state;
-	dev = s->usbdev;
-	if (file->f_mode & FMODE_WRITE)
-		drain_out(as, file->f_flags & O_NONBLOCK);
-	down(&open_sem);
-	if (file->f_mode & FMODE_WRITE) {
-		usbout_stop(as);
-		if (dev && as->usbout.interface >= 0)
-			usb_set_interface(dev, as->usbout.interface, 0);
-		dmabuf_release(&as->usbout.dma);
-		usbout_release(as);
-	}
-	if (file->f_mode & FMODE_READ) {
-		usbin_stop(as);
-		if (dev && as->usbin.interface >= 0)
-			usb_set_interface(dev, as->usbin.interface, 0);
-		dmabuf_release(&as->usbin.dma);
-		usbin_release(as);
-	}
-	as->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
-	release(s);
-	wake_up(&open_wait);
-	unlock_kernel();
-	return 0;
-}
-
-static /*const*/ struct file_operations usb_audio_fops = {
-	.owner =	THIS_MODULE,
-	.llseek =	no_llseek,
-	.read =		usb_audio_read,
-	.write =	usb_audio_write,
-	.poll =		usb_audio_poll,
-	.ioctl =	usb_audio_ioctl,
-	.mmap =		usb_audio_mmap,
-	.open =		usb_audio_open,
-	.release =	usb_audio_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int usb_audio_probe(struct usb_interface *iface,
-			   const struct usb_device_id *id);
-static void usb_audio_disconnect(struct usb_interface *iface);
-
-static struct usb_device_id usb_audio_ids [] = {
-    { .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS),
-      .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = 1},
-    { }						/* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, usb_audio_ids);
-
-static struct usb_driver usb_audio_driver = {
-	.name =		"audio",
-	.probe =	usb_audio_probe,
-	.disconnect =	usb_audio_disconnect,
-	.id_table =	usb_audio_ids,
-};
-
-static void *find_descriptor(void *descstart, unsigned int desclen, void *after, 
-			     u8 dtype, int iface, int altsetting)
-{
-	u8 *p, *end, *next;
-	int ifc = -1, as = -1;
-
-	p = descstart;
-	end = p + desclen;
-	for (; p < end;) {
-		if (p[0] < 2)
-			return NULL;
-		next = p + p[0];
-		if (next > end)
-			return NULL;
-		if (p[1] == USB_DT_INTERFACE) {
-			/* minimum length of interface descriptor */
-			if (p[0] < 9)
-				return NULL;
-			ifc = p[2];
-			as = p[3];
-		}
-		if (p[1] == dtype && (!after || (void *)p > after) &&
-		    (iface == -1 || iface == ifc) && (altsetting == -1 || altsetting == as)) {
-			return p;
-		}
-		p = next;
-	}
-	return NULL;
-}
-
-static void *find_csinterface_descriptor(void *descstart, unsigned int desclen, void *after, u8 dsubtype, int iface, int altsetting)
-{
-	unsigned char *p;
-
-	p = find_descriptor(descstart, desclen, after, USB_DT_CS_INTERFACE, iface, altsetting);
-	while (p) {
-		if (p[0] >= 3 && p[2] == dsubtype)
-			return p;
-		p = find_descriptor(descstart, desclen, p, USB_DT_CS_INTERFACE, iface, altsetting);
-	}
-	return NULL;
-}
-
-static void *find_audiocontrol_unit(void *descstart, unsigned int desclen, void *after, u8 unit, int iface)
-{
-	unsigned char *p;
-
-	p = find_descriptor(descstart, desclen, after, USB_DT_CS_INTERFACE, iface, -1);
-	while (p) {
-		if (p[0] >= 4 && p[2] >= INPUT_TERMINAL && p[2] <= EXTENSION_UNIT && p[3] == unit)
-			return p;
-		p = find_descriptor(descstart, desclen, p, USB_DT_CS_INTERFACE, iface, -1);
-	}
-	return NULL;
-}
-
-static void usb_audio_parsestreaming(struct usb_audio_state *s, unsigned char *buffer, unsigned int buflen, int asifin, int asifout)
-{
-	struct usb_device *dev = s->usbdev;
-	struct usb_audiodev *as;
-	struct usb_host_interface *alts;
-	struct usb_interface *iface;
-	struct audioformat *fp;
-	unsigned char *fmt, *csep;
-	unsigned int i, j, k, format, idx;
-
-	if (!(as = kmalloc(sizeof(struct usb_audiodev), GFP_KERNEL)))
-		return;
-	memset(as, 0, sizeof(struct usb_audiodev));
-	init_waitqueue_head(&as->usbin.dma.wait);
-	init_waitqueue_head(&as->usbout.dma.wait);
-	spin_lock_init(&as->lock);
-	as->usbin.durb[0].urb = usb_alloc_urb (DESCFRAMES, GFP_KERNEL);
-	as->usbin.durb[1].urb = usb_alloc_urb (DESCFRAMES, GFP_KERNEL);
-	as->usbin.surb[0].urb = usb_alloc_urb (SYNCFRAMES, GFP_KERNEL);
-	as->usbin.surb[1].urb = usb_alloc_urb (SYNCFRAMES, GFP_KERNEL);
-	as->usbout.durb[0].urb = usb_alloc_urb (DESCFRAMES, GFP_KERNEL);
-	as->usbout.durb[1].urb = usb_alloc_urb (DESCFRAMES, GFP_KERNEL);
-	as->usbout.surb[0].urb = usb_alloc_urb (SYNCFRAMES, GFP_KERNEL);
-	as->usbout.surb[1].urb = usb_alloc_urb (SYNCFRAMES, GFP_KERNEL);
-	if ((!as->usbin.durb[0].urb) ||
-	    (!as->usbin.durb[1].urb) ||
-	    (!as->usbin.surb[0].urb) ||
-	    (!as->usbin.surb[1].urb) ||
-	    (!as->usbout.durb[0].urb) ||
-	    (!as->usbout.durb[1].urb) ||
-	    (!as->usbout.surb[0].urb) ||
-	    (!as->usbout.surb[1].urb)) {
-		usb_free_urb(as->usbin.durb[0].urb);
-		usb_free_urb(as->usbin.durb[1].urb);
-		usb_free_urb(as->usbin.surb[0].urb);
-		usb_free_urb(as->usbin.surb[1].urb);
-		usb_free_urb(as->usbout.durb[0].urb);
-		usb_free_urb(as->usbout.durb[1].urb);
-		usb_free_urb(as->usbout.surb[0].urb);
-		usb_free_urb(as->usbout.surb[1].urb);
-		kfree(as);
-		return;
-	}
-	as->state = s;
-	as->usbin.interface = asifin;
-	as->usbout.interface = asifout;
-	/* search for input formats */
-	if (asifin >= 0) {
-		as->usbin.flags = FLG_CONNECTED;
-		iface = usb_ifnum_to_if(dev, asifin);
-		for (idx = 0; idx < iface->num_altsetting; idx++) {
-			alts = &iface->altsetting[idx];
-			i = alts->desc.bAlternateSetting;
-			if (alts->desc.bInterfaceClass != USB_CLASS_AUDIO || alts->desc.bInterfaceSubClass != 2)
-				continue;
-			if (alts->desc.bNumEndpoints < 1) {
-				if (i != 0) {  /* altsetting 0 has no endpoints (Section B.3.4.1) */
-					printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u does not have an endpoint\n", 
-					       dev->devnum, asifin, i);
-				}
-				continue;
-			}
-			if ((alts->endpoint[0].desc.bmAttributes & 0x03) != 0x01 ||
-			    !(alts->endpoint[0].desc.bEndpointAddress & 0x80)) {
-				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u first endpoint not isochronous in\n", 
-				       dev->devnum, asifin, i);
-				continue;
-			}
-			fmt = find_csinterface_descriptor(buffer, buflen, NULL, AS_GENERAL, asifin, i);
-			if (!fmt) {
-				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n", 
-				       dev->devnum, asifin, i);
-				continue;
-			}
-			if (fmt[0] < 7 || fmt[6] != 0 || (fmt[5] != 1 && fmt[5] != 2)) {
-				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u format not supported\n", 
-				       dev->devnum, asifin, i);
-				continue;
-			}
-			format = (fmt[5] == 2) ? (AFMT_U16_LE | AFMT_U8) : (AFMT_S16_LE | AFMT_S8);
-			fmt = find_csinterface_descriptor(buffer, buflen, NULL, FORMAT_TYPE, asifin, i);
-			if (!fmt) {
-				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n", 
-				       dev->devnum, asifin, i);
-				continue;
-			}
-			if (fmt[0] < 8+3*(fmt[7] ? fmt[7] : 2) || fmt[3] != 1) {
-				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not supported\n", 
-				       dev->devnum, asifin, i);
-				continue;
-			}
-			if (fmt[4] < 1 || fmt[4] > 2 || fmt[5] < 1 || fmt[5] > 2) {
-				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u unsupported channels %u framesize %u\n", 
-				       dev->devnum, asifin, i, fmt[4], fmt[5]);
-				continue;
-			}
-			csep = find_descriptor(buffer, buflen, NULL, USB_DT_CS_ENDPOINT, asifin, i);
-			if (!csep || csep[0] < 7 || csep[2] != EP_GENERAL) {
-				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u no or invalid class specific endpoint descriptor\n", 
-				       dev->devnum, asifin, i);
-				continue;
-			}
-			if (as->numfmtin >= MAXFORMATS)
-				continue;
-			fp = &as->fmtin[as->numfmtin++];
-			if (fmt[5] == 2)
-				format &= (AFMT_U16_LE | AFMT_S16_LE);
-			else
-				format &= (AFMT_U8 | AFMT_S8);
-			if (fmt[4] == 2)
-				format |= AFMT_STEREO;
-			fp->format = format;
-			fp->altsetting = i;
-			fp->sratelo = fp->sratehi = fmt[8] | (fmt[9] << 8) | (fmt[10] << 16);
-			printk(KERN_INFO "usbaudio: valid input sample rate %u\n", fp->sratelo);
-			for (j = fmt[7] ? (fmt[7]-1) : 1; j > 0; j--) {
-				k = fmt[8+3*j] | (fmt[9+3*j] << 8) | (fmt[10+3*j] << 16);
-				printk(KERN_INFO "usbaudio: valid input sample rate %u\n", k);
-				if (k > fp->sratehi)
-					fp->sratehi = k;
-				if (k < fp->sratelo)
-					fp->sratelo = k;
-			}
-			fp->attributes = csep[3];
-			printk(KERN_INFO "usbaudio: device %u interface %u altsetting %u: format 0x%08x sratelo %u sratehi %u attributes 0x%02x\n", 
-			       dev->devnum, asifin, i, fp->format, fp->sratelo, fp->sratehi, fp->attributes);
-		}
-	}
-	/* search for output formats */
-	if (asifout >= 0) {
-		as->usbout.flags = FLG_CONNECTED;
-		iface = usb_ifnum_to_if(dev, asifout);
-		for (idx = 0; idx < iface->num_altsetting; idx++) {
-			alts = &iface->altsetting[idx];
-			i = alts->desc.bAlternateSetting;
-			if (alts->desc.bInterfaceClass != USB_CLASS_AUDIO || alts->desc.bInterfaceSubClass != 2)
-				continue;
-			if (alts->desc.bNumEndpoints < 1) {
-				/* altsetting 0 should never have iso EPs */
-				if (i != 0)
-				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u does not have an endpoint\n", 
-				       dev->devnum, asifout, i);
-				continue;
-			}
-			if ((alts->endpoint[0].desc.bmAttributes & 0x03) != 0x01 ||
-			    (alts->endpoint[0].desc.bEndpointAddress & 0x80)) {
-				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u first endpoint not isochronous out\n", 
-				       dev->devnum, asifout, i);
-				continue;
-			}
-			/* See USB audio formats manual, section 2 */
-			fmt = find_csinterface_descriptor(buffer, buflen, NULL, AS_GENERAL, asifout, i);
-			if (!fmt) {
-				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n", 
-				       dev->devnum, asifout, i);
-				continue;
-			}
-			if (fmt[0] < 7 || fmt[6] != 0 || (fmt[5] != 1 && fmt[5] != 2)) {
-				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u format not supported\n", 
-				       dev->devnum, asifout, i);
-				continue;
-			}
-			format = (fmt[5] == 2) ? (AFMT_U16_LE | AFMT_U8) : (AFMT_S16_LE | AFMT_S8);
-			/* Dallas DS4201 workaround */
-			if (le16_to_cpu(dev->descriptor.idVendor) == 0x04fa && 
-			    le16_to_cpu(dev->descriptor.idProduct) == 0x4201)
-				format = (AFMT_S16_LE | AFMT_S8);
-			fmt = find_csinterface_descriptor(buffer, buflen, NULL, FORMAT_TYPE, asifout, i);
-			if (!fmt) {
-				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n", 
-				       dev->devnum, asifout, i);
-				continue;
-			}
-			if (fmt[0] < 8+3*(fmt[7] ? fmt[7] : 2) || fmt[3] != 1) {
-				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not supported\n", 
-				       dev->devnum, asifout, i);
-				continue;
-			}
-			if (fmt[4] < 1 || fmt[4] > 2 || fmt[5] < 1 || fmt[5] > 2) {
-				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u unsupported channels %u framesize %u\n", 
-				       dev->devnum, asifout, i, fmt[4], fmt[5]);
-				continue;
-			}
-			csep = find_descriptor(buffer, buflen, NULL, USB_DT_CS_ENDPOINT, asifout, i);
-			if (!csep || csep[0] < 7 || csep[2] != EP_GENERAL) {
-				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u no or invalid class specific endpoint descriptor\n", 
-				       dev->devnum, asifout, i);
-				continue;
-			}
-			if (as->numfmtout >= MAXFORMATS)
-				continue;
-			fp = &as->fmtout[as->numfmtout++];
-			if (fmt[5] == 2)
-				format &= (AFMT_U16_LE | AFMT_S16_LE);
-			else
-				format &= (AFMT_U8 | AFMT_S8);
-			if (fmt[4] == 2)
-				format |= AFMT_STEREO;
-			fp->format = format;
-			fp->altsetting = i;
-			fp->sratelo = fp->sratehi = fmt[8] | (fmt[9] << 8) | (fmt[10] << 16);
-			printk(KERN_INFO "usbaudio: valid output sample rate %u\n", fp->sratelo);
-			for (j = fmt[7] ? (fmt[7]-1) : 1; j > 0; j--) {
-				k = fmt[8+3*j] | (fmt[9+3*j] << 8) | (fmt[10+3*j] << 16);
-				printk(KERN_INFO "usbaudio: valid output sample rate %u\n", k);
-				if (k > fp->sratehi)
-					fp->sratehi = k;
-				if (k < fp->sratelo)
-					fp->sratelo = k;
-			}
-			fp->attributes = csep[3];
-			printk(KERN_INFO "usbaudio: device %u interface %u altsetting %u: format 0x%08x sratelo %u sratehi %u attributes 0x%02x\n", 
-			       dev->devnum, asifout, i, fp->format, fp->sratelo, fp->sratehi, fp->attributes);
-		}
-	}
-	if (as->numfmtin == 0 && as->numfmtout == 0) {
-		usb_free_urb(as->usbin.durb[0].urb);
-		usb_free_urb(as->usbin.durb[1].urb);
-		usb_free_urb(as->usbin.surb[0].urb);
-		usb_free_urb(as->usbin.surb[1].urb);
-		usb_free_urb(as->usbout.durb[0].urb);
-		usb_free_urb(as->usbout.durb[1].urb);
-		usb_free_urb(as->usbout.surb[0].urb);
-		usb_free_urb(as->usbout.surb[1].urb);
-		kfree(as);
-		return;
-	}
-	if ((as->dev_audio = register_sound_dsp(&usb_audio_fops, -1)) < 0) {
-		printk(KERN_ERR "usbaudio: cannot register dsp\n");
-		usb_free_urb(as->usbin.durb[0].urb);
-		usb_free_urb(as->usbin.durb[1].urb);
-		usb_free_urb(as->usbin.surb[0].urb);
-		usb_free_urb(as->usbin.surb[1].urb);
-		usb_free_urb(as->usbout.durb[0].urb);
-		usb_free_urb(as->usbout.durb[1].urb);
-		usb_free_urb(as->usbout.surb[0].urb);
-		usb_free_urb(as->usbout.surb[1].urb);
-		kfree(as);
-		return;
-	}
-	printk(KERN_INFO "usbaudio: registered dsp 14,%d\n", as->dev_audio);
-	/* everything successful */
-	list_add_tail(&as->list, &s->audiolist);
-}
-
-struct consmixstate {
-	struct usb_audio_state *s;
-	unsigned char *buffer;
-	unsigned int buflen;
-	unsigned int ctrlif;
-	struct mixerchannel mixch[SOUND_MIXER_NRDEVICES];
-	unsigned int nrmixch;
-	unsigned int mixchmask;
-	unsigned long unitbitmap[32/sizeof(unsigned long)];
-	/* return values */
-	unsigned int nrchannels;
-	unsigned int termtype;
-	unsigned int chconfig;
-};
-
-static struct mixerchannel *getmixchannel(struct consmixstate *state, unsigned int nr)
-{
-	struct mixerchannel *c;
-
-	if (nr >= SOUND_MIXER_NRDEVICES) {
-		printk(KERN_ERR "usbaudio: invalid OSS mixer channel %u\n", nr);
-		return NULL;
-	}
-	if (!(state->mixchmask & (1 << nr))) {
-		printk(KERN_WARNING "usbaudio: OSS mixer channel %u already in use\n", nr);
-		return NULL;
-	}
-	c = &state->mixch[state->nrmixch++];
-	c->osschannel = nr;
-	state->mixchmask &= ~(1 << nr);
-	return c;
-}
-
-static unsigned int getvolchannel(struct consmixstate *state)
-{
-	unsigned int u;
-
-	if ((state->termtype & 0xff00) == 0x0000 && (state->mixchmask & SOUND_MASK_VOLUME))
-		return SOUND_MIXER_VOLUME;
-	if ((state->termtype & 0xff00) == 0x0100) {
-		if (state->mixchmask & SOUND_MASK_PCM)
-			return SOUND_MIXER_PCM;
-		if (state->mixchmask & SOUND_MASK_ALTPCM)
-			return SOUND_MIXER_ALTPCM;
-	}
-	if ((state->termtype & 0xff00) == 0x0200 && (state->mixchmask & SOUND_MASK_MIC))
-		return SOUND_MIXER_MIC;
-	if ((state->termtype & 0xff00) == 0x0300 && (state->mixchmask & SOUND_MASK_SPEAKER))
-		return SOUND_MIXER_SPEAKER;
-	if ((state->termtype & 0xff00) == 0x0500) {
-		if (state->mixchmask & SOUND_MASK_PHONEIN)
-			return SOUND_MIXER_PHONEIN;
-		if (state->mixchmask & SOUND_MASK_PHONEOUT)
-			return SOUND_MIXER_PHONEOUT;
-	}
-	if (state->termtype >= 0x710 && state->termtype <= 0x711 && (state->mixchmask & SOUND_MASK_RADIO))
-		return SOUND_MIXER_RADIO;
-	if (state->termtype >= 0x709 && state->termtype <= 0x70f && (state->mixchmask & SOUND_MASK_VIDEO))
-		return SOUND_MIXER_VIDEO;
-	u = ffs(state->mixchmask & (SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_LINE1 | SOUND_MASK_LINE2 | SOUND_MASK_LINE3 |
-				    SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 | SOUND_MASK_DIGITAL3));
-	return u-1;
-}
-
-static void prepmixch(struct consmixstate *state)
-{
-	struct usb_device *dev = state->s->usbdev;
-	struct mixerchannel *ch;
-	unsigned char *buf;
-	__s16 v1;
-	unsigned int v2, v3;
-
-	if (!state->nrmixch || state->nrmixch > SOUND_MIXER_NRDEVICES)
-		return;
-	buf = kmalloc(sizeof(*buf) * 2, GFP_KERNEL);
-	if (!buf) {
-		printk(KERN_ERR "prepmixch: out of memory\n") ;
-		return;
-	}
-
-	ch = &state->mixch[state->nrmixch-1];
-	switch (ch->selector) {
-	case 0:  /* mixer unit request */
-		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
-			goto err;
-		ch->minval = buf[0] | (buf[1] << 8);
-		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
-			goto err;
-		ch->maxval = buf[0] | (buf[1] << 8);
-		v2 = ch->maxval - ch->minval;
-		if (!v2)
-			v2 = 1;
-		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
-			goto err;
-		v1 = buf[0] | (buf[1] << 8);
-		v3 = v1 - ch->minval;
-		v3 = 100 * v3 / v2;
-		if (v3 > 100)
-			v3 = 100;
-		ch->value = v3;
-		if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) {
-			if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-					    ((ch->chnum + !!(ch->flags & MIXFLG_STEREOIN)) << 8) | (1 + !!(ch->flags & MIXFLG_STEREOOUT)),
-					    state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
-			goto err;
-			v1 = buf[0] | (buf[1] << 8);
-			v3 = v1 - ch->minval;
-			v3 = 100 * v3 / v2;
-			if (v3 > 100)
-				v3 = 100;
-		}
-		ch->value |= v3 << 8;
-		break;
-
-		/* various feature unit controls */
-	case VOLUME_CONTROL:
-		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
-			goto err;
-		ch->minval = buf[0] | (buf[1] << 8);
-		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
-			goto err;
-		ch->maxval = buf[0] | (buf[1] << 8);
-		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
-			goto err;
-		v1 = buf[0] | (buf[1] << 8);
-		v2 = ch->maxval - ch->minval;
-		v3 = v1 - ch->minval;
-		if (!v2)
-			v2 = 1;
-		v3 = 100 * v3 / v2;
-		if (v3 > 100)
-			v3 = 100;
-		ch->value = v3;
-		if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) {
-			if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-					    (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
-				goto err;
-			v1 = buf[0] | (buf[1] << 8);
-			v3 = v1 - ch->minval;
-			v3 = 100 * v3 / v2;
-			if (v3 > 100)
-				v3 = 100;
-		}
-		ch->value |= v3 << 8;
-		break;
-		
-	case BASS_CONTROL:
-	case MID_CONTROL:
-	case TREBLE_CONTROL:
-		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, 1000) < 0)
-			goto err;
-		ch->minval = buf[0] << 8;
-		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, 1000) < 0)
-			goto err;
-		ch->maxval = buf[0] << 8;
-		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, 1000) < 0)
-			goto err;
-		v1 = buf[0] << 8;
-		v2 = ch->maxval - ch->minval;
-		v3 = v1 - ch->minval;
-		if (!v2)
-			v2 = 1;
-		v3 = 100 * v3 / v2;
-		if (v3 > 100)
-			v3 = 100;
-		ch->value = v3;
-		if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) {
-			if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-					    (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 1, 1000) < 0)
-				goto err;
-			v1 = buf[0] << 8;
-			v3 = v1 - ch->minval;
-			v3 = 100 * v3 / v2;
-			if (v3 > 100)
-				v3 = 100;
-		}
-		ch->value |= v3 << 8;
-		break;
-		
-	default:
-		goto err;
-	}
-
- freebuf:
-	kfree(buf);
-	return;
- err:
-	printk(KERN_ERR "usbaudio: mixer request device %u if %u unit %u ch %u selector %u failed\n", 
-	       dev->devnum, state->ctrlif, ch->unitid, ch->chnum, ch->selector);
-	if (state->nrmixch)
-		state->nrmixch--;
-	goto freebuf;
-}
-
-
-static void usb_audio_recurseunit(struct consmixstate *state, unsigned char unitid);
-
-static inline int checkmixbmap(unsigned char *bmap, unsigned char flg, unsigned int inidx, unsigned int numoch)
-{
-	unsigned int idx;
-
-	idx = inidx*numoch;
-	if (!(bmap[-(idx >> 3)] & (0x80 >> (idx & 7))))
-		return 0;
-	if (!(flg & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
-		return 1;
-	idx = (inidx+!!(flg & MIXFLG_STEREOIN))*numoch+!!(flg & MIXFLG_STEREOOUT);
-	if (!(bmap[-(idx >> 3)] & (0x80 >> (idx & 7))))
-		return 0;
-	return 1;
-}
-
-static void usb_audio_mixerunit(struct consmixstate *state, unsigned char *mixer)
-{
-	unsigned int nroutch = mixer[5+mixer[4]];
-	unsigned int chidx[SOUND_MIXER_NRDEVICES+1];
-	unsigned int termt[SOUND_MIXER_NRDEVICES];
-	unsigned char flg = (nroutch >= 2) ? MIXFLG_STEREOOUT : 0;
-	unsigned char *bmap = &mixer[9+mixer[4]];
-	unsigned int bmapsize;
-	struct mixerchannel *ch;
-	unsigned int i;
-
-	if (!mixer[4]) {
-		printk(KERN_ERR "usbaudio: unit %u invalid MIXER_UNIT descriptor\n", mixer[3]);
-		return;
-	}
-	if (mixer[4] > SOUND_MIXER_NRDEVICES) {
-		printk(KERN_ERR "usbaudio: mixer unit %u: too many input pins\n", mixer[3]);
-		return;
-	}
-	chidx[0] = 0;
-	for (i = 0; i < mixer[4]; i++) {
-		usb_audio_recurseunit(state, mixer[5+i]);
-		chidx[i+1] = chidx[i] + state->nrchannels;
-		termt[i] = state->termtype;
-	}
-	state->termtype = 0;
-	state->chconfig = mixer[6+mixer[4]] | (mixer[7+mixer[4]] << 8);
-	bmapsize = (nroutch * chidx[mixer[4]] + 7) >> 3;
-	bmap += bmapsize - 1;
-	if (mixer[0] < 10+mixer[4]+bmapsize) {
-		printk(KERN_ERR "usbaudio: unit %u invalid MIXER_UNIT descriptor (bitmap too small)\n", mixer[3]);
-		return;
-	}
-	for (i = 0; i < mixer[4]; i++) {
-		state->termtype = termt[i];
-		if (chidx[i+1]-chidx[i] >= 2) {
-			flg |= MIXFLG_STEREOIN;
-			if (checkmixbmap(bmap, flg, chidx[i], nroutch)) {
-				ch = getmixchannel(state, getvolchannel(state));
-				if (ch) {
-					ch->unitid = mixer[3];
-					ch->selector = 0;
-					ch->chnum = chidx[i]+1;
-					ch->flags = flg;
-					prepmixch(state);
-				}
-				continue;
-			}
-		}
-		flg &= ~MIXFLG_STEREOIN;
-		if (checkmixbmap(bmap, flg, chidx[i], nroutch)) {
-			ch = getmixchannel(state, getvolchannel(state));
-			if (ch) {
-				ch->unitid = mixer[3];
-				ch->selector = 0;
-				ch->chnum = chidx[i]+1;
-				ch->flags = flg;
-				prepmixch(state);
-			}
-		}
-	}	
-	state->termtype = 0;
-}
-
-static struct mixerchannel *slctsrc_findunit(struct consmixstate *state, __u8 unitid)
-{
-	unsigned int i;
-	
-	for (i = 0; i < state->nrmixch; i++)
-		if (state->mixch[i].unitid == unitid)
-			return &state->mixch[i];
-	return NULL;
-}
-
-static void usb_audio_selectorunit(struct consmixstate *state, unsigned char *selector)
-{
-	unsigned int chnum, i, mixch;
-	struct mixerchannel *mch;
-
-	if (!selector[4]) {
-		printk(KERN_ERR "usbaudio: unit %u invalid SELECTOR_UNIT descriptor\n", selector[3]);
-		return;
-	}
-	mixch = state->nrmixch;
-	usb_audio_recurseunit(state, selector[5]);
-	if (state->nrmixch != mixch) {
-		mch = &state->mixch[state->nrmixch-1];
-		mch->slctunitid = selector[3] | (1 << 8);
-	} else if ((mch = slctsrc_findunit(state, selector[5]))) {
-		mch->slctunitid = selector[3] | (1 << 8);
-	} else {
-		printk(KERN_INFO "usbaudio: selector unit %u: ignoring channel 1\n", selector[3]);
-	}
-	chnum = state->nrchannels;
-	for (i = 1; i < selector[4]; i++) {
-		mixch = state->nrmixch;
-		usb_audio_recurseunit(state, selector[5+i]);
-		if (chnum != state->nrchannels) {
-			printk(KERN_ERR "usbaudio: selector unit %u: input pins with varying channel numbers\n", selector[3]);
-			state->termtype = 0;
-			state->chconfig = 0;
-			state->nrchannels = 0;
-			return;
-		}
-		if (state->nrmixch != mixch) {
-			mch = &state->mixch[state->nrmixch-1];
-			mch->slctunitid = selector[3] | ((i + 1) << 8);
-		} else if ((mch = slctsrc_findunit(state, selector[5+i]))) {
-			mch->slctunitid = selector[3] | ((i + 1) << 8);
-		} else {
-			printk(KERN_INFO "usbaudio: selector unit %u: ignoring channel %u\n", selector[3], i+1);
-		}
-	}
-	state->termtype = 0;
-	state->chconfig = 0;
-}
-
-/* in the future we might try to handle 3D etc. effect units */
-
-static void usb_audio_processingunit(struct consmixstate *state, unsigned char *proc)
-{
-	unsigned int i;
-
-	for (i = 0; i < proc[6]; i++)
-		usb_audio_recurseunit(state, proc[7+i]);
-	state->nrchannels = proc[7+proc[6]];
-	state->termtype = 0;
-	state->chconfig = proc[8+proc[6]] | (proc[9+proc[6]] << 8);
-}
-
-
-/* See Audio Class Spec, section 4.3.2.5 */
-static void usb_audio_featureunit(struct consmixstate *state, unsigned char *ftr)
-{
-	struct mixerchannel *ch;
-	unsigned short chftr, mchftr;
-#if 0
-	struct usb_device *dev = state->s->usbdev;
-	unsigned char data[1];
-#endif
-	unsigned char nr_logical_channels, i;
-
-	usb_audio_recurseunit(state, ftr[4]);
-
-	if (ftr[5] == 0 ) {
-		printk(KERN_ERR "usbaudio: wrong controls size in feature unit %u\n",ftr[3]);
-		return;
-	}
-
-	if (state->nrchannels == 0) {
-		printk(KERN_ERR "usbaudio: feature unit %u source has no channels\n", ftr[3]);
-		return;
-	}
-	if (state->nrchannels > 2)
-		printk(KERN_WARNING "usbaudio: feature unit %u: OSS mixer interface does not support more than 2 channels\n", ftr[3]);
-
-	nr_logical_channels=(ftr[0]-7)/ftr[5]-1;
-
-	if (nr_logical_channels != state->nrchannels) {
-		printk(KERN_WARNING "usbaudio: warning: found %d of %d logical channels.\n", state->nrchannels,nr_logical_channels);
-
-		if (state->nrchannels == 1 && nr_logical_channels==0) {
-			printk(KERN_INFO "usbaudio: assuming the channel found is the master channel (got a Philips camera?). Should be fine.\n");
-		} else if (state->nrchannels == 1 && nr_logical_channels==2) {
-			printk(KERN_INFO "usbaudio: assuming that a stereo channel connected directly to a mixer is missing in search (got Labtec headset?). Should be fine.\n");
-			state->nrchannels=nr_logical_channels;
-		} else {
-			printk(KERN_WARNING "usbaudio: no idea what's going on..., contact linux-usb-devel@lists.sourceforge.net\n");
-		}
-	}
-
-	/* There is always a master channel */
-	mchftr = ftr[6];
-	/* Binary AND over logical channels if they exist */
-	if (nr_logical_channels) {
-		chftr = ftr[6+ftr[5]];
-		for (i = 2; i <= nr_logical_channels; i++)
-			chftr &= ftr[6+i*ftr[5]];
-	} else {
-		chftr = 0;
-	}
-
-	/* volume control */
-	if (chftr & 2) {
-		ch = getmixchannel(state, getvolchannel(state));
-		if (ch) {
-			ch->unitid = ftr[3];
-			ch->selector = VOLUME_CONTROL;
-			ch->chnum = 1;
-			ch->flags = (state->nrchannels > 1) ? (MIXFLG_STEREOIN | MIXFLG_STEREOOUT) : 0;
-			prepmixch(state);
-		}
-	} else if (mchftr & 2) {
-		ch = getmixchannel(state, getvolchannel(state));
-		if (ch) {
-			ch->unitid = ftr[3];
-			ch->selector = VOLUME_CONTROL;
-			ch->chnum = 0;
-			ch->flags = 0;
-			prepmixch(state);
-		}
-	}
-	/* bass control */
-	if (chftr & 4) {
-		ch = getmixchannel(state, SOUND_MIXER_BASS);
-		if (ch) {
-			ch->unitid = ftr[3];
-			ch->selector = BASS_CONTROL;
-			ch->chnum = 1;
-			ch->flags = (state->nrchannels > 1) ? (MIXFLG_STEREOIN | MIXFLG_STEREOOUT) : 0;
-			prepmixch(state);
-		}
-	} else if (mchftr & 4) {
-		ch = getmixchannel(state, SOUND_MIXER_BASS);
-		if (ch) {
-			ch->unitid = ftr[3];
-			ch->selector = BASS_CONTROL;
-			ch->chnum = 0;
-			ch->flags = 0;
-			prepmixch(state);
-		}
-	}
-	/* treble control */
-	if (chftr & 16) {
-		ch = getmixchannel(state, SOUND_MIXER_TREBLE);
-		if (ch) {
-			ch->unitid = ftr[3];
-			ch->selector = TREBLE_CONTROL;
-			ch->chnum = 1;
-			ch->flags = (state->nrchannels > 1) ? (MIXFLG_STEREOIN | MIXFLG_STEREOOUT) : 0;
-			prepmixch(state);
-		}
-	} else if (mchftr & 16) {
-		ch = getmixchannel(state, SOUND_MIXER_TREBLE);
-		if (ch) {
-			ch->unitid = ftr[3];
-			ch->selector = TREBLE_CONTROL;
-			ch->chnum = 0;
-			ch->flags = 0;
-			prepmixch(state);
-		}
-	}
-#if 0
-	/* if there are mute controls, unmute them */
-	/* does not seem to be necessary, and the Dallas chip does not seem to support the "all" channel (255) */
-	if ((chftr & 1) || (mchftr & 1)) {
-		printk(KERN_DEBUG "usbaudio: unmuting feature unit %u interface %u\n", ftr[3], state->ctrlif);
-		data[0] = 0;
-		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-				    (MUTE_CONTROL << 8) | 0xff, state->ctrlif | (ftr[3] << 8), data, 1, 1000) < 0)
-			printk(KERN_WARNING "usbaudio: failure to unmute feature unit %u interface %u\n", ftr[3], state->ctrlif);
- 	}
-#endif
-}
-
-static void usb_audio_recurseunit(struct consmixstate *state, unsigned char unitid)
-{
-	unsigned char *p1;
-	unsigned int i, j;
-
-	if (test_and_set_bit(unitid, state->unitbitmap)) {
-		printk(KERN_INFO "usbaudio: mixer path revisits unit %d\n", unitid);
-		return;
-	}
-	p1 = find_audiocontrol_unit(state->buffer, state->buflen, NULL, unitid, state->ctrlif);
-	if (!p1) {
-		printk(KERN_ERR "usbaudio: unit %d not found!\n", unitid);
-		return;
-	}
-	state->nrchannels = 0;
-	state->termtype = 0;
-	state->chconfig = 0;
-	switch (p1[2]) {
-	case INPUT_TERMINAL:
-		if (p1[0] < 12) {
-			printk(KERN_ERR "usbaudio: unit %u: invalid INPUT_TERMINAL descriptor\n", unitid);
-			return;
-		}
-		state->nrchannels = p1[7];
-		state->termtype = p1[4] | (p1[5] << 8);
-		state->chconfig = p1[8] | (p1[9] << 8);
-		return;
-
-	case MIXER_UNIT:
-		if (p1[0] < 10 || p1[0] < 10+p1[4]) {
-			printk(KERN_ERR "usbaudio: unit %u: invalid MIXER_UNIT descriptor\n", unitid);
-			return;
-		}
-		usb_audio_mixerunit(state, p1);
-		return;
-
-	case SELECTOR_UNIT:
-		if (p1[0] < 6 || p1[0] < 6+p1[4]) {
-			printk(KERN_ERR "usbaudio: unit %u: invalid SELECTOR_UNIT descriptor\n", unitid);
-			return;
-		}
-		usb_audio_selectorunit(state, p1);
-		return;
-
-	case FEATURE_UNIT: /* See USB Audio Class Spec 4.3.2.5 */
-		if (p1[0] < 7 || p1[0] < 7+p1[5]) {
-			printk(KERN_ERR "usbaudio: unit %u: invalid FEATURE_UNIT descriptor\n", unitid);
-			return;
-		}
-		usb_audio_featureunit(state, p1);
-		return;		
-
-	case PROCESSING_UNIT:
-		if (p1[0] < 13 || p1[0] < 13+p1[6] || p1[0] < 13+p1[6]+p1[11+p1[6]]) {
-			printk(KERN_ERR "usbaudio: unit %u: invalid PROCESSING_UNIT descriptor\n", unitid);
-			return;
-		}
-		usb_audio_processingunit(state, p1);
-		return;		
-
-	case EXTENSION_UNIT:
-		if (p1[0] < 13 || p1[0] < 13+p1[6] || p1[0] < 13+p1[6]+p1[11+p1[6]]) {
-			printk(KERN_ERR "usbaudio: unit %u: invalid EXTENSION_UNIT descriptor\n", unitid);
-			return;
-		}
-		for (j = i = 0; i < p1[6]; i++) {
-			usb_audio_recurseunit(state, p1[7+i]);
-			if (!i)
-				j = state->termtype;
-			else if (j != state->termtype)
-				j = 0;
-		}
-		state->nrchannels = p1[7+p1[6]];
-		state->chconfig = p1[8+p1[6]] | (p1[9+p1[6]] << 8);
-		state->termtype = j;
-		return;
-
-	default:
-		printk(KERN_ERR "usbaudio: unit %u: unexpected type 0x%02x\n", unitid, p1[2]);
-		return;
-	}
-}
-
-static void usb_audio_constructmixer(struct usb_audio_state *s, unsigned char *buffer, unsigned int buflen, unsigned int ctrlif, unsigned char *oterm)
-{
-	struct usb_mixerdev *ms;
-	struct consmixstate state;
-
-	memset(&state, 0, sizeof(state));
-	state.s = s;
-	state.nrmixch = 0;
-	state.mixchmask = ~0;
-	state.buffer = buffer;
-	state.buflen = buflen;
-	state.ctrlif = ctrlif;
-	set_bit(oterm[3], state.unitbitmap);  /* mark terminal ID as visited */
-	printk(KERN_DEBUG "usbaudio: constructing mixer for Terminal %u type 0x%04x\n",
-	       oterm[3], oterm[4] | (oterm[5] << 8));
-	usb_audio_recurseunit(&state, oterm[7]);
-	if (!state.nrmixch) {
-		printk(KERN_INFO "usbaudio: no mixer controls found for Terminal %u\n", oterm[3]);
-		return;
-	}
-	if (!(ms = kmalloc(sizeof(struct usb_mixerdev)+state.nrmixch*sizeof(struct mixerchannel), GFP_KERNEL)))
-		return;
-	memset(ms, 0, sizeof(struct usb_mixerdev));
-	memcpy(&ms->ch, &state.mixch, state.nrmixch*sizeof(struct mixerchannel));
-	ms->state = s;
-	ms->iface = ctrlif;
-	ms->numch = state.nrmixch;
-	if ((ms->dev_mixer = register_sound_mixer(&usb_mixer_fops, -1)) < 0) {
-		printk(KERN_ERR "usbaudio: cannot register mixer\n");
-		kfree(ms);
-		return;
-	}
-	printk(KERN_INFO "usbaudio: registered mixer 14,%d\n", ms->dev_mixer);
-	list_add_tail(&ms->list, &s->mixerlist);
-}
-
-/* arbitrary limit, we won't check more interfaces than this */
-#define USB_MAXINTERFACES	32
-
-static struct usb_audio_state *usb_audio_parsecontrol(struct usb_device *dev, unsigned char *buffer, unsigned int buflen, unsigned int ctrlif)
-{
-	struct usb_audio_state *s;
-	struct usb_interface *iface;
-	struct usb_host_interface *alt;
-	unsigned char ifin[USB_MAXINTERFACES], ifout[USB_MAXINTERFACES];
-	unsigned char *p1;
-	unsigned int i, j, k, numifin = 0, numifout = 0;
-	
-	if (!(s = kmalloc(sizeof(struct usb_audio_state), GFP_KERNEL)))
-		return NULL;
-	memset(s, 0, sizeof(struct usb_audio_state));
-	INIT_LIST_HEAD(&s->audiolist);
-	INIT_LIST_HEAD(&s->mixerlist);
-	s->usbdev = dev;
-	s->count = 1;
-
-	/* find audiocontrol interface */
-	if (!(p1 = find_csinterface_descriptor(buffer, buflen, NULL, HEADER, ctrlif, -1))) {
-		printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u no HEADER found\n",
-		       dev->devnum, ctrlif);
-		goto ret;
-	}
-	if (p1[0] < 8 + p1[7]) {
-		printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u HEADER error\n",
-		       dev->devnum, ctrlif);
-		goto ret;
-	}
-	if (!p1[7])
-		printk(KERN_INFO "usbaudio: device %d audiocontrol interface %u has no AudioStreaming and MidiStreaming interfaces\n",
-		       dev->devnum, ctrlif);
-	for (i = 0; i < p1[7]; i++) {
-		j = p1[8+i];
-		iface = usb_ifnum_to_if(dev, j);
-		if (!iface) {
-			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u does not exist\n",
-			       dev->devnum, ctrlif, j);
-			continue;
-		}
-		if (iface->num_altsetting == 1) {
-			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u has only 1 altsetting.\n", dev->devnum, ctrlif);
-			continue;
-		}
-		alt = usb_altnum_to_altsetting(iface, 0);
-		if (!alt) {
-			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u has no altsetting 0\n",
-			       dev->devnum, ctrlif, j);
-			continue;
-		}
-		if (alt->desc.bInterfaceClass != USB_CLASS_AUDIO) {
-			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u is not an AudioClass interface\n",
-			       dev->devnum, ctrlif, j);
-			continue;
-		}
-		if (alt->desc.bInterfaceSubClass == 3) {
-			printk(KERN_INFO "usbaudio: device %d audiocontrol interface %u interface %u MIDIStreaming not supported\n",
-			       dev->devnum, ctrlif, j);
-			continue;
-		}
-		if (alt->desc.bInterfaceSubClass != 2) {
-			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u invalid AudioClass subtype\n",
-			       dev->devnum, ctrlif, j);
-			continue;
-		}
-		if (alt->desc.bNumEndpoints > 0) {
-			/* Check all endpoints; should they all have a bandwidth of 0 ? */
-			for (k = 0; k < alt->desc.bNumEndpoints; k++) {
-				if (le16_to_cpu(alt->endpoint[k].desc.wMaxPacketSize) > 0) {
-					printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u endpoint %d does not have 0 bandwidth at alt[0]\n", dev->devnum, ctrlif, k);
-					break;
-				}
-			}
-			if (k < alt->desc.bNumEndpoints)
-				continue;
-		}
-
-		alt = usb_altnum_to_altsetting(iface, 1);
-		if (!alt) {
-			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u has no altsetting 1\n",
-			       dev->devnum, ctrlif, j);
-			continue;
-		}
-		if (alt->desc.bNumEndpoints < 1) {
-			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u has no endpoint\n",
-			       dev->devnum, ctrlif, j);
-			continue;
-		}
-		/* note: this requires the data endpoint to be ep0 and the optional sync
-		   ep to be ep1, which seems to be the case */
-		if (alt->endpoint[0].desc.bEndpointAddress & USB_DIR_IN) {
-			if (numifin < USB_MAXINTERFACES) {
-				ifin[numifin++] = j;
-				usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1);
-			}
-		} else {
-			if (numifout < USB_MAXINTERFACES) {
-				ifout[numifout++] = j;
-				usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1);
-			}
-		}
-	}
-	printk(KERN_INFO "usbaudio: device %d audiocontrol interface %u has %u input and %u output AudioStreaming interfaces\n",
-	       dev->devnum, ctrlif, numifin, numifout);
-	for (i = 0; i < numifin && i < numifout; i++)
-		usb_audio_parsestreaming(s, buffer, buflen, ifin[i], ifout[i]);
-	for (j = i; j < numifin; j++)
-		usb_audio_parsestreaming(s, buffer, buflen, ifin[i], -1);
-	for (j = i; j < numifout; j++)
-		usb_audio_parsestreaming(s, buffer, buflen, -1, ifout[i]);
-	/* now walk through all OUTPUT_TERMINAL descriptors to search for mixers */
-	p1 = find_csinterface_descriptor(buffer, buflen, NULL, OUTPUT_TERMINAL, ctrlif, -1);
-	while (p1) {
-		if (p1[0] >= 9)
-			usb_audio_constructmixer(s, buffer, buflen, ctrlif, p1);
-		p1 = find_csinterface_descriptor(buffer, buflen, p1, OUTPUT_TERMINAL, ctrlif, -1);
-	}
-
-ret:
-	if (list_empty(&s->audiolist) && list_empty(&s->mixerlist)) {
-		kfree(s);
-		return NULL;
-	}
-	/* everything successful */
-	down(&open_sem);
-	list_add_tail(&s->audiodev, &audiodevs);
-	up(&open_sem);
-	printk(KERN_DEBUG "usb_audio_parsecontrol: usb_audio_state at %p\n", s);
-	return s;
-}
-
-/* we only care for the currently active configuration */
-
-static int usb_audio_probe(struct usb_interface *intf,
-			   const struct usb_device_id *id)
-{
-	struct usb_device *dev = interface_to_usbdev (intf);
-	struct usb_audio_state *s;
-	unsigned char *buffer;
-	unsigned int buflen;
-
-#if 0
-	printk(KERN_DEBUG "usbaudio: Probing if %i: IC %x, ISC %x\n", ifnum,
-	       config->interface[ifnum].altsetting[0].desc.bInterfaceClass,
-	       config->interface[ifnum].altsetting[0].desc.bInterfaceSubClass);
-#endif
-
-	/*
-	 * audiocontrol interface found
-	 * find which configuration number is active
-	 */
-	buffer = dev->rawdescriptors[dev->actconfig - dev->config];
-	buflen = le16_to_cpu(dev->actconfig->desc.wTotalLength);
-	s = usb_audio_parsecontrol(dev, buffer, buflen, intf->altsetting->desc.bInterfaceNumber);
-	if (s) {
-		usb_set_intfdata (intf, s);
-		return 0;
-	}
-	return -ENODEV;
-}
-
-
-/* a revoke facility would make things simpler */
-
-static void usb_audio_disconnect(struct usb_interface *intf)
-{
-	struct usb_audio_state *s = usb_get_intfdata (intf);
-	struct usb_audiodev *as;
-	struct usb_mixerdev *ms;
-
-	if (!s)
-		return;
-
-	/* we get called with -1 for every audiostreaming interface registered */
-	if (s == (struct usb_audio_state *)-1) {
-		dprintk((KERN_DEBUG "usbaudio: note, usb_audio_disconnect called with -1\n"));
-		return;
-	}
-	if (!s->usbdev) {
-		dprintk((KERN_DEBUG "usbaudio: error,  usb_audio_disconnect already called for %p!\n", s));
-		return;
-	}
-	down(&open_sem);
-	list_del_init(&s->audiodev);
-	s->usbdev = NULL;
-	usb_set_intfdata (intf, NULL);
-
-	/* deregister all audio and mixer devices, so no new processes can open this device */
-	list_for_each_entry(as, &s->audiolist, list) {
-		usbin_disc(as);
-		usbout_disc(as);
-		wake_up(&as->usbin.dma.wait);
-		wake_up(&as->usbout.dma.wait);
-		if (as->dev_audio >= 0) {
-			unregister_sound_dsp(as->dev_audio);
-			printk(KERN_INFO "usbaudio: unregister dsp 14,%d\n", as->dev_audio);
-		}
-		as->dev_audio = -1;
-	}
-	list_for_each_entry(ms, &s->mixerlist, list) {
-		if (ms->dev_mixer >= 0) {
-			unregister_sound_mixer(ms->dev_mixer);
-			printk(KERN_INFO "usbaudio: unregister mixer 14,%d\n", ms->dev_mixer);
-		}
-		ms->dev_mixer = -1;
-	}
-	release(s);
-	wake_up(&open_wait);
-}
-
-static int __init usb_audio_init(void)
-{
-	int result = usb_register(&usb_audio_driver);
-	if (result == 0) 
-		info(DRIVER_VERSION ":" DRIVER_DESC);
-	return result;
-}
-
-
-static void __exit usb_audio_cleanup(void)
-{
-	usb_deregister(&usb_audio_driver);
-}
-
-module_init(usb_audio_init);
-module_exit(usb_audio_cleanup);
-
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/usb/class/audio.h b/drivers/usb/class/audio.h
deleted file mode 100644
index 45916eb..0000000
--- a/drivers/usb/class/audio.h
+++ /dev/null
@@ -1,110 +0,0 @@
-#define CS_AUDIO_UNDEFINED		0x20
-#define CS_AUDIO_DEVICE			0x21
-#define CS_AUDIO_CONFIGURATION		0x22
-#define CS_AUDIO_STRING			0x23
-#define CS_AUDIO_INTERFACE		0x24
-#define CS_AUDIO_ENDPOINT		0x25
-
-#define HEADER				0x01
-#define INPUT_TERMINAL			0x02
-#define OUTPUT_TERMINAL			0x03
-#define MIXER_UNIT			0x04
-#define SELECTOR_UNIT			0x05
-#define FEATURE_UNIT			0x06
-#define PROCESSING_UNIT			0x07
-#define EXTENSION_UNIT			0x08
-
-#define AS_GENERAL			0x01
-#define FORMAT_TYPE			0x02
-#define FORMAT_SPECIFIC			0x03
-
-#define EP_GENERAL			0x01
-
-#define MAX_CHAN			9
-#define MAX_FREQ			16
-#define MAX_IFACE			8
-#define MAX_FORMAT			8
-#define MAX_ALT				32 	/* Sorry, we need quite a few for the Philips webcams */
-
-struct usb_audio_terminal
-{	
-	u8	flags;
-	u8	assoc;
-	u16	type;			/* Mic etc */
-	u8	channels;
-	u8	source;
-	u16	chancfg;
-};
-
-struct usb_audio_format
-{
-	u8	type;
-	u8	channels;
-	u8	num_freq;
-	u8	sfz;
-	u8	bits;
-	u16	freq[MAX_FREQ];
-};
-
-struct usb_audio_interface
-{
-	u8	terminal;
-	u8	delay;
-	u16	num_formats;
-	u16	format_type;
-	u8	flags;
-	u8	idleconf;	/* Idle config */
-#define AU_IFACE_FOUND	1
-	struct  usb_audio_format format[MAX_FORMAT];
-};
-
-struct usb_audio_device
-{
-	struct list_head list;
-	u8	mixer;
-	u8	selector;
-	void	*irq_handle;
-	u8	num_channels;
-	u8	num_dsp_iface;
-	u8	channel_map[MAX_CHAN];
-	struct usb_audio_terminal terminal[MAX_CHAN];
-	struct usb_audio_interface interface[MAX_IFACE][MAX_ALT];
-};
-
-
-
-/* Audio Class specific Request Codes */
-
-#define SET_CUR    0x01
-#define GET_CUR    0x81
-#define SET_MIN    0x02
-#define GET_MIN    0x82
-#define SET_MAX    0x03
-#define GET_MAX    0x83
-#define SET_RES    0x04
-#define GET_RES    0x84
-#define SET_MEM    0x05
-#define GET_MEM    0x85
-#define GET_STAT   0xff
-
-/* Terminal Control Selectors */
-
-#define COPY_PROTECT_CONTROL       0x01
-
-/* Feature Unit Control Selectors */
-
-#define MUTE_CONTROL               0x01
-#define VOLUME_CONTROL             0x02
-#define BASS_CONTROL               0x03
-#define MID_CONTROL                0x04
-#define TREBLE_CONTROL             0x05
-#define GRAPHIC_EQUALIZER_CONTROL  0x06
-#define AUTOMATIC_GAIN_CONTROL     0x07
-#define DELAY_CONTROL              0x08
-#define BASS_BOOST_CONTROL         0x09
-#define LOUDNESS_CONTROL           0x0a
-
-/* Endpoint Control Selectors */
-
-#define SAMPLING_FREQ_CONTROL      0x01
-#define PITCH_CONTROL              0x02
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 97bdeb1..6dd339f 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -60,6 +60,7 @@
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include <linux/usb.h>
 #include <linux/usb_cdc.h>
@@ -80,7 +81,7 @@
 static struct tty_driver *acm_tty_driver;
 static struct acm *acm_table[ACM_TTY_MINORS];
 
-static DECLARE_MUTEX(open_sem);
+static DEFINE_MUTEX(open_mutex);
 
 #define ACM_READY(acm)	(acm && acm->dev && acm->used)
 
@@ -431,8 +432,8 @@
 	int rv = -EINVAL;
 	int i;
 	dbg("Entering acm_tty_open.\n");
-	
-	down(&open_sem);
+
+	mutex_lock(&open_mutex);
 
 	acm = acm_table[tty->index];
 	if (!acm || !acm->dev)
@@ -474,14 +475,14 @@
 
 done:
 err_out:
-	up(&open_sem);
+	mutex_unlock(&open_mutex);
 	return rv;
 
 full_bailout:
 	usb_kill_urb(acm->ctrlurb);
 bail_out:
 	acm->used--;
-	up(&open_sem);
+	mutex_unlock(&open_mutex);
 	return -EIO;
 }
 
@@ -507,7 +508,7 @@
 	if (!acm || !acm->used)
 		return;
 
-	down(&open_sem);
+	mutex_lock(&open_mutex);
 	if (!--acm->used) {
 		if (acm->dev) {
 			acm_set_control(acm, acm->ctrlout = 0);
@@ -518,7 +519,7 @@
 		} else
 			acm_tty_unregister(acm);
 	}
-	up(&open_sem);
+	mutex_unlock(&open_mutex);
 }
 
 static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
@@ -1013,9 +1014,9 @@
 		return;
 	}
 
-	down(&open_sem);
+	mutex_lock(&open_mutex);
 	if (!usb_get_intfdata(intf)) {
-		up(&open_sem);
+		mutex_unlock(&open_mutex);
 		return;
 	}
 	acm->dev = NULL;
@@ -1045,11 +1046,11 @@
 
 	if (!acm->used) {
 		acm_tty_unregister(acm);
-		up(&open_sem);
+		mutex_unlock(&open_mutex);
 		return;
 	}
 
-	up(&open_sem);
+	mutex_unlock(&open_mutex);
 
 	if (acm->tty)
 		tty_hangup(acm->tty);
diff --git a/drivers/usb/class/usb-midi.c b/drivers/usb/class/usb-midi.c
deleted file mode 100644
index f13f004..0000000
--- a/drivers/usb/class/usb-midi.c
+++ /dev/null
@@ -1,2153 +0,0 @@
-/*
-  usb-midi.c  --  USB-MIDI driver
-
-  Copyright (C) 2001 
-      NAGANO Daisuke <breeze.nagano@nifty.ne.jp>
-
-  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.
-
-  This driver is based on:
-    - 'Universal Serial Bus Device Class Definition for MIDI Device'
-    - linux/drivers/sound/es1371.c, linux/drivers/usb/audio.c
-    - alsa/lowlevel/pci/cs64xx.c
-    - umidi.c for NetBSD
- */
-
-/* ------------------------------------------------------------------------- */
-
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/poll.h>
-#include <linux/sound.h>
-#include <linux/init.h>
-#include <asm/semaphore.h>
-
-#include "usb-midi.h"
-
-/* ------------------------------------------------------------------------- */
-
-/* More verbose on syslog */
-#undef MIDI_DEBUG
-
-#define MIDI_IN_BUFSIZ 1024
-
-#define HAVE_SUPPORT_USB_MIDI_CLASS
-
-#undef HAVE_SUPPORT_ALSA
-
-/* ------------------------------------------------------------------------- */
-
-static int singlebyte = 0;
-module_param(singlebyte, int, 0);
-MODULE_PARM_DESC(singlebyte,"Enable sending MIDI messages with single message packet");
-
-static int maxdevices = 4;
-module_param(maxdevices, int, 0);
-MODULE_PARM_DESC(maxdevices,"Max number of allocatable MIDI device");
-
-static int uvendor     = -1;
-module_param(uvendor, int, 0);
-MODULE_PARM_DESC(uvendor, "The USB Vendor ID of a semi-compliant interface");
-
-static int uproduct    = -1;
-module_param(uproduct, int, 0);
-MODULE_PARM_DESC(uproduct, "The USB Product ID of a semi-compliant interface");
-
-static int uinterface  = -1;
-module_param(uinterface, int, 0);
-MODULE_PARM_DESC(uinterface, "The Interface number of a semi-compliant interface");
-
-static int ualt        = -1;
-module_param(ualt, int, 0);
-MODULE_PARM_DESC(ualt, "The optional alternative setting of a semi-compliant interface");
-
-static int umin        = -1;
-module_param(umin, int, 0);
-MODULE_PARM_DESC(umin, "The input endpoint of a semi-compliant interface");
-
-static int umout       = -1;
-module_param(umout, int, 0);
-MODULE_PARM_DESC(umout, "The output endpoint of a semi-compliant interface");
-
-static int ucable      = -1;
-module_param(ucable, int, 0);
-MODULE_PARM_DESC(ucable, "The cable number used for a semi-compliant interface");
-
-/** Note -- the usb_string() returns only Latin-1 characters.
- * (unicode chars <= 255). To support Japanese, a unicode16LE-to-EUC or
- * unicode16LE-to-JIS routine is needed to wrap around usb_get_string().
- **/
-static unsigned short ulangid      = 0x0409; /** 0x0411 for Japanese **/
-module_param(ulangid, ushort, 0);
-MODULE_PARM_DESC(ulangid, "The optional preferred USB Language ID for all devices");
-
-MODULE_AUTHOR("NAGANO Daisuke <breeze.nagano@nifty.ne.jp>");
-MODULE_DESCRIPTION("USB-MIDI driver");
-MODULE_LICENSE("GPL");
-
-/* ------------------------------------------------------------------------- */
-
-/** MIDIStreaming Class-Specific Interface Descriptor Subtypes **/
-
-#define MS_DESCRIPTOR_UNDEFINED	0
-#define MS_HEADER		1
-#define MIDI_IN_JACK		2
-#define MIDI_OUT_JACK		3
-/* Spec reads: ELEMENT */
-#define ELEMENT_DESCRIPTOR   	4
-
-#define MS_HEADER_LENGTH	7
-
-/** MIDIStreaming Class-Specific Endpoint Descriptor Subtypes **/
-
-#define DESCRIPTOR_UNDEFINED	0
-/* Spec reads: MS_GENERAL */
-#define MS_GENERAL_ENDPOINT	1
-
-/** MIDIStreaming MIDI IN and OUT Jack Types **/
-
-#define JACK_TYPE_UNDEFINED	0
-/* Spec reads: EMBEDDED */
-#define EMBEDDED_JACK		1
-/* Spec reads: EXTERNAL */
-#define EXTERNAL_JACK		2
-
-
-/* structure summary
-  
-      usb_midi_state     usb_device
-       |         |
-      *|        *|       per ep
-     in_ep     out_ep
-       |         |
-      *|        *|       per cable
-      min       mout
-       |         |       (cable to device pairing magic)
-       |         |
-       usb_midi_dev      dev_id (major,minor) == file->private_data
-
-*/
-
-/* usb_midi_state: corresponds to a USB-MIDI module */
-struct usb_midi_state {
-	struct list_head   mididev;
-	
-	struct usb_device *usbdev;
-	
-	struct list_head   midiDevList;
-	struct list_head   inEndpointList;
-	struct list_head   outEndpointList;
-	
-	spinlock_t         lock;
-	
-	unsigned int       count; /* usage counter */
-};
-
-/* midi_out_endpoint: corresponds to an output endpoint */
-struct midi_out_endpoint {
-	struct list_head  list;
-	
-	struct usb_device *usbdev;
-	int                endpoint;
-	spinlock_t         lock;
-	wait_queue_head_t  wait;
-	
-	unsigned char     *buf;
-	int                bufWrPtr;
-	int                bufSize;
-	
-	struct urb       *urb;
-};
-
-/* midi_in_endpoint: corresponds to an input endpoint */
-struct midi_in_endpoint {
-	struct list_head   list;
-
-	struct usb_device *usbdev;
-	int                endpoint;
-	spinlock_t         lock;
-	wait_queue_head_t  wait;
-
-	struct usb_mididev *cables[16];	// cables open for read
-	int                 readers;	// number of cables open for read
-
-	struct urb        *urb;
-	unsigned char     *recvBuf;
-	int                recvBufSize;
-	int                urbSubmitted;	//FIXME: == readers > 0
-};
-
-/* usb_mididev: corresponds to a logical device */
-struct usb_mididev {
-	struct list_head       list;
-
-	struct usb_midi_state *midi;
-	int                    dev_midi;
-	mode_t                 open_mode;
-
-	struct {
-		struct midi_in_endpoint *ep;
-		int              cableId;
-		
-// as we are pushing data from usb_bulk_read to usb_midi_read,
-// we need a larger, cyclic buffer here.
-		unsigned char    buf[MIDI_IN_BUFSIZ];
-		int              bufRdPtr;
-		int              bufWrPtr;
-		int              bufRemains;
-	} min;
-
-	struct {
-		struct midi_out_endpoint *ep;
-		int              cableId;
-		
-		unsigned char    buf[3];
-		int              bufPtr;
-		int              bufRemains;
-		
-		int              isInExclusive;
-		unsigned char    lastEvent;
-	} mout;
-
-	int singlebyte;
-};
-
-/** Map the high nybble of MIDI voice messages to number of Message bytes.
- * High nyble ranges from 0x8 to 0xe
- */
-
-static int remains_80e0[] = {
-	3,	/** 0x8X Note Off **/
-	3,	/** 0x9X Note On **/
-	3,	/** 0xAX Poly-key pressure **/
-	3,	/** 0xBX Control Change **/
-	2,	/** 0xCX Program Change **/
-	2,	/** 0xDX Channel pressure **/
-	3 	/** 0xEX PitchBend Change **/
-};
-
-/** Map the messages to a number of Message bytes.
- *
- **/
-static int remains_f0f6[] = {
-	0,	/** 0xF0 **/
-	2,	/** 0XF1 **/
-	3,	/** 0XF2 **/
-	2,	/** 0XF3 **/
-	2,	/** 0XF4 (Undefined by MIDI Spec, and subject to change) **/
-	2,	/** 0XF5 (Undefined by MIDI Spec, and subject to change) **/
-	1	/** 0XF6 **/
-};
-
-/** Map the messages to a CIN (Code Index Number).
- *
- **/
-static int cin_f0ff[] = {
-	4,	/** 0xF0 System Exclusive Message Start (special cases may be 6 or 7) */
-	2,	/** 0xF1 **/
-	3,	/** 0xF2 **/
-	2,	/** 0xF3 **/
-	2,	/** 0xF4 **/
-	2,	/** 0xF5 **/
-	5,	/** 0xF6 **/
-	5,	/** 0xF7 End of System Exclusive Message (May be 6 or 7) **/
-	5,	/** 0xF8 **/
-	5,	/** 0xF9 **/
-	5,	/** 0xFA **/
-	5,	/** 0xFB **/
-	5,	/** 0xFC **/
-	5,	/** 0xFD **/
-	5,	/** 0xFE **/
-	5	/** 0xFF **/
-};
-
-/** Map MIDIStreaming Event packet Code Index Number (low nybble of byte 0)
- * to the number of bytes of valid MIDI data.
- *
- * CIN of 0 and 1 are NOT USED in MIDIStreaming 1.0.
- *
- **/
-static int cin_to_len[] = {
-	0, 0, 2, 3,
-	3, 1, 2, 3,
-	3, 3, 3, 3,
-	2, 2, 3, 1
-};
-
-
-/* ------------------------------------------------------------------------- */
-
-static struct list_head mididevs = LIST_HEAD_INIT(mididevs);
-
-static DECLARE_MUTEX(open_sem);
-static DECLARE_WAIT_QUEUE_HEAD(open_wait);
-
-
-/* ------------------------------------------------------------------------- */
-
-static void usb_write_callback(struct urb *urb, struct pt_regs *regs)
-{
-	struct midi_out_endpoint *ep = (struct midi_out_endpoint *)urb->context;
-
-	if ( waitqueue_active( &ep->wait ) )
-		wake_up_interruptible( &ep->wait );
-}
-
-
-static int usb_write( struct midi_out_endpoint *ep, unsigned char *buf, int len )
-{
-	struct usb_device *d;
-	int pipe;
-	int ret = 0;
-	int status;
-	int maxretry = 50;
-	
-	DECLARE_WAITQUEUE(wait,current);
-	init_waitqueue_head(&ep->wait);
-
-	d = ep->usbdev;
-	pipe = usb_sndbulkpipe(d, ep->endpoint);
-	usb_fill_bulk_urb( ep->urb, d, pipe, (unsigned char*)buf, len,
-		       usb_write_callback, ep );
-
-	status = usb_submit_urb(ep->urb, GFP_KERNEL);
-    
-	if (status) {
-		printk(KERN_ERR "usbmidi: Cannot submit urb (%d)\n",status);
-		ret = -EIO;
-		goto error;
-	}
-
-	add_wait_queue( &ep->wait, &wait );
-	set_current_state( TASK_INTERRUPTIBLE );
-
-	while( ep->urb->status == -EINPROGRESS ) {
-		if ( maxretry-- < 0 ) {
-			printk(KERN_ERR "usbmidi: usb_bulk_msg timed out\n");
-			ret = -ETIME;
-			break;
-		}
-		interruptible_sleep_on_timeout( &ep->wait, 10 );
-	}
-	set_current_state( TASK_RUNNING );
-	remove_wait_queue( &ep->wait, &wait );
-
-error:
-	return ret;
-}
-
-
-/** Copy data from URB to In endpoint buf.
- * Discard if CIN == 0 or CIN = 1.
- *
- *
- **/
-
-static void usb_bulk_read(struct urb *urb, struct pt_regs *regs)
-{
-	struct midi_in_endpoint *ep = (struct midi_in_endpoint *)(urb->context);
-	unsigned char *data = urb->transfer_buffer;
-	int i, j, wake;
-
-	if ( !ep->urbSubmitted ) {
-		return;
-	}
-
-	if ( (urb->status == 0) && (urb->actual_length > 0) ) {
-		wake = 0;
-		spin_lock( &ep->lock );
-
-		for(j = 0; j < urb->actual_length; j += 4) {
-			int cin = (data[j]>>0)&0xf;
-			int cab = (data[j]>>4)&0xf;
-			struct usb_mididev *cable = ep->cables[cab];
-			if ( cable ) {
-				int len = cin_to_len[cin]; /** length of MIDI data **/
-				for (i = 0; i < len; i++) {
-					cable->min.buf[cable->min.bufWrPtr] = data[1+i+j];
-					cable->min.bufWrPtr = (cable->min.bufWrPtr+1)%MIDI_IN_BUFSIZ;
-					if (cable->min.bufRemains < MIDI_IN_BUFSIZ)
-						cable->min.bufRemains += 1;
-					else /** need to drop data **/
-						cable->min.bufRdPtr += (cable->min.bufRdPtr+1)%MIDI_IN_BUFSIZ;
-					wake = 1;
-				}
-			}
-		}
-
-		spin_unlock ( &ep->lock );
-		if ( wake ) {
-			wake_up( &ep->wait );
-		}
-	}
-
-	/* urb->dev must be reinitialized on 2.4.x kernels */
-	urb->dev = ep->usbdev;
-
-	urb->actual_length = 0;
-	usb_submit_urb(urb, GFP_ATOMIC);
-}
-
-
-
-/* ------------------------------------------------------------------------- */
-
-/* This routine must be called with spin_lock */
-
-/** Wrapper around usb_write().
- *  This routine must be called with spin_lock held on ep.
- *  Called by midiWrite(), putOneMidiEvent(), and  usb_midi_write();
- **/
-static int flush_midi_buffer( struct midi_out_endpoint *ep )
-{
-	int ret=0;
-
-	if ( ep->bufWrPtr > 0 ) {
-		ret = usb_write( ep, ep->buf, ep->bufWrPtr );
-		ep->bufWrPtr = 0;
-	}
-
-	return ret;
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-
-/** Given a MIDI Event, determine size of data to be attached to 
- * USB-MIDI packet.
- * Returns 1, 2 or 3.
- * Called by midiWrite();
- * Uses remains_80e0 and remains_f0f6;
- **/
-static int get_remains(int event)
-{
-	int ret;
-
-	if ( event  < 0x80 ) {
-		ret = 1;
-	} else if ( event < 0xf0 ) {
-		ret = remains_80e0[((event-0x80)>>4)&0x0f];
-	} else if ( event < 0xf7 ) {
-		ret = remains_f0f6[event-0xf0];
-	} else {
-		ret = 1;
-	}
-
-	return ret;
-}
-
-/** Given the output MIDI data in the output buffer, computes a reasonable 
- * CIN.
- * Called by putOneMidiEvent().
- **/
-static int get_CIN( struct usb_mididev *m )
-{
-	int cin;
-
-	if ( m->mout.buf[0] == 0xf7 ) {
-		cin = 5;
-	}
-	else if ( m->mout.buf[1] == 0xf7 ) {
-		cin = 6;
-	}
-	else if ( m->mout.buf[2] == 0xf7 ) {
-		cin = 7;
-	}
-	else {
-		if ( m->mout.isInExclusive == 1 ) {
-			cin = 4;
-		} else if ( m->mout.buf[0] < 0x80 ) {
-			/** One byte that we know nothing about. **/
-			cin = 0xF; 
-		} else if ( m->mout.buf[0] < 0xf0 ) {
-			/** MIDI Voice messages 0x8X to 0xEX map to cin 0x8 to 0xE. **/
-			cin = (m->mout.buf[0]>>4)&0x0f; 
-		}
-		else {
-			/** Special lookup table exists for real-time events. **/
-			cin = cin_f0ff[m->mout.buf[0]-0xf0];
-		}
-	}
-
-	return cin;
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-
-
-/** Move data to USB endpoint buffer.
- *
- **/
-static int put_one_midi_event(struct usb_mididev *m)
-{
-	int cin;
-	unsigned long flags;
-	struct midi_out_endpoint *ep = m->mout.ep;
-	int ret=0;
-
-	cin = get_CIN( m );
-	if ( cin > 0x0f || cin < 0 ) {
-		return -EINVAL;
-	}
-
-	spin_lock_irqsave( &ep->lock, flags );
-	ep->buf[ep->bufWrPtr++] = (m->mout.cableId<<4) | cin;
-	ep->buf[ep->bufWrPtr++] = m->mout.buf[0];
-	ep->buf[ep->bufWrPtr++] = m->mout.buf[1];
-	ep->buf[ep->bufWrPtr++] = m->mout.buf[2];
-	if ( ep->bufWrPtr >= ep->bufSize ) {
-		ret = flush_midi_buffer( ep );
-	}
-	spin_unlock_irqrestore( &ep->lock, flags);
-
-	m->mout.buf[0] = m->mout.buf[1] = m->mout.buf[2] = 0;
-	m->mout.bufPtr = 0;
-
-	return ret;
-}
-
-/** Write the MIDI message v on the midi device.
- *  Called by usb_midi_write();
- *  Responsible for packaging a MIDI data stream into USB-MIDI packets.
- **/
-
-static int midi_write( struct usb_mididev *m, int v )
-{
-	unsigned long flags;
-	struct midi_out_endpoint *ep = m->mout.ep;
-	int ret=0;
-	unsigned char c = (unsigned char)v;
-	unsigned char sysrt_buf[4];
-
-	if ( m->singlebyte != 0 ) {
-		/** Simple code to handle the single-byte USB-MIDI protocol. */
-		spin_lock_irqsave( &ep->lock, flags );
-		if ( ep->bufWrPtr+4 > ep->bufSize ) {
-			ret = flush_midi_buffer( ep );
-			if ( !ret ) {
-				spin_unlock_irqrestore( &ep->lock, flags );
-				return ret;
-			}
-		}
-		ep->buf[ep->bufWrPtr++] = (m->mout.cableId<<4) |  0x0f; /* single byte */
-		ep->buf[ep->bufWrPtr++] = c;
-		ep->buf[ep->bufWrPtr++] = 0;
-		ep->buf[ep->bufWrPtr++] = 0;
-		if ( ep->bufWrPtr >= ep->bufSize ) {
-			ret = flush_midi_buffer( ep );
-		}
-		spin_unlock_irqrestore( &ep->lock, flags );
-
-		return ret;
-	}
-	/** Normal USB-MIDI protocol begins here. */
-
-	if ( c > 0xf7 ) {	/* system: Realtime messages */
-		/** Realtime messages are written IMMEDIATELY. */
-		sysrt_buf[0] = (m->mout.cableId<<4) | 0x0f;
-		sysrt_buf[1] = c;
-		sysrt_buf[2] = 0;
-		sysrt_buf[3] = 0;
-		spin_lock_irqsave( &ep->lock, flags );
-		ret = usb_write( ep, sysrt_buf, 4 );
-		spin_unlock_irqrestore( &ep->lock, flags );
-		/* m->mout.lastEvent = 0; */
-
-		return ret;
-	}
-
-	if ( c >= 0x80 ) {
-		if ( c < 0xf0 ) {
-			m->mout.lastEvent = c;
-			m->mout.isInExclusive = 0;
-			m->mout.bufRemains = get_remains(c);
-		} else if ( c == 0xf0 ) {
-			/* m->mout.lastEvent = 0; */
-			m->mout.isInExclusive = 1;
-			m->mout.bufRemains = get_remains(c);
-		} else if ( c == 0xf7 && m->mout.isInExclusive == 1 ) {
-			/* m->mout.lastEvent = 0; */
-			m->mout.isInExclusive = 0;
-			m->mout.bufRemains = 1;
-		} else if ( c > 0xf0 ) {
-			/* m->mout.lastEvent = 0; */
-			m->mout.isInExclusive = 0;
-			m->mout.bufRemains = get_remains(c);
-		}
-    
-	} else if ( m->mout.bufRemains == 0 && m->mout.isInExclusive == 0 ) {
-		if ( m->mout.lastEvent == 0 ) {
-			return 0; /* discard, waiting for the first event */
-		}
-		/** track status **/
-		m->mout.buf[0] = m->mout.lastEvent;
-		m->mout.bufPtr = 1;
-		m->mout.bufRemains = get_remains(m->mout.lastEvent)-1;
-	}
-  
-	m->mout.buf[m->mout.bufPtr++] = c;
-	m->mout.bufRemains--;
-	if ( m->mout.bufRemains == 0 || m->mout.bufPtr >= 3) {
-		ret = put_one_midi_event(m);
-	}
-
-	return ret;
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-/** Basic operation on /dev/midiXX as registered through struct file_operations.
- *
- *  Basic contract: Used to change the current read/write position in a file.
- *  On success, the non-negative position is reported.
- *  On failure, the negative of an error code is reported.
- *
- *  Because a MIDIStream is not a file, all seek operations are doomed to fail.
- *
- **/
-static loff_t usb_midi_llseek(struct file *file, loff_t offset, int origin)
-{
-	/** Tell user you cannot seek on a PIPE-like device. **/
-	return -ESPIPE;
-}
-
-
-/** Basic operation on /dev/midiXX as registered through struct file_operations.
- *
- * Basic contract: Block until count bytes have been read or an error occurs.
- *
- **/
-
-static ssize_t usb_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
-	struct usb_mididev *m = (struct usb_mididev *)file->private_data;
-	struct midi_in_endpoint *ep = m->min.ep;
-	ssize_t ret;
-	DECLARE_WAITQUEUE(wait, current);
-
-	if ( !access_ok(VERIFY_READ, buffer, count) ) {
-		return -EFAULT;
-	}
-	if ( count == 0 ) {
-		return 0;
-	}
-
-	add_wait_queue( &ep->wait, &wait );
-	ret = 0;
-	while( count > 0 ) {
-		int cnt;
-		int d = (int)count;
-
-		cnt = m->min.bufRemains;
-		if ( cnt > d ) {
-			cnt = d;
-		}
-
-		if ( cnt <= 0 ) {
-			if ( file->f_flags & O_NONBLOCK ) {
-				if (!ret) 
-					ret = -EAGAIN;
-				break;
-			}
-			__set_current_state(TASK_INTERRUPTIBLE);
-			schedule();
-			if (signal_pending(current)) {
-				if(!ret)
-					ret=-ERESTARTSYS;
-				break;
-			}
-			continue;
-		}
-
-		{
-			int i;
-			unsigned long flags; /* used to synchronize access to the endpoint */
-			spin_lock_irqsave( &ep->lock, flags );
-			for (i = 0; i < cnt; i++) {
-				if ( copy_to_user( buffer+i, m->min.buf+m->min.bufRdPtr, 1 ) ) {
-					if ( !ret )
-						ret = -EFAULT;
-					break;
-				}
-				m->min.bufRdPtr = (m->min.bufRdPtr+1)%MIDI_IN_BUFSIZ;
-				m->min.bufRemains -= 1;
-			}
-			spin_unlock_irqrestore( &ep->lock, flags );
-		}
-
-		count-=cnt;
-		buffer+=cnt;
-		ret+=cnt;
-
-		break;
-	}
-
-	remove_wait_queue( &ep->wait, &wait );
-	set_current_state(TASK_RUNNING);
-
-	return ret;
-}
-
-
-/** Basic operation on /dev/midiXX as registered through struct file_operations.
- *
- *  Basic Contract: Take MIDI data byte-by-byte and pass it to
- *  writeMidi() which packages MIDI data into USB-MIDI stream.
- *  Then flushMidiData() is called to ensure all bytes have been written
- *  in a timely fashion.
- *
- **/
-
-static ssize_t usb_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
-	struct usb_mididev *m = (struct usb_mididev *)file->private_data;
-	ssize_t ret;
-	unsigned long int flags;
-
-	if ( !access_ok(VERIFY_READ, buffer, count) ) {
-		return -EFAULT;
-	}
-	if ( count == 0 ) {
-		return 0;
-	}
-
-	ret = 0;
-	while( count > 0 ) {
-		unsigned char c;
-
-		if (copy_from_user((unsigned char *)&c, buffer, 1)) {
-			if ( ret == 0 )
-				ret = -EFAULT;
-			break;
-		}
-		if( midi_write(m, (int)c) ) {
-			if ( ret == 0 )
-				ret = -EFAULT;
-			break;
-		}
-		count--;
-		buffer++;
-		ret++;
-	}
-
-	spin_lock_irqsave( &m->mout.ep->lock, flags );
-	if ( flush_midi_buffer(m->mout.ep) < 0 ) {
-		ret = -EFAULT;
-	}
-	spin_unlock_irqrestore( &m->mout.ep->lock, flags );
-
-	return ret;
-}
-
-/** Basic operation on /dev/midiXX as registered through struct file_operations.
- *
- * Basic contract:  Wait (spin) until ready to read or write on the file.
- *
- **/
-static unsigned int usb_midi_poll(struct file *file, struct poll_table_struct *wait)
-{
-	struct usb_mididev *m = (struct usb_mididev *)file->private_data;
-	struct midi_in_endpoint *iep = m->min.ep;
-	struct midi_out_endpoint *oep = m->mout.ep;
-	unsigned long flags;
-	unsigned int mask = 0;
-  
-	if ( file->f_mode & FMODE_READ ) {
-		poll_wait( file, &iep->wait, wait );
-		spin_lock_irqsave( &iep->lock, flags );
-		if ( m->min.bufRemains > 0 )
-			mask |= POLLIN | POLLRDNORM;
-		spin_unlock_irqrestore( &iep->lock, flags );
-	}
-
-	if ( file->f_mode & FMODE_WRITE ) {
-		poll_wait( file, &oep->wait, wait );
-		spin_lock_irqsave( &oep->lock, flags );
-		if ( oep->bufWrPtr < oep->bufSize )
-			mask |= POLLOUT | POLLWRNORM;
-		spin_unlock_irqrestore( &oep->lock, flags );
-	}
-
-	return mask;
-}
-
-
-/** Basic operation on /dev/midiXX as registered through struct file_operations.
- *
- * Basic contract: This is always the first operation performed on the
- * device node. If no method is defined, the open succeeds without any
- * notification given to the module.
- *
- **/
-
-static int usb_midi_open(struct inode *inode, struct file *file)
-{
-	int minor = iminor(inode);
-	DECLARE_WAITQUEUE(wait, current);
-	struct usb_midi_state *s;
-	struct usb_mididev    *m;
-	unsigned long flags;
-	int succeed = 0;
-
-#if 0
-	printk(KERN_INFO "usb-midi: Open minor= %d.\n", minor);
-#endif
-
-	for(;;) {
-		down(&open_sem);
-		list_for_each_entry(s, &mididevs, mididev) {
-			list_for_each_entry(m, &s->midiDevList, list) {
-				if ( !((m->dev_midi ^ minor) & ~0xf) )
-					goto device_found;
-			}
-		}
-		up(&open_sem);
-		return -ENODEV;
-
-	device_found:
-		if ( !s->usbdev ) {
-			up(&open_sem);
-			return -EIO;
-		}
-		if ( !(m->open_mode & file->f_mode) ) {
-			break;
-		}
-		if ( file->f_flags & O_NONBLOCK ) {
-			up(&open_sem);
-			return -EBUSY;
-		}
-		__set_current_state(TASK_INTERRUPTIBLE);
-		add_wait_queue( &open_wait, &wait );
-		up(&open_sem);
-		schedule();
-		remove_wait_queue( &open_wait, &wait );
-		if ( signal_pending(current) ) {
-			return -ERESTARTSYS;
-		}
-	}
-
-	file->private_data = m;
-	spin_lock_irqsave( &s->lock, flags );
-
-	if ( !(m->open_mode & (FMODE_READ | FMODE_WRITE)) ) {
-		//FIXME: intented semantics unclear here
-		m->min.bufRdPtr       = 0;
-		m->min.bufWrPtr       = 0;
-		m->min.bufRemains     = 0;
-		spin_lock_init(&m->min.ep->lock);
-
-		m->mout.bufPtr        = 0;
-		m->mout.bufRemains    = 0;
-		m->mout.isInExclusive = 0;
-		m->mout.lastEvent     = 0;
-		spin_lock_init(&m->mout.ep->lock);
-	}
-
-	if ( (file->f_mode & FMODE_READ) && m->min.ep != NULL ) {
-		unsigned long int flagsep;
-		spin_lock_irqsave( &m->min.ep->lock, flagsep );
-		m->min.ep->cables[m->min.cableId] = m;
-		m->min.ep->readers += 1;
-		m->min.bufRdPtr       = 0;
-		m->min.bufWrPtr       = 0;
-		m->min.bufRemains     = 0;
-		spin_unlock_irqrestore( &m->min.ep->lock, flagsep );
-
-		if ( !(m->min.ep->urbSubmitted)) {
-
-			/* urb->dev must be reinitialized on 2.4.x kernels */
-			m->min.ep->urb->dev = m->min.ep->usbdev;
-
-			if ( usb_submit_urb(m->min.ep->urb, GFP_ATOMIC) ) {
-				printk(KERN_ERR "usbmidi: Cannot submit urb for MIDI-IN\n");
-			}
-			m->min.ep->urbSubmitted = 1;
-		}
-		m->open_mode |= FMODE_READ;
-		succeed = 1;
-	}
-
-	if ( (file->f_mode & FMODE_WRITE) && m->mout.ep != NULL ) {
-		m->mout.bufPtr        = 0;
-		m->mout.bufRemains    = 0;
-		m->mout.isInExclusive = 0;
-		m->mout.lastEvent     = 0;
-		m->open_mode |= FMODE_WRITE;
-		succeed = 1;
-	}
-
-	spin_unlock_irqrestore( &s->lock, flags );
-
-	s->count++;
-	up(&open_sem);
-
-	/** Changed to prevent extra increments to USE_COUNT. **/
-	if (!succeed) {
-		return -EBUSY;
-	}
-
-#if 0
-	printk(KERN_INFO "usb-midi: Open Succeeded. minor= %d.\n", minor);
-#endif
-
-	return nonseekable_open(inode, file); /** Success. **/
-}
-
-
-/** Basic operation on /dev/midiXX as registered through struct file_operations.
- *
- *  Basic contract: Close an opened file and deallocate anything we allocated.
- *  Like open(), this can be missing. If open set file->private_data,
- *  release() must clear it.
- *
- **/
-
-static int usb_midi_release(struct inode *inode, struct file *file)
-{
-	struct usb_mididev *m = (struct usb_mididev *)file->private_data;
-	struct usb_midi_state *s = (struct usb_midi_state *)m->midi;
-
-#if 0
-	printk(KERN_INFO "usb-midi: Close.\n");
-#endif
-
-	down(&open_sem);
-
-	if ( m->open_mode & FMODE_WRITE ) {
-		m->open_mode &= ~FMODE_WRITE;
-		usb_kill_urb( m->mout.ep->urb );
-	}
-
-	if ( m->open_mode & FMODE_READ ) {
-	        unsigned long int flagsep;
-	        spin_lock_irqsave( &m->min.ep->lock, flagsep );
-                m->min.ep->cables[m->min.cableId] = NULL; // discard cable
-                m->min.ep->readers -= 1;
-		m->open_mode &= ~FMODE_READ;
-		if ( m->min.ep->readers == 0 &&
-                     m->min.ep->urbSubmitted ) {
-			m->min.ep->urbSubmitted = 0;
-			usb_kill_urb(m->min.ep->urb);
-		}
-	        spin_unlock_irqrestore( &m->min.ep->lock, flagsep );
-	}
-
-	s->count--;
-
-	up(&open_sem);
-	wake_up(&open_wait);
-
-	file->private_data = NULL;
-	return 0;
-}
-
-static struct file_operations usb_midi_fops = {
-	.owner =	THIS_MODULE,
-	.llseek =	usb_midi_llseek,
-	.read =		usb_midi_read,
-	.write =	usb_midi_write,
-	.poll =		usb_midi_poll,
-	.open =		usb_midi_open,
-	.release =	usb_midi_release,
-};
-
-/* ------------------------------------------------------------------------- */
-
-/** Returns filled midi_in_endpoint structure or null on failure.
- *
- * Parameters:
- *	d        - a usb_device
- *	endPoint - An usb endpoint in the range 0 to 15.
- * Called by allocUsbMidiDev();
- *
- **/
-
-static struct midi_in_endpoint *alloc_midi_in_endpoint( struct usb_device *d, int endPoint )
-{
-	struct midi_in_endpoint *ep;
-	int bufSize;
-	int pipe;
-
-	endPoint &= 0x0f; /* Silently force endPoint to lie in range 0 to 15. */
-
-	pipe =  usb_rcvbulkpipe( d, endPoint );
-	bufSize = usb_maxpacket( d, pipe, 0 );
-	/* usb_pipein() = ! usb_pipeout() = true for an in Endpoint */
-
-	ep = (struct midi_in_endpoint *)kmalloc(sizeof(struct midi_in_endpoint), GFP_KERNEL);
-	if ( !ep ) {
-		printk(KERN_ERR "usbmidi: no memory for midi in-endpoint\n");
-		return NULL;
-	}
-	memset( ep, 0, sizeof(struct midi_in_endpoint) );
-//      this sets cables[] and readers to 0, too.
-//      for (i=0; i<16; i++) ep->cables[i] = 0; // discard cable
-//      ep->readers = 0;
-
-	ep->endpoint = endPoint;
-
-	ep->recvBuf = (unsigned char *)kmalloc(sizeof(unsigned char)*(bufSize), GFP_KERNEL);
-	if ( !ep->recvBuf ) {
-		printk(KERN_ERR "usbmidi: no memory for midi in-endpoint buffer\n");
-		kfree(ep);
-		return NULL;
-	}
-
-	ep->urb = usb_alloc_urb(0, GFP_KERNEL); /* no ISO */
-	if ( !ep->urb ) {
-		printk(KERN_ERR "usbmidi: no memory for midi in-endpoint urb\n");
-		kfree(ep->recvBuf);
-		kfree(ep);
-		return NULL;
-	}
-	usb_fill_bulk_urb( ep->urb, d, 
-		       usb_rcvbulkpipe(d, endPoint),
-		       (unsigned char *)ep->recvBuf, bufSize,
-		       usb_bulk_read, ep );
-
-	/* ep->bufRdPtr     = 0; */
-	/* ep->bufWrPtr     = 0; */
-	/* ep->bufRemains   = 0; */
-	/* ep->urbSubmitted = 0; */
-	ep->recvBufSize  = bufSize;
-
-	init_waitqueue_head(&ep->wait);
-
-	return ep;
-}
-
-static int remove_midi_in_endpoint( struct midi_in_endpoint *min )
-{
-	usb_kill_urb( min->urb );
-	usb_free_urb( min->urb );
-	kfree( min->recvBuf );
-	kfree( min );
-
-	return 0;
-}
-
-/** Returns filled midi_out_endpoint structure or null on failure.
- *
- * Parameters:
- *	d        - a usb_device
- *	endPoint - An usb endpoint in the range 0 to 15.
- * Called by allocUsbMidiDev();
- *
- **/
-static struct midi_out_endpoint *alloc_midi_out_endpoint( struct usb_device *d, int endPoint )
-{
-	struct midi_out_endpoint *ep = NULL;
-	int pipe;
-	int bufSize;
-
-	endPoint &= 0x0f;
-	pipe =  usb_sndbulkpipe( d, endPoint );
-	bufSize = usb_maxpacket( d, pipe, 1 );
-
-	ep = (struct midi_out_endpoint *)kmalloc(sizeof(struct midi_out_endpoint), GFP_KERNEL);
-	if ( !ep ) {
-		printk(KERN_ERR "usbmidi: no memory for midi out-endpoint\n");
-		return NULL;
-	}
-	memset( ep, 0, sizeof(struct midi_out_endpoint) );
-
-	ep->endpoint = endPoint;
-	ep->buf = (unsigned char *)kmalloc(sizeof(unsigned char)*bufSize, GFP_KERNEL);
-	if ( !ep->buf ) {
-		printk(KERN_ERR "usbmidi: no memory for midi out-endpoint buffer\n");
-		kfree(ep);
-		return NULL;
-	}
-
-	ep->urb = usb_alloc_urb(0, GFP_KERNEL); /* no ISO */
-	if ( !ep->urb ) {
-		printk(KERN_ERR "usbmidi: no memory for midi out-endpoint urb\n");
-		kfree(ep->buf);
-		kfree(ep);
-		return NULL;
-	}
-
-	ep->bufSize       = bufSize;
-	/* ep->bufWrPtr      = 0; */
-
-	init_waitqueue_head(&ep->wait);
-
-	return ep;
-}
-
-
-static int remove_midi_out_endpoint( struct midi_out_endpoint *mout )
-{
-	usb_kill_urb( mout->urb );
-	usb_free_urb( mout->urb );
-	kfree( mout->buf );
-	kfree( mout );
-
-	return 0;
-}
-
-
-/** Returns a filled usb_mididev structure, registered as a Linux MIDI device.
- *
- * Returns null if memory is not available or the device cannot be registered.
- * Called by allocUsbMidiDev();
- *
- **/
-static struct usb_mididev *allocMidiDev(
-	struct usb_midi_state *s,
-	struct midi_in_endpoint *min,
-	struct midi_out_endpoint *mout,
-	int inCableId,
-	int outCableId )
-{
-	struct usb_mididev *m;
-
-	m = (struct usb_mididev *)kmalloc(sizeof(struct usb_mididev), GFP_KERNEL);
-	if (!m) {
-		printk(KERN_ERR "usbmidi: no memory for midi device\n");
-		return NULL;
-	}
-
-	memset(m, 0, sizeof(struct usb_mididev));
-
-	if ((m->dev_midi = register_sound_midi(&usb_midi_fops, -1)) < 0) {
-		printk(KERN_ERR "usbmidi: cannot register midi device\n");
-		kfree(m);
-		return NULL;
-	}
-
-	m->midi               = s;
-	/* m->open_mode          = 0; */
-
-	if ( min ) {
-		m->min.ep             = min;
-		m->min.ep->usbdev     = s->usbdev;
-		m->min.cableId        = inCableId;
-	}
-	/* m->min.bufPtr         = 0; */
-	/* m->min.bufRemains     = 0; */
-
-	if ( mout ) {
-		m->mout.ep            = mout;
-		m->mout.ep->usbdev    = s->usbdev;
-		m->mout.cableId       = outCableId;
-	}
-	/* m->mout.bufPtr        = 0; */
-	/* m->mout.bufRemains    = 0; */
-	/* m->mout.isInExclusive = 0; */
-	/* m->mout.lastEvent     = 0; */
-
-	m->singlebyte         = singlebyte;
-
-	return m;
-}
-
-
-static void release_midi_device( struct usb_midi_state *s )
-{
-	struct usb_mididev *m;
-	struct midi_in_endpoint *min;
-	struct midi_out_endpoint *mout;
-
-	if ( s->count > 0 ) {
-		up(&open_sem);
-		return;
-	}
-	up( &open_sem );
-	wake_up( &open_wait );
-
-	while(!list_empty(&s->inEndpointList)) {
-		min = list_entry(s->inEndpointList.next, struct midi_in_endpoint, list);
-		list_del(&min->list);
-		remove_midi_in_endpoint(min);
-	}
-
-	while(!list_empty(&s->outEndpointList)) {
-		mout = list_entry(s->outEndpointList.next, struct midi_out_endpoint, list);
-		list_del(&mout->list);
-		remove_midi_out_endpoint(mout);
-	}
-
-	while(!list_empty(&s->midiDevList)) {
-		m = list_entry(s->midiDevList.next, struct usb_mididev, list);
-		list_del(&m->list);
-		kfree(m);
-	}
-
-	kfree(s);
-
-	return;
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-/** Utility routine to find a descriptor in a dump of many descriptors.
- * Returns start of descriptor or NULL if not found. 
- * descStart pointer to list of interfaces.
- * descLength length (in bytes) of dump
- * after (ignored if NULL) this routine returns only descriptors after "after"
- * dtype (mandatory) The descriptor type.
- * iface (ignored if -1) returns descriptor at/following given interface
- * altSetting (ignored if -1) returns descriptor at/following given altSetting
- *
- *
- *  Called by parseDescriptor(), find_csinterface_descriptor();
- *
- */
-static void *find_descriptor( void *descStart, unsigned int descLength, void *after, unsigned char dtype, int iface, int altSetting )
-{
-	unsigned char *p, *end, *next;
-	int interfaceNumber = -1, altSet = -1;
-
-	p = descStart;
-	end = p + descLength;
-	for( ; p < end; ) {
-		if ( p[0] < 2 )
-			return NULL;
-		next = p + p[0];
-		if ( next > end )
-			return NULL;
-		if ( p[1] == USB_DT_INTERFACE ) {
-			if ( p[0] < USB_DT_INTERFACE_SIZE )
-				return NULL;
-			interfaceNumber = p[2];
-			altSet = p[3];
-		}
-		if ( p[1] == dtype &&
-		     ( !after || ( p > (unsigned char *)after) ) &&
-		     ( ( iface == -1) || (iface == interfaceNumber) ) &&
-		     ( (altSetting == -1) || (altSetting == altSet) )) {
-			return p;
-		}
-		p = next;
-	}
-	return NULL;
-}
-
-/** Utility to find a class-specific interface descriptor.
- *  dsubtype is a descriptor subtype
- *  Called by parseDescriptor();
- **/
-static void *find_csinterface_descriptor(void *descStart, unsigned int descLength, void *after, u8 dsubtype, int iface, int altSetting)
-{
-	unsigned char *p;
-  
-	p = find_descriptor( descStart, descLength, after, USB_DT_CS_INTERFACE, iface, altSetting );
-	while ( p ) {
-		if ( p[0] >= 3 && p[2] == dsubtype )
-			return p;
-		p = find_descriptor( descStart, descLength, p, USB_DT_CS_INTERFACE, 
-				     iface, altSetting );
-	}
-	return NULL;
-}
-
-
-/** The magic of making a new usb_midi_device from config happens here.
- *
- * The caller is responsible for free-ing this return value (if not NULL).
- *
- **/
-static struct usb_midi_device *parse_descriptor( struct usb_device *d, unsigned char *buffer, int bufSize, unsigned int ifnum , unsigned int altSetting, int quirks)
-{
-	struct usb_midi_device *u;
-	unsigned char *p1;
-	unsigned char *p2;
-	unsigned char *next;
-	int iep, oep;
-	int length;
-	unsigned long longBits;
-	int pins, nbytes, offset, shift, jack;
-#ifdef HAVE_JACK_STRINGS
-	/** Jacks can have associated names.  **/
-	unsigned char jack2string[256];
-#endif
-
-	u = NULL;
-	/* find audiocontrol interface */
-	p1 = find_csinterface_descriptor( buffer, bufSize, NULL,
-					  MS_HEADER, ifnum, altSetting);
-
-	if ( !p1 ) {
-		goto error_end;
-	}
-
-	if ( p1[0] < MS_HEADER_LENGTH ) {
-		goto error_end;
-	}
-
-	/* Assume success. Since the device corresponds to USB-MIDI spec, we assume
-	   that the rest of the USB 2.0 spec is obeyed. */
-
-	u = (struct usb_midi_device *)kmalloc( sizeof(struct usb_midi_device), GFP_KERNEL );
-	if ( !u ) {
-		return NULL;
-	}
-	u->deviceName = NULL;
-	u->idVendor = le16_to_cpu(d->descriptor.idVendor);
-	u->idProduct = le16_to_cpu(d->descriptor.idProduct);
-	u->interface = ifnum;
-	u->altSetting = altSetting;
-	u->in[0].endpoint = -1;
-	u->in[0].cableId = -1;
-	u->out[0].endpoint = -1;
-	u->out[0].cableId = -1;
-
-
-	printk(KERN_INFO "usb-midi: Found MIDIStreaming device corresponding to Release %d.%02d of spec.\n",
-	       (p1[4] >> 4) * 10 + (p1[4] & 0x0f ),
-	       (p1[3] >> 4) * 10 + (p1[3] & 0x0f )
-		);
-
-	length = p1[5] | (p1[6] << 8);
-
-#ifdef HAVE_JACK_STRINGS
-	memset(jack2string, 0, sizeof(unsigned char) * 256);
-#endif
-
-	length -= p1[0];
-	for (p2 = p1 + p1[0]; length > 0; p2 = next) {
-		next = p2 + p2[0];
-		length -= p2[0];
-
-		if (p2[0] < 2 )
-			break;
-		if (p2[1] != USB_DT_CS_INTERFACE)
-			break;
-		if (p2[2] == MIDI_IN_JACK && p2[0] >= 6 ) {
-			jack = p2[4];
-#ifdef HAVE_JACK_STRINGS
-			jack2string[jack] = p2[5];
-#endif
-			printk(KERN_INFO "usb-midi: Found IN Jack 0x%02x %s\n",
-			       jack, (p2[3] == EMBEDDED_JACK)?"EMBEDDED":"EXTERNAL" );
-		} else if ( p2[2] == MIDI_OUT_JACK && p2[0] >= 6) {
-			pins = p2[5];
-			if ( p2[0] < (6 + 2 * pins) )
-				continue;
-			jack = p2[4];
-#ifdef HAVE_JACK_STRINGS
-			jack2string[jack] = p2[5 + 2 * pins];
-#endif
-			printk(KERN_INFO "usb-midi: Found OUT Jack 0x%02x %s, %d pins\n",
-			       jack, (p2[3] == EMBEDDED_JACK)?"EMBEDDED":"EXTERNAL", pins );
-		} else if ( p2[2] == ELEMENT_DESCRIPTOR  && p2[0]  >= 10) {
-			pins = p2[4];
-			if ( p2[0] < (9 + 2 * pins ) )
-				continue;
-			nbytes = p2[8 + 2 * pins ];
-			if ( p2[0] < (10 + 2 * pins + nbytes) )
-				continue;
-			longBits = 0L;
-			for ( offset = 0, shift = 0; offset < nbytes && offset < 8; offset ++, shift += 8) {
-				longBits |= ((long)(p2[9 + 2 * pins + offset])) << shift;
-			}
-			jack = p2[3];
-#ifdef HAVE_JACK_STRINGS
-			jack2string[jack] = p2[9 + 2 * pins + nbytes];
-#endif
-			printk(KERN_INFO "usb-midi: Found ELEMENT 0x%02x, %d/%d pins in/out, bits: 0x%016lx\n",
-			       jack, pins, (int)(p2[5 + 2 * pins]), (long)longBits );
-		} else {
-		}
-	}
-
-	iep=0;
-	oep=0;
-
-	if (quirks==0) {
-		/* MIDISTREAM */
-		p2 = NULL;
-		for (p1 = find_descriptor(buffer, bufSize, NULL, USB_DT_ENDPOINT,
-					  ifnum, altSetting ); p1; p1 = next ) {
-			next = find_descriptor(buffer, bufSize, p1, USB_DT_ENDPOINT,
-					       ifnum, altSetting ); 
-			p2 = find_descriptor(buffer, bufSize, p1, USB_DT_CS_ENDPOINT,
-					     ifnum, altSetting ); 
-
-			if ( p2 && next && ( p2 > next ) )
-				p2 = NULL;
-
-			if ( p1[0] < 9 || !p2 || p2[0] < 4 )
-				continue;
-
-			if ( (p1[2] & 0x80) == 0x80 ) {
-				if ( iep < 15 ) {
-					pins = p2[3]; /* not pins -- actually "cables" */
-					if ( pins > 16 )
-						pins = 16;
-					u->in[iep].endpoint = p1[2];
-					u->in[iep].cableId = ( 1 << pins ) - 1;
-					if ( u->in[iep].cableId )
-						iep ++;
-					if ( iep < 15 ) {
-						u->in[iep].endpoint = -1;
-						u->in[iep].cableId = -1;
-					}
-				}
-			} else {
-				if ( oep < 15 ) {
-					pins = p2[3]; /* not pins -- actually "cables" */
-					if ( pins > 16 )
-						pins = 16;
-					u->out[oep].endpoint = p1[2];
-					u->out[oep].cableId = ( 1 << pins ) - 1;
-					if ( u->out[oep].cableId )
-						oep ++;
-					if ( oep < 15 ) {
-						u->out[oep].endpoint = -1;
-						u->out[oep].cableId = -1;
-					}
-				}
-			}
-	
-		}
-	} else if (quirks==1) {
-		/* YAMAHA quirks */
-		for (p1 = find_descriptor(buffer, bufSize, NULL, USB_DT_ENDPOINT,
-					  ifnum, altSetting ); p1; p1 = next ) {
-			next = find_descriptor(buffer, bufSize, p1, USB_DT_ENDPOINT,
-					       ifnum, altSetting ); 
-	
-			if ( p1[0] < 7 )
-				continue;
-
-			if ( (p1[2] & 0x80) == 0x80 ) {
-				if ( iep < 15 ) {
-					pins = iep+1;
-					if ( pins > 16 )
-						pins = 16;
-					u->in[iep].endpoint = p1[2];
-					u->in[iep].cableId = ( 1 << pins ) - 1;
-					if ( u->in[iep].cableId )
-						iep ++;
-					if ( iep < 15 ) {
-						u->in[iep].endpoint = -1;
-						u->in[iep].cableId = -1;
-					}
-				}
-			} else {
-				if ( oep < 15 ) {
-					pins = oep+1;
-					u->out[oep].endpoint = p1[2];
-					u->out[oep].cableId = ( 1 << pins ) - 1;
-					if ( u->out[oep].cableId )
-						oep ++;
-					if ( oep < 15 ) {
-						u->out[oep].endpoint = -1;
-						u->out[oep].cableId = -1;
-					}
-				}
-			}
-	
-		}
-	}
-
-	if ( !iep && ! oep ) {
-		goto error_end;
-	}
-
-	return u;
-
-error_end:
-	kfree(u);
-	return NULL;
-}
-
-/* ------------------------------------------------------------------------- */
-
-/** Returns number between 0 and 16.
- *
- **/
-static int on_bits( unsigned short v )
-{
-	int i;
-	int ret=0;
-
-	for ( i=0 ; i<16 ; i++ ) {
-		if ( v & (1<<i) )
-			ret++;
-	}
-
-	return ret;
-}
-
-
-/** USB-device will be interrogated for altSetting.
- *
- * Returns negative on error.
- * Called by allocUsbMidiDev();
- *
- **/
-
-static int get_alt_setting( struct usb_device *d, int ifnum )
-{
-	int alts, alt=0;
-	struct usb_interface *iface;
-	struct usb_host_interface *interface;
-	struct usb_endpoint_descriptor *ep;
-	int epin, epout;
-	int i;
-
-	iface = usb_ifnum_to_if( d, ifnum );
-	alts = iface->num_altsetting;
-
-	for ( alt=0 ; alt<alts ; alt++ ) {
-		interface = &iface->altsetting[alt];
-		epin = -1;
-		epout = -1;
-
-		for ( i=0 ; i<interface->desc.bNumEndpoints ; i++ ) {
-			ep = &interface->endpoint[i].desc;
-			if ( (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK ) {
-				continue;
-			}
-			if ( (ep->bEndpointAddress & USB_DIR_IN) && epin < 0 ) {
-				epin = i;
-			} else if ( epout < 0 ) {
-				epout = i;
-			}
-			if ( epin >= 0 && epout >= 0 ) {
-				return interface->desc.bAlternateSetting;
-			}
-		}
-	}
-
-	return -ENODEV;
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-
-/** Returns 0 if successful in allocating and registering internal structures.
- * Returns negative on failure.
- * Calls allocMidiDev which additionally registers /dev/midiXX devices.
- * Writes messages on success to indicate which /dev/midiXX is which physical
- * endpoint.
- *
- **/
-static int alloc_usb_midi_device( struct usb_device *d, struct usb_midi_state *s, struct usb_midi_device *u )
-{
-	struct usb_mididev **mdevs=NULL;
-	struct midi_in_endpoint *mins[15], *min;
-	struct midi_out_endpoint *mouts[15], *mout;
-	int inDevs=0, outDevs=0;
-	int inEndpoints=0, outEndpoints=0;
-	int inEndpoint, outEndpoint;
-	int inCableId, outCableId;
-	int i;
-	int devices = 0;
-	int alt = 0;
-
-	/* Obtain altSetting or die.. */
-	alt = u->altSetting;
-	if ( alt < 0 ) {
-		alt = get_alt_setting( d, u->interface );
-	}
-	if ( alt < 0 )
-		return -ENXIO;
-
-	/* Configure interface */
-	if ( usb_set_interface( d, u->interface, alt ) < 0 ) {
-		return -ENXIO;
-	}
-
-	for ( i = 0 ; i < 15 ; i++ ) {
-		mins[i] = NULL;
-		mouts[i] = NULL;
-	}
-
-	/* Begin Allocation */
-	while( inEndpoints < 15
-	       && inDevs < maxdevices
-	       && u->in[inEndpoints].cableId >= 0 ) {
-		inDevs += on_bits((unsigned short)u->in[inEndpoints].cableId);
-		mins[inEndpoints] = alloc_midi_in_endpoint( d, u->in[inEndpoints].endpoint );
-		if ( mins[inEndpoints] == NULL )
-			goto error_end;
-		inEndpoints++;
-	}
-
-	while( outEndpoints < 15
-	       && outDevs < maxdevices
-	       && u->out[outEndpoints].cableId >= 0 ) {
-		outDevs += on_bits((unsigned short)u->out[outEndpoints].cableId);
-		mouts[outEndpoints] = alloc_midi_out_endpoint( d, u->out[outEndpoints].endpoint );
-		if ( mouts[outEndpoints] == NULL )
-			goto error_end;
-		outEndpoints++;
-	}
-
-	devices = inDevs > outDevs ? inDevs : outDevs;
-	devices = maxdevices > devices ? devices : maxdevices;
-
-	/* obtain space for device name (iProduct) if not known. */
-	if ( ! u->deviceName ) {
-		mdevs = (struct usb_mididev **)
-			kmalloc(sizeof(struct usb_mididevs *)*devices
-				+ sizeof(char) * 256, GFP_KERNEL);
-	} else {
-		mdevs = (struct usb_mididev **)
-			kmalloc(sizeof(struct usb_mididevs *)*devices, GFP_KERNEL);
-	}
-
-	if ( !mdevs ) {
-		/* devices = 0; */
-		/* mdevs = NULL; */
-		goto error_end;
-	}
-	for ( i=0 ; i<devices ; i++ ) {
-		mdevs[i] = NULL;
-	}
-
-	/* obtain device name (iProduct) if not known. */
-	if ( ! u->deviceName ) {
-		u->deviceName = (char *) (mdevs + devices);
-		if ( ! d->have_langid && d->descriptor.iProduct) {
-			alt = usb_get_string(d, 0, 0, u->deviceName, 250);
-			if (alt < 0) {
-				printk(KERN_INFO "error getting string descriptor 0 (error=%d)\n", alt);
-			} else if (u->deviceName[0] < 4) {
-				printk(KERN_INFO "string descriptor 0 too short (length = %d)\n", alt);
-			} else {
-				printk(KERN_INFO "string descriptor 0 found (length = %d)\n", alt);
-				for(; alt >= 4; alt -= 2) {
-					i = u->deviceName[alt-2] | (u->deviceName[alt-1]<< 8);
-					printk(KERN_INFO "usb-midi: langid(%d) 0x%04x\n",
-					       (alt-4) >> 1, i);
-					if ( ( ( i ^ ulangid ) & 0xff ) == 0 ) {
-						d->have_langid = 1;
-						d->string_langid = i;
-						printk(KERN_INFO "usb-midi: langid(match) 0x%04x\n", i);
-						if ( i == ulangid )
-							break;
-					}
-				}
-			}
-		}
-		u->deviceName[0] = (char) 0;
-		if (d->descriptor.iProduct) {
-			printk(KERN_INFO "usb-midi: fetchString(%d)\n", d->descriptor.iProduct);
-			alt = usb_string(d, d->descriptor.iProduct, u->deviceName, 255);
-			if( alt < 0 ) {
-				u->deviceName[0] = (char) 0;
-			}
-			printk(KERN_INFO "usb-midi: fetchString = %d\n", alt);
-		} 
-		/* Failsafe */
-		if ( !u->deviceName[0] ) {
-			if (le16_to_cpu(d->descriptor.idVendor) == USB_VENDOR_ID_ROLAND ) {
-				strcpy(u->deviceName, "Unknown Roland");
-			} else if (le16_to_cpu(d->descriptor.idVendor) == USB_VENDOR_ID_STEINBERG  ) {
-				strcpy(u->deviceName, "Unknown Steinberg");
-			} else if (le16_to_cpu(d->descriptor.idVendor) == USB_VENDOR_ID_YAMAHA ) {
-				strcpy(u->deviceName, "Unknown Yamaha");
-			} else {
-				strcpy(u->deviceName, "Unknown");
-			}
-		}
-	}
-
-	inEndpoint  = 0; inCableId  = -1;
-	outEndpoint = 0; outCableId = -1;
-
-	for ( i=0 ; i<devices ; i++ ) {
-		for ( inCableId ++ ;
-		      inEndpoint <15
-			      && mins[inEndpoint] 
-			      && !(u->in[inEndpoint].cableId & (1<<inCableId)) ;
-		      inCableId++ ) {
-			if ( inCableId >= 16 ) {
-				inEndpoint  ++;
-				inCableId  = 0;
-			}
-		}
-		min  = mins[inEndpoint];
-		for ( outCableId ++ ;
-		      outEndpoint <15
-			      && mouts[outEndpoint] 
-			      && !(u->out[outEndpoint].cableId & (1<<outCableId)) ;
-		      outCableId++ ) {
-			if ( outCableId >= 16 ) {
-				outEndpoint  ++;
-				outCableId  = 0;
-			}
-		}
-		mout = mouts[outEndpoint];
-
-		mdevs[i] = allocMidiDev( s, min, mout, inCableId, outCableId );
-		if ( mdevs[i] == NULL )
-			goto error_end;
-
-	}
-
-	/* Success! */
-	for ( i=0 ; i<devices ; i++ ) {
-		list_add_tail( &mdevs[i]->list, &s->midiDevList );
-	}
-	for ( i=0 ; i<inEndpoints ; i++ ) {
-		list_add_tail( &mins[i]->list, &s->inEndpointList );
-	}
-	for ( i=0 ; i<outEndpoints ; i++ ) {
-		list_add_tail( &mouts[i]->list, &s->outEndpointList );
-	}
-
-	printk(KERN_INFO "usbmidi: found [ %s ] (0x%04x:0x%04x), attached:\n", u->deviceName, u->idVendor, u->idProduct );
-	for ( i=0 ; i<devices ; i++ ) {
-		int dm = (mdevs[i]->dev_midi-2)>>4;
-		if ( mdevs[i]->mout.ep != NULL && mdevs[i]->min.ep != NULL ) {
-			printk(KERN_INFO "usbmidi: /dev/midi%02d: in (ep:%02x cid:%2d bufsiz:%2d) out (ep:%02x cid:%2d bufsiz:%2d)\n", 
-			       dm,
-			       mdevs[i]->min.ep->endpoint|USB_DIR_IN, mdevs[i]->min.cableId, mdevs[i]->min.ep->recvBufSize,
-			       mdevs[i]->mout.ep->endpoint, mdevs[i]->mout.cableId, mdevs[i]->mout.ep->bufSize);
-		} else if ( mdevs[i]->min.ep != NULL ) {
-			printk(KERN_INFO "usbmidi: /dev/midi%02d: in (ep:%02x cid:%2d bufsiz:%02d)\n", 
-			       dm,
-			       mdevs[i]->min.ep->endpoint|USB_DIR_IN, mdevs[i]->min.cableId, mdevs[i]->min.ep->recvBufSize);
-		} else if ( mdevs[i]->mout.ep != NULL ) {
-			printk(KERN_INFO "usbmidi: /dev/midi%02d: out (ep:%02x cid:%2d bufsiz:%02d)\n", 
-			       dm,
-			       mdevs[i]->mout.ep->endpoint, mdevs[i]->mout.cableId, mdevs[i]->mout.ep->bufSize);
-		}
-	}
-
-	kfree(mdevs);
-	return 0;
-
- error_end:
-	if ( mdevs != NULL ) {
-		for ( i=0 ; i<devices ; i++ ) {
-			if ( mdevs[i] != NULL ) {
-				unregister_sound_midi( mdevs[i]->dev_midi );
-				kfree(mdevs[i]);
-			}
-		}
-		kfree(mdevs);
-	}
-
-	for ( i=0 ; i<15 ; i++ ) {
-		if ( mins[i] != NULL ) {
-			remove_midi_in_endpoint( mins[i] );
-		}
-		if ( mouts[i] != NULL ) {
-			remove_midi_out_endpoint( mouts[i] );
-		}
-	}
-
-	return -ENOMEM;
-}
-
-/* ------------------------------------------------------------------------- */
-
-/** Attempt to scan YAMAHA's device descriptor and detect correct values of
- *  them.
- *  Return 0 on succes, negative on failure.
- *  Called by usb_midi_probe();
- **/
-
-static int detect_yamaha_device( struct usb_device *d,
-		struct usb_interface *iface, unsigned int ifnum,
-		struct usb_midi_state *s)
-{
-	struct usb_host_interface *interface;
-	struct usb_midi_device *u;
-	unsigned char *buffer;
-	int bufSize;
-	int i;
-	int alts=-1;
-	int ret;
-
-	if (le16_to_cpu(d->descriptor.idVendor) != USB_VENDOR_ID_YAMAHA) {
-		return -EINVAL;
-	}
-
-	for ( i=0 ; i < iface->num_altsetting; i++ ) {
-		interface = iface->altsetting + i;
-
-		if ( interface->desc.bInterfaceClass != 255 ||
-		     interface->desc.bInterfaceSubClass != 0 )
-			continue;
-		alts = interface->desc.bAlternateSetting;
-	}
-	if ( alts == -1 ) {
-		return -EINVAL;
-	}
-
-	printk(KERN_INFO "usb-midi: Found YAMAHA USB-MIDI device on dev %04x:%04x, iface %d\n",
-	       le16_to_cpu(d->descriptor.idVendor),
-	       le16_to_cpu(d->descriptor.idProduct), ifnum);
-
-	i = d->actconfig - d->config;
-	buffer = d->rawdescriptors[i];
-	bufSize = le16_to_cpu(d->actconfig->desc.wTotalLength);
-
-	u = parse_descriptor( d, buffer, bufSize, ifnum, alts, 1);
-	if ( u == NULL ) {
-		return -EINVAL;
-	}
-
-	ret = alloc_usb_midi_device( d, s, u );
-
-	kfree(u);
-
-	return ret;
-}
-
-
-/** Scan table of known devices which are only partially compliant with 
- * the MIDIStreaming specification.
- * Called by usb_midi_probe();
- *
- **/
-
-static int detect_vendor_specific_device( struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s )
-{
-	struct usb_midi_device *u;
-	int i;
-	int ret = -ENXIO;
-
-	for ( i=0; i<VENDOR_SPECIFIC_USB_MIDI_DEVICES ; i++ ) {
-		u=&(usb_midi_devices[i]);
-    
-		if ( le16_to_cpu(d->descriptor.idVendor) != u->idVendor ||
-		     le16_to_cpu(d->descriptor.idProduct) != u->idProduct ||
-		     ifnum != u->interface )
-			continue;
-
-		ret = alloc_usb_midi_device( d, s, u );
-		break;
-	}
-
-	return ret;
-}
-
-
-/** Attempt to match any config of an interface to a MIDISTREAMING interface.
- *  Returns 0 on success, negative on failure.
- * Called by usb_midi_probe();
- **/
-static int detect_midi_subclass(struct usb_device *d,
-		struct usb_interface *iface, unsigned int ifnum,
-		struct usb_midi_state *s)
-{
-	struct usb_host_interface *interface;
-	struct usb_midi_device *u;
-	unsigned char *buffer;
-	int bufSize;
-	int i;
-	int alts=-1;
-	int ret;
-
-	for ( i=0 ; i < iface->num_altsetting; i++ ) {
-		interface = iface->altsetting + i;
-
-		if ( interface->desc.bInterfaceClass != USB_CLASS_AUDIO ||
-		     interface->desc.bInterfaceSubClass != USB_SUBCLASS_MIDISTREAMING )
-			continue;
-		alts = interface->desc.bAlternateSetting;
-	}
-	if ( alts == -1 ) {
-		return -EINVAL;
-	}
-
-	printk(KERN_INFO "usb-midi: Found MIDISTREAMING on dev %04x:%04x, iface %d\n",
-	       le16_to_cpu(d->descriptor.idVendor), 
-	       le16_to_cpu(d->descriptor.idProduct), ifnum);
-
-
-	/* From USB Spec v2.0, Section 9.5.
-	   If the class or vendor specific descriptors use the same format
-	   as standard descriptors (e.g., start with a length byte and
-	   followed by a type byte), they must be returned interleaved with
-	   standard descriptors in the configuration information returned by
-	   a GetDescriptor(Configuration) request. In this case, the class
-	   or vendor-specific descriptors must follow a related standard
-	   descriptor they modify or extend.
-	*/
-
-	i = d->actconfig - d->config;
-	buffer = d->rawdescriptors[i];
-	bufSize = le16_to_cpu(d->actconfig->desc.wTotalLength);
-
-	u = parse_descriptor( d, buffer, bufSize, ifnum, alts, 0);
-	if ( u == NULL ) {
-		return -EINVAL;
-	}
-
-	ret = alloc_usb_midi_device( d, s, u );
-
-	kfree(u);
-
-	return ret;
-}
-
-
-/** When user has requested a specific device, match it exactly.
- *
- * Uses uvendor, uproduct, uinterface, ualt, umin, umout and ucable.
- * Called by usb_midi_probe();
- *
- **/
-static int detect_by_hand(struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s)
-{
-	struct usb_midi_device u;
-
-	if ( le16_to_cpu(d->descriptor.idVendor) != uvendor ||
-	     le16_to_cpu(d->descriptor.idProduct) != uproduct ||
-	     ifnum != uinterface ) {
-		return -EINVAL;
-	}
-
-	if ( ualt < 0 )
-		ualt = -1;
-
-	if ( umin   < 0 || umin   > 15 )
-		umin   = 0x01 | USB_DIR_IN;
-	if ( umout  < 0 || umout  > 15 )
-		umout  = 0x01;
-	if ( ucable < 0 || ucable > 15 )
-		ucable = 0;
-
-	u.deviceName = NULL; /* A flag for alloc_usb_midi_device to get device
-				name from device. */
-	u.idVendor   = uvendor;
-	u.idProduct  = uproduct;
-	u.interface  = uinterface;
-	u.altSetting = ualt;
-
-	u.in[0].endpoint    = umin;
-	u.in[0].cableId     = (1<<ucable);
-
-	u.out[0].endpoint   = umout;
-	u.out[0].cableId    = (1<<ucable);
-
-	return alloc_usb_midi_device( d, s, &u );
-}
-
-
-
-/* ------------------------------------------------------------------------- */
-
-static int usb_midi_probe(struct usb_interface *intf, 
-			  const struct usb_device_id *id)
-{
-	struct usb_midi_state *s;
-	struct usb_device *dev = interface_to_usbdev(intf);
-	int ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
-
-	s = (struct usb_midi_state *)kmalloc(sizeof(struct usb_midi_state), GFP_KERNEL);
-	if ( !s )
-		return -ENOMEM;
-
-	memset( s, 0, sizeof(struct usb_midi_state) );
-	INIT_LIST_HEAD(&s->midiDevList);
-	INIT_LIST_HEAD(&s->inEndpointList);
-	INIT_LIST_HEAD(&s->outEndpointList);
-	s->usbdev = dev;
-	s->count  = 0;
-	spin_lock_init(&s->lock);
-
-	if (
-		detect_by_hand( dev, ifnum, s ) &&
-		detect_midi_subclass( dev, intf, ifnum, s ) &&
-		detect_vendor_specific_device( dev, ifnum, s ) &&
-		detect_yamaha_device( dev, intf, ifnum, s) ) {
-		kfree(s);
-		return -EIO;
-	}
-
-	down(&open_sem);
-	list_add_tail(&s->mididev, &mididevs);
-	up(&open_sem);
-
-	usb_set_intfdata (intf, s);
-	return 0;
-}
-
-
-static void usb_midi_disconnect(struct usb_interface *intf)
-{
-	struct usb_midi_state *s = usb_get_intfdata (intf);
-	struct usb_mididev    *m;
-
-	if ( !s )
-		return;
-
-	if ( s == (struct usb_midi_state *)-1 ) {
-		return;
-	}
-	if ( !s->usbdev ) {
-		return;
-	}
-	down(&open_sem);
-	list_del(&s->mididev);
-	INIT_LIST_HEAD(&s->mididev);
-	s->usbdev = NULL;
-	usb_set_intfdata (intf, NULL);
-
-	list_for_each_entry(m, &s->midiDevList, list) {
-		wake_up(&(m->min.ep->wait));
-		wake_up(&(m->mout.ep->wait));
-		if ( m->dev_midi >= 0 ) {
-			unregister_sound_midi(m->dev_midi);
-		}
-		m->dev_midi = -1;
-	}
-	release_midi_device(s);
-	wake_up(&open_wait);
-}
-
-/* we want to look at all devices by hand */
-static struct usb_device_id id_table[] = {
-	{.driver_info = 42},
-	{}
-};
-
-static struct usb_driver usb_midi_driver = {
-	.name =		"midi",
-	.probe =	usb_midi_probe,
-	.disconnect =	usb_midi_disconnect,
-	.id_table =	id_table,
-};
-
-/* ------------------------------------------------------------------------- */
-
-static int __init usb_midi_init(void)
-{
-	return usb_register(&usb_midi_driver);
-}
-
-static void __exit usb_midi_exit(void)
-{
-	usb_deregister(&usb_midi_driver);
-}
-
-module_init(usb_midi_init) ;
-module_exit(usb_midi_exit) ;
-
-#ifdef HAVE_ALSA_SUPPORT
-#define SNDRV_MAIN_OBJECT_FILE
-#include "../../include/driver.h"
-#include "../../include/control.h"
-#include "../../include/info.h"
-#include "../../include/cs46xx.h"
-
-/* ------------------------------------------------------------------------- */
-
-static int snd_usbmidi_input_close(snd_rawmidi_substream_t * substream)
-{
-	return 0;
-}
-
-static int snd_usbmidi_input_open(snd_rawmidi_substream_t * substream )
-{
-	return 0;
-}
-
-static void snd_usbmidi_input_trigger(snd_rawmidi_substream_t * substream, int up)
-{
-	return 0;
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-static int snd_usbmidi_output_close(snd_rawmidi_substream_t * substream)
-{
-	return 0;
-}
-
-static int snd_usbmidi_output_open(snd_rawmidi_substream_t * substream)
-{
-	return 0;
-}
-
-static void snd_usb_midi_output_trigger(snd_rawmidi_substream_t * substream,
-					int up)
-{
-	return 0;
-}
-
-/* ------------------------------------------------------------------------- */
-
-static snd_rawmidi_ops_t snd_usbmidi_output =
-{
-        .open =         snd_usbmidi_output_open,
-        .close =        snd_usbmidi_output_close,
-        .trigger =      snd_usbmidi_output_trigger,
-};
-static snd_rawmidi_ops_t snd_usbmidi_input =
-{
-        .open =         snd_usbmidi_input_open,
-        .close =        snd_usbmidi_input_close,
-        .trigger =      snd_usbmidi_input_trigger,
-};
-
-int snd_usbmidi_midi(cs46xx_t *chip, int device, snd_rawmidi_t **rrawmidi)
-{
-	snd_rawmidi_t *rmidi;
-	int err;
-
-	if (rrawmidi)
-		*rrawmidi = NULL;
-	if ((err = snd_rawmidi_new(chip->card, "USB-MIDI", device, 1, 1, &rmidi)) < 0)
-		return err;
-	strcpy(rmidi->name, "USB-MIDI");
-
-	snd_rawmidi_set_ops( rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_usbmidi_output );
-	snd_rawmidi_set_ops( rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_usbmidi_input );
-
-	rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
-
-	rmidi->private_data = chip;
-	chip->rmidi = rmidi;
-	if (rrawmidi)
-		*rrawmidi = NULL;
-
-	return 0;
-}
-
-int snd_usbmidi_create( snd_card_t * card,
-			struct pci_dev * pci,
-			usbmidi_t ** rchip )
-{
-	usbmidi_t *chip;
-	int err, idx;
-	snd_region_t *region;
-	static snd_device_opt_t ops = {
-		.dev_free = snd_usbmidi_dev_free,
-	};
-
-	*rchip = NULL;
-	chip = snd_magic_kcalloc( usbmidi_t, 0, GFP_KERNEL );
-	if ( chip == NULL )
-		return -ENOMEM;
-}
-
-EXPORT_SYMBOL(snd_usbmidi_create);
-EXPORT_SYMBOL(snd_usbmidi_midi);
-#endif /* HAVE_ALSA_SUPPORT */
-
diff --git a/drivers/usb/class/usb-midi.h b/drivers/usb/class/usb-midi.h
deleted file mode 100644
index 358cdef..0000000
--- a/drivers/usb/class/usb-midi.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
-  usb-midi.h  --  USB-MIDI driver
-
-  Copyright (C) 2001
-      NAGANO Daisuke <breeze.nagano@nifty.ne.jp>
-
-  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 _USB_MIDI_H_
-#define _USB_MIDI_H_
-
-#ifndef USB_SUBCLASS_MIDISTREAMING
-#define USB_SUBCLASS_MIDISTREAMING	3
-#endif
-
-/* ------------------------------------------------------------------------- */
-/* Roland MIDI Devices */
-
-#define USB_VENDOR_ID_ROLAND		0x0582
-#define USBMIDI_ROLAND_UA100G		0x0000
-#define USBMIDI_ROLAND_MPU64		0x0002
-#define USBMIDI_ROLAND_SC8850		0x0003
-#define USBMIDI_ROLAND_SC8820		0x0007
-#define USBMIDI_ROLAND_UM2		0x0005
-#define USBMIDI_ROLAND_UM1		0x0009
-#define USBMIDI_ROLAND_PC300		0x0008
-
-/* YAMAHA MIDI Devices */
-#define USB_VENDOR_ID_YAMAHA		0x0499
-#define USBMIDI_YAMAHA_MU1000		0x1001
-
-/* Steinberg MIDI Devices */
-#define USB_VENDOR_ID_STEINBERG		0x0763
-#define USBMIDI_STEINBERG_USB2MIDI	0x1001
-
-/* Mark of the Unicorn MIDI Devices */
-#define USB_VENDOR_ID_MOTU		0x07fd
-#define USBMIDI_MOTU_FASTLANE		0x0001
-
-/* ------------------------------------------------------------------------- */
-/* Supported devices */
-
-struct usb_midi_endpoint {
-	int  endpoint;
-	int  cableId; /* if bit-n == 1 then cableId-n is enabled (n: 0 - 15) */
-};
-
-struct usb_midi_device {
-	char  *deviceName;
-
-	u16    idVendor;
-	u16    idProduct;
-	int    interface;
-	int    altSetting; /* -1: auto detect */
-
-	struct usb_midi_endpoint in[15];
-	struct usb_midi_endpoint out[15];
-};
-
-static struct usb_midi_device usb_midi_devices[] = {
-  { /* Roland UM-1 */
-    "Roland UM-1",
-    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM1, 2, -1,
-    { { 0x81, 1 }, {-1, -1} },
-    { { 0x01, 1,}, {-1, -1} },
-  },
-
-  { /* Roland UM-2 */
-    "Roland UM-2" ,
-    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM2, 2, -1,
-    { { 0x81, 3 }, {-1, -1} },
-    { { 0x01, 3,}, {-1, -1} },
-  },
-
-/** Next entry courtesy research by Michael Minn <michael@michaelminn.com> **/
-  { /* Roland UA-100 */
-    "Roland UA-100",
-    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UA100G, 2, -1,
-    { { 0x82, 7 }, {-1, -1} }, /** cables 0,1 and 2 for SYSEX **/
-    { { 0x02, 7 }, {-1, -1} },
-  },
-
-/** Next entry courtesy research by Michael Minn <michael@michaelminn.com> **/
-  { /* Roland SC8850 */
-    "Roland SC8850",
-    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8850, 2, -1,
-    { { 0x81, 0x3f }, {-1, -1} },
-    { { 0x01, 0x3f }, {-1, -1} },
-  },
-
-  { /* Roland SC8820 */
-    "Roland SC8820",
-    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8820, 2, -1,
-    { { 0x81, 0x13 }, {-1, -1} },
-    { { 0x01, 0x13 }, {-1, -1} },
-  },
-
-  { /* Roland SC8820 */
-    "Roland SC8820",
-    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8820, 2, -1,
-    { { 0x81, 17 }, {-1, -1} },
-    { { 0x01, 17 }, {-1, -1} },
-  },
-
-  { /* YAMAHA MU1000 */
-    "YAMAHA MU1000",
-    USB_VENDOR_ID_YAMAHA, USBMIDI_YAMAHA_MU1000, 0, -1, 
-    { { 0x81, 1 }, {-1, -1} },
-    { { 0x01, 15 }, {-1, -1} },
-  },
-  { /* Roland PC-300 */
-    "Roland PC-300",
-    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_PC300, 2, -1, 
-    { { 0x81, 1 }, {-1, -1} },
-    { { 0x01, 1 }, {-1, -1} },
-  },
-  { /* MOTU Fastlane USB */
-    "MOTU Fastlane USB",
-    USB_VENDOR_ID_MOTU, USBMIDI_MOTU_FASTLANE, 1, 0,
-    { { 0x82, 3 }, {-1, -1} },
-    { { 0x02, 3 }, {-1, -1} },
-  }
-};
-
-#define VENDOR_SPECIFIC_USB_MIDI_DEVICES (sizeof(usb_midi_devices)/sizeof(struct usb_midi_device))
-
-/* for Hot-Plugging */
-
-static struct usb_device_id usb_midi_ids [] = {
-	{ .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS),
-	  .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = USB_SUBCLASS_MIDISTREAMING},
-	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM1    ) },
-	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM2    ) },
-	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UA100G ) },
-	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_PC300 ) },
-	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8850 ) },
-	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8820 ) },
-	{ USB_DEVICE( USB_VENDOR_ID_YAMAHA, USBMIDI_YAMAHA_MU1000 ) },
-	{ USB_DEVICE( USB_VENDOR_ID_MOTU,   USBMIDI_MOTU_FASTLANE ) },
-/*	{ USB_DEVICE( USB_VENDOR_ID_STEINBERG, USBMIDI_STEINBERG_USB2MIDI ) },*/
-	{ } /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, usb_midi_ids);
-
-/* ------------------------------------------------------------------------- */
-#endif /* _USB_MIDI_H_ */
-
-
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index d34848a..48dee4b8 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -55,6 +55,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/lp.h>
+#include <linux/mutex.h>
 #undef DEBUG
 #include <linux/usb.h>
 
@@ -223,7 +224,7 @@
 
 /* forward reference to make our lives easier */
 static struct usb_driver usblp_driver;
-static DECLARE_MUTEX(usblp_sem);	/* locks the existence of usblp's */
+static DEFINE_MUTEX(usblp_mutex);	/* locks the existence of usblp's */
 
 /*
  * Functions for usblp control messages.
@@ -351,7 +352,7 @@
 	if (minor < 0)
 		return -ENODEV;
 
-	down (&usblp_sem);
+	mutex_lock (&usblp_mutex);
 
 	retval = -ENODEV;
 	intf = usb_find_interface(&usblp_driver, minor);
@@ -399,7 +400,7 @@
 		}
 	}
 out:
-	up (&usblp_sem);
+	mutex_unlock (&usblp_mutex);
 	return retval;
 }
 
@@ -425,13 +426,13 @@
 {
 	struct usblp *usblp = file->private_data;
 
-	down (&usblp_sem);
+	mutex_lock (&usblp_mutex);
 	usblp->used = 0;
 	if (usblp->present) {
 		usblp_unlink_urbs(usblp);
 	} else 		/* finish cleanup from disconnect */
 		usblp_cleanup (usblp);
-	up (&usblp_sem);
+	mutex_unlock (&usblp_mutex);
 	return 0;
 }
 
@@ -1152,7 +1153,7 @@
 
 	device_remove_file(&intf->dev, &dev_attr_ieee1284_id);
 
-	down (&usblp_sem);
+	mutex_lock (&usblp_mutex);
 	down (&usblp->sem);
 	usblp->present = 0;
 	usb_set_intfdata (intf, NULL);
@@ -1166,7 +1167,7 @@
 
 	if (!usblp->used)
 		usblp_cleanup (usblp);
-	up (&usblp_sem);
+	mutex_unlock (&usblp_mutex);
 }
 
 static struct usb_device_id usblp_ids [] = {
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index 2684e15..c0f3734 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -57,6 +57,7 @@
 #include <linux/usb.h>
 #include <linux/smp_lock.h>
 #include <linux/usbdevice_fs.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 #include "usb.h"
@@ -570,7 +571,7 @@
 	if (!access_ok(VERIFY_WRITE, buf, nbytes))
 		return -EFAULT;
 
-	down (&usb_bus_list_lock);
+	mutex_lock(&usb_bus_list_lock);
 	/* print devices for all busses */
 	list_for_each_entry(bus, &usb_bus_list, bus_list) {
 		/* recurse through all children of the root hub */
@@ -580,12 +581,12 @@
 		ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos, bus->root_hub, bus, 0, 0, 0);
 		usb_unlock_device(bus->root_hub);
 		if (ret < 0) {
-			up(&usb_bus_list_lock);
+			mutex_unlock(&usb_bus_list_lock);
 			return ret;
 		}
 		total_written += ret;
 	}
-	up (&usb_bus_list_lock);
+	mutex_unlock(&usb_bus_list_lock);
 	return total_written;
 }
 
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 2b68998..545da37 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -134,26 +134,21 @@
 	}
 
 	if (pos < sizeof(struct usb_device_descriptor)) {
-		struct usb_device_descriptor *desc = kmalloc(sizeof(*desc), GFP_KERNEL);
-		if (!desc) {
-			ret = -ENOMEM;
-			goto err;
-		}
-		memcpy(desc, &dev->descriptor, sizeof(dev->descriptor));
-		le16_to_cpus(&desc->bcdUSB);
-		le16_to_cpus(&desc->idVendor);
-		le16_to_cpus(&desc->idProduct);
-		le16_to_cpus(&desc->bcdDevice);
+		struct usb_device_descriptor temp_desc ; /* 18 bytes - fits on the stack */
+
+		memcpy(&temp_desc, &dev->descriptor, sizeof(dev->descriptor));
+		le16_to_cpus(&temp_desc.bcdUSB);
+		le16_to_cpus(&temp_desc.idVendor);
+		le16_to_cpus(&temp_desc.idProduct);
+		le16_to_cpus(&temp_desc.bcdDevice);
 
 		len = sizeof(struct usb_device_descriptor) - pos;
 		if (len > nbytes)
 			len = nbytes;
-		if (copy_to_user(buf, ((char *)desc) + pos, len)) {
-			kfree(desc);
+		if (copy_to_user(buf, ((char *)&temp_desc) + pos, len)) {
 			ret = -EFAULT;
 			goto err;
 		}
-		kfree(desc);
 
 		*ppos += len;
 		buf += len;
@@ -498,7 +493,8 @@
 {
 	int ret = 0;
 
-	if (ps->dev->state != USB_STATE_CONFIGURED)
+	if (ps->dev->state != USB_STATE_ADDRESS
+	 && ps->dev->state != USB_STATE_CONFIGURED)
 		return -EHOSTUNREACH;
 	if (USB_TYPE_VENDOR == (USB_TYPE_MASK & requesttype))
 		return 0;
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index dce9d98..c196f38 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -378,7 +378,7 @@
 
 	return NULL;
 }
-EXPORT_SYMBOL(usb_match_id);
+EXPORT_SYMBOL_GPL_FUTURE(usb_match_id);
 
 int usb_device_match(struct device *dev, struct device_driver *drv)
 {
@@ -446,7 +446,7 @@
 
 	return retval;
 }
-EXPORT_SYMBOL(usb_register_driver);
+EXPORT_SYMBOL_GPL_FUTURE(usb_register_driver);
 
 /**
  * usb_deregister - unregister a USB driver
@@ -469,4 +469,4 @@
 
 	usbfs_update_special();
 }
-EXPORT_SYMBOL(usb_deregister);
+EXPORT_SYMBOL_GPL_FUTURE(usb_deregister);
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index 29b5b2a..e0afb5a 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -264,14 +264,19 @@
 		 */
 		retval = pci_set_power_state (dev, PCI_D3hot);
 		if (retval == 0) {
-			dev_dbg (hcd->self.controller, "--> PCI D3\n");
+			int wake = device_can_wakeup(&hcd->self.root_hub->dev);
+
+			wake = wake && device_may_wakeup(hcd->self.controller);
+
+			dev_dbg (hcd->self.controller, "--> PCI D3%s\n",
+					wake ? "/wakeup" : "");
 
 			/* Ignore these return values.  We rely on pci code to
 			 * reject requests the hardware can't implement, rather
 			 * than coding the same thing.
 			 */
-			(void) pci_enable_wake (dev, PCI_D3hot, hcd->remote_wakeup);
-			(void) pci_enable_wake (dev, PCI_D3cold, hcd->remote_wakeup);
+			(void) pci_enable_wake (dev, PCI_D3hot, wake);
+			(void) pci_enable_wake (dev, PCI_D3cold, wake);
 		} else {
 			dev_dbg (&dev->dev, "PCI D3 suspend fail, %d\n",
 					retval);
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 0018bbc..fbd938d 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -34,6 +34,7 @@
 #include <asm/scatterlist.h>
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
+#include <linux/mutex.h>
 #include <asm/irq.h>
 #include <asm/byteorder.h>
 
@@ -93,7 +94,7 @@
 static struct usb_busmap busmap;
 
 /* used when updating list of hcds */
-DECLARE_MUTEX (usb_bus_list_lock);	/* exported only for usbfs */
+DEFINE_MUTEX(usb_bus_list_lock);	/* exported only for usbfs */
 EXPORT_SYMBOL_GPL (usb_bus_list_lock);
 
 /* used for controlling access to virtual root hubs */
@@ -366,21 +367,39 @@
 
 	/* DEVICE REQUESTS */
 
+	/* The root hub's remote wakeup enable bit is implemented using
+	 * driver model wakeup flags.  If this system supports wakeup
+	 * through USB, userspace may change the default "allow wakeup"
+	 * policy through sysfs or these calls.
+	 *
+	 * Most root hubs support wakeup from downstream devices, for
+	 * runtime power management (disabling USB clocks and reducing
+	 * VBUS power usage).  However, not all of them do so; silicon,
+	 * board, and BIOS bugs here are not uncommon, so these can't
+	 * be treated quite like external hubs.
+	 *
+	 * Likewise, not all root hubs will pass wakeup events upstream,
+	 * to wake up the whole system.  So don't assume root hub and
+	 * controller capabilities are identical.
+	 */
+
 	case DeviceRequest | USB_REQ_GET_STATUS:
-		tbuf [0] = (hcd->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP)
+		tbuf [0] = (device_may_wakeup(&hcd->self.root_hub->dev)
+					<< USB_DEVICE_REMOTE_WAKEUP)
 				| (1 << USB_DEVICE_SELF_POWERED);
 		tbuf [1] = 0;
 		len = 2;
 		break;
 	case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
 		if (wValue == USB_DEVICE_REMOTE_WAKEUP)
-			hcd->remote_wakeup = 0;
+			device_set_wakeup_enable(&hcd->self.root_hub->dev, 0);
 		else
 			goto error;
 		break;
 	case DeviceOutRequest | USB_REQ_SET_FEATURE:
-		if (hcd->can_wakeup && wValue == USB_DEVICE_REMOTE_WAKEUP)
-			hcd->remote_wakeup = 1;
+		if (device_can_wakeup(&hcd->self.root_hub->dev)
+				&& wValue == USB_DEVICE_REMOTE_WAKEUP)
+			device_set_wakeup_enable(&hcd->self.root_hub->dev, 1);
 		else
 			goto error;
 		break;
@@ -409,7 +428,7 @@
 				bufp = fs_rh_config_descriptor;
 				len = sizeof fs_rh_config_descriptor;
 			}
-			if (hcd->can_wakeup)
+			if (device_can_wakeup(&hcd->self.root_hub->dev))
 				patch_wakeup = 1;
 			break;
 		case USB_DT_STRING << 8:
@@ -761,14 +780,14 @@
 {
 	int busnum;
 
-	down (&usb_bus_list_lock);
+	mutex_lock(&usb_bus_list_lock);
 	busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1);
 	if (busnum < USB_MAXBUS) {
 		set_bit (busnum, busmap.busmap);
 		bus->busnum = busnum;
 	} else {
 		printk (KERN_ERR "%s: too many buses\n", usbcore_name);
-		up(&usb_bus_list_lock);
+		mutex_unlock(&usb_bus_list_lock);
 		return -E2BIG;
 	}
 
@@ -776,7 +795,7 @@
 					     bus->controller, "usb_host%d", busnum);
 	if (IS_ERR(bus->class_dev)) {
 		clear_bit(busnum, busmap.busmap);
-		up(&usb_bus_list_lock);
+		mutex_unlock(&usb_bus_list_lock);
 		return PTR_ERR(bus->class_dev);
 	}
 
@@ -784,7 +803,7 @@
 
 	/* Add it to the local list of buses */
 	list_add (&bus->bus_list, &usb_bus_list);
-	up (&usb_bus_list_lock);
+	mutex_unlock(&usb_bus_list_lock);
 
 	usb_notify_add_bus(bus);
 
@@ -809,9 +828,9 @@
 	 * controller code, as well as having it call this when cleaning
 	 * itself up
 	 */
-	down (&usb_bus_list_lock);
+	mutex_lock(&usb_bus_list_lock);
 	list_del (&bus->bus_list);
-	up (&usb_bus_list_lock);
+	mutex_unlock(&usb_bus_list_lock);
 
 	usb_notify_remove_bus(bus);
 
@@ -822,18 +841,17 @@
 
 /**
  * register_root_hub - called by usb_add_hcd() to register a root hub
- * @usb_dev: the usb root hub device to be registered.
  * @hcd: host controller for this root hub
  *
  * This function registers the root hub with the USB subsystem.  It sets up
- * the device properly in the device tree and stores the root_hub pointer
- * in the bus structure, then calls usb_new_device() to register the usb
- * device.  It also assigns the root hub's USB address (always 1).
+ * the device properly in the device tree and then calls usb_new_device()
+ * to register the usb device.  It also assigns the root hub's USB address
+ * (always 1).
  */
-static int register_root_hub (struct usb_device *usb_dev,
-		struct usb_hcd *hcd)
+static int register_root_hub(struct usb_hcd *hcd)
 {
 	struct device *parent_dev = hcd->self.controller;
+	struct usb_device *usb_dev = hcd->self.root_hub;
 	const int devnum = 1;
 	int retval;
 
@@ -844,14 +862,12 @@
 	set_bit (devnum, usb_dev->bus->devmap.devicemap);
 	usb_set_device_state(usb_dev, USB_STATE_ADDRESS);
 
-	down (&usb_bus_list_lock);
-	usb_dev->bus->root_hub = usb_dev;
+	mutex_lock(&usb_bus_list_lock);
 
 	usb_dev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64);
 	retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);
 	if (retval != sizeof usb_dev->descriptor) {
-		usb_dev->bus->root_hub = NULL;
-		up (&usb_bus_list_lock);
+		mutex_unlock(&usb_bus_list_lock);
 		dev_dbg (parent_dev, "can't read %s device descriptor %d\n",
 				usb_dev->dev.bus_id, retval);
 		return (retval < 0) ? retval : -EMSGSIZE;
@@ -859,11 +875,10 @@
 
 	retval = usb_new_device (usb_dev);
 	if (retval) {
-		usb_dev->bus->root_hub = NULL;
 		dev_err (parent_dev, "can't register root hub for %s, %d\n",
 				usb_dev->dev.bus_id, retval);
 	}
-	up (&usb_bus_list_lock);
+	mutex_unlock(&usb_bus_list_lock);
 
 	if (retval == 0) {
 		spin_lock_irq (&hcd_root_hub_lock);
@@ -1090,7 +1105,6 @@
 	spin_lock_irqsave (&hcd_data_lock, flags);
 	list_del_init (&urb->urb_list);
 	spin_unlock_irqrestore (&hcd_data_lock, flags);
-	usb_put_dev (urb->dev);
 }
 
 
@@ -1130,7 +1144,6 @@
 	case HC_STATE_RUNNING:
 	case HC_STATE_RESUMING:
 doit:
-		usb_get_dev (urb->dev);
 		list_add_tail (&urb->urb_list, &ep->urb_list);
 		status = 0;
 		break;
@@ -1771,12 +1784,10 @@
 
 	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
 
-	/* till now HC has been in an indeterminate state ... */
-	if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) {
-		dev_err(hcd->self.controller, "can't reset\n");
-		return retval;
-	}
-
+	/* HC is in reset state, but accessible.  Now do the one-time init,
+	 * bottom up so that hcds can customize the root hubs before khubd
+	 * starts talking to them.  (Note, bus id is assigned early too.)
+	 */
 	if ((retval = hcd_buffer_create(hcd)) != 0) {
 		dev_dbg(hcd->self.controller, "pool alloc failed\n");
 		return retval;
@@ -1785,6 +1796,36 @@
 	if ((retval = usb_register_bus(&hcd->self)) < 0)
 		goto err_register_bus;
 
+	if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) {
+		dev_err(hcd->self.controller, "unable to allocate root hub\n");
+		retval = -ENOMEM;
+		goto err_allocate_root_hub;
+	}
+	rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH :
+			USB_SPEED_FULL;
+	hcd->self.root_hub = rhdev;
+
+	/* "reset" is misnamed; its role is now one-time init. the controller
+	 * should already have been reset (and boot firmware kicked off etc).
+	 */
+	if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) {
+		dev_err(hcd->self.controller, "can't setup\n");
+		goto err_hcd_driver_setup;
+	}
+
+	/* wakeup flag init is in transition; for now we can't rely on PCI to
+	 * initialize these bits properly, so we let reset() override it.
+	 * This init should _precede_ the reset() once PCI behaves.
+	 */
+	device_init_wakeup(&rhdev->dev,
+			device_can_wakeup(hcd->self.controller));
+
+	/* NOTE: root hub and controller capabilities may not be the same */
+	if (device_can_wakeup(hcd->self.controller)
+			&& device_can_wakeup(&hcd->self.root_hub->dev))
+		dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");
+
+	/* enable irqs just before we start the controller */
 	if (hcd->driver->irq) {
 		char	buf[8], *bufp = buf;
 
@@ -1816,56 +1857,32 @@
 					(unsigned long long)hcd->rsrc_start);
 	}
 
-	/* Allocate the root hub before calling hcd->driver->start(),
-	 * but don't register it until afterward so that the hardware
-	 * is running.
-	 */
-	if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) {
-		dev_err(hcd->self.controller, "unable to allocate root hub\n");
-		retval = -ENOMEM;
-		goto err_allocate_root_hub;
-	}
-
-	/* Although in principle hcd->driver->start() might need to use rhdev,
-	 * none of the current drivers do.
-	 */
 	if ((retval = hcd->driver->start(hcd)) < 0) {
 		dev_err(hcd->self.controller, "startup error %d\n", retval);
 		goto err_hcd_driver_start;
 	}
 
-	/* hcd->driver->start() reported can_wakeup, probably with
-	 * assistance from board's boot firmware.
-	 * NOTE:  normal devices won't enable wakeup by default.
-	 */
-	if (hcd->can_wakeup)
-		dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");
-	hcd->remote_wakeup = hcd->can_wakeup;
-
-	rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH :
-			USB_SPEED_FULL;
+	/* starting here, usbcore will pay attention to this root hub */
 	rhdev->bus_mA = min(500u, hcd->power_budget);
-	if ((retval = register_root_hub(rhdev, hcd)) != 0)
+	if ((retval = register_root_hub(hcd)) != 0)
 		goto err_register_root_hub;
 
 	if (hcd->uses_new_polling && hcd->poll_rh)
 		usb_hcd_poll_rh_status(hcd);
 	return retval;
 
- err_register_root_hub:
+err_register_root_hub:
 	hcd->driver->stop(hcd);
-
- err_hcd_driver_start:
-	usb_put_dev(rhdev);
-
- err_allocate_root_hub:
+err_hcd_driver_start:
 	if (hcd->irq >= 0)
 		free_irq(irqnum, hcd);
-
- err_request_irq:
+err_request_irq:
+err_hcd_driver_setup:
+	hcd->self.root_hub = NULL;
+	usb_put_dev(rhdev);
+err_allocate_root_hub:
 	usb_deregister_bus(&hcd->self);
-
- err_register_bus:
+err_register_bus:
 	hcd_buffer_destroy(hcd);
 	return retval;
 } 
@@ -1891,9 +1908,9 @@
 	hcd->rh_registered = 0;
 	spin_unlock_irq (&hcd_root_hub_lock);
 
-	down(&usb_bus_list_lock);
+	mutex_lock(&usb_bus_list_lock);
 	usb_disconnect(&hcd->self.root_hub);
-	up(&usb_bus_list_lock);
+	mutex_unlock(&usb_bus_list_lock);
 
 	hcd->poll_rh = 0;
 	del_timer_sync(&hcd->rh_timer);
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index 591b5aa..7022aaf 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -78,8 +78,6 @@
 #define HCD_FLAG_HW_ACCESSIBLE	0x00000001
 #define HCD_FLAG_SAW_IRQ	0x00000002
 
-	unsigned		can_wakeup:1;	/* hw supports wakeup? */
-	unsigned		remote_wakeup:1;/* sw should use wakeup? */
 	unsigned		rh_registered:1;/* is root hub registered? */
 
 	/* The next flag is a stopgap, to be removed when all the HCDs
@@ -364,7 +362,7 @@
 /* exported only within usbcore */
 
 extern struct list_head usb_bus_list;
-extern struct semaphore usb_bus_list_lock;
+extern struct mutex usb_bus_list_lock;
 extern wait_queue_head_t usb_kill_urb_queue;
 
 extern struct usb_bus *usb_bus_get (struct usb_bus *bus);
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 650d5ee..8e65f7a 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -22,6 +22,7 @@
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
 #include <linux/kthread.h>
+#include <linux/mutex.h>
 
 #include <asm/semaphore.h>
 #include <asm/uaccess.h>
@@ -1005,12 +1006,18 @@
 		;	/* do nothing */
 	else if (new_state != USB_STATE_NOTATTACHED) {
 		udev->state = new_state;
-		if (new_state == USB_STATE_CONFIGURED)
-			device_init_wakeup(&udev->dev,
-				(udev->actconfig->desc.bmAttributes
-				 & USB_CONFIG_ATT_WAKEUP));
-		else if (new_state != USB_STATE_SUSPENDED)
-			device_init_wakeup(&udev->dev, 0);
+
+		/* root hub wakeup capabilities are managed out-of-band
+		 * and may involve silicon errata ... ignore them here.
+		 */
+		if (udev->parent) {
+			if (new_state == USB_STATE_CONFIGURED)
+				device_init_wakeup(&udev->dev,
+					(udev->actconfig->desc.bmAttributes
+					 & USB_CONFIG_ATT_WAKEUP));
+			else if (new_state != USB_STATE_SUSPENDED)
+				device_init_wakeup(&udev->dev, 0);
+		}
 	} else
 		recursively_mark_NOTATTACHED(udev);
 	spin_unlock_irqrestore(&device_state_lock, flags);
@@ -1172,8 +1179,11 @@
 	c = udev->config;
 	num_configs = udev->descriptor.bNumConfigurations;
 	for (i = 0; i < num_configs; (i++, c++)) {
-		struct usb_interface_descriptor	*desc =
-				&c->intf_cache[0]->altsetting->desc;
+		struct usb_interface_descriptor	*desc = NULL;
+
+		/* It's possible that a config has no interfaces! */
+		if (c->desc.bNumInterfaces > 0)
+			desc = &c->intf_cache[0]->altsetting->desc;
 
 		/*
 		 * HP's USB bus-powered keyboard has only one configuration
@@ -1208,7 +1218,8 @@
 		/* If the first config's first interface is COMM/2/0xff
 		 * (MSFT RNDIS), rule it out unless Linux has host-side
 		 * RNDIS support. */
-		if (i == 0 && desc->bInterfaceClass == USB_CLASS_COMM
+		if (i == 0 && desc
+				&& desc->bInterfaceClass == USB_CLASS_COMM
 				&& desc->bInterfaceSubClass == 2
 				&& desc->bInterfaceProtocol == 0xff) {
 #ifndef CONFIG_USB_NET_RNDIS
@@ -1224,8 +1235,8 @@
 		 * than a vendor-specific driver. */
 		else if (udev->descriptor.bDeviceClass !=
 						USB_CLASS_VENDOR_SPEC &&
-				desc->bInterfaceClass !=
-						USB_CLASS_VENDOR_SPEC) {
+				(!desc || desc->bInterfaceClass !=
+						USB_CLASS_VENDOR_SPEC)) {
 			best = c;
 			break;
 		}
@@ -1876,18 +1887,18 @@
 	if (udev->state == USB_STATE_NOTATTACHED)
 		return -ENODEV;
 
-#ifdef	CONFIG_USB_SUSPEND
 	/* selective resume of one downstream hub-to-device port */
 	if (udev->parent) {
+#ifdef	CONFIG_USB_SUSPEND
 		if (udev->state == USB_STATE_SUSPENDED) {
 			// NOTE swsusp may bork us, device state being wrong...
 			// NOTE this fails if parent is also suspended...
 			status = hub_port_resume(hdev_to_hub(udev->parent),
 					udev->portnum, udev);
 		} else
+#endif
 			status = 0;
 	} else
-#endif
 		status = finish_device_resume(udev);
 	if (status < 0)
 		dev_dbg(&udev->dev, "can't resume, status %d\n",
@@ -2162,7 +2173,7 @@
 hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 		int retry_counter)
 {
-	static DECLARE_MUTEX(usb_address0_sem);
+	static DEFINE_MUTEX(usb_address0_mutex);
 
 	struct usb_device	*hdev = hub->hdev;
 	int			i, j, retval;
@@ -2183,7 +2194,7 @@
 	if (oldspeed == USB_SPEED_LOW)
 		delay = HUB_LONG_RESET_TIME;
 
-	down(&usb_address0_sem);
+	mutex_lock(&usb_address0_mutex);
 
 	/* Reset the device; full speed may morph to high speed */
 	retval = hub_port_reset(hub, port1, udev, delay);
@@ -2381,7 +2392,7 @@
 fail:
 	if (retval)
 		hub_port_disable(hub, port1, 0);
-	up(&usb_address0_sem);
+	mutex_unlock(&usb_address0_mutex);
 	return retval;
 }
 
@@ -3017,7 +3028,7 @@
 	parent_hub = hdev_to_hub(parent_hdev);
 
 	/* If we're resetting an active hub, take some special actions */
-	if (udev->actconfig &&
+	if (udev->actconfig && udev->actconfig->desc.bNumInterfaces > 0 &&
 			udev->actconfig->interface[0]->dev.driver ==
 				&hub_driver.driver &&
 			(hub = hdev_to_hub(udev)) != NULL) {
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 7135e54..08fb20f 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -631,8 +631,8 @@
  * Returns the number of bytes received on success, or else the status code
  * returned by the underlying usb_control_msg() call.
  */
-int usb_get_string(struct usb_device *dev, unsigned short langid,
-		unsigned char index, void *buf, int size)
+static int usb_get_string(struct usb_device *dev, unsigned short langid,
+			  unsigned char index, void *buf, int size)
 {
 	int i;
 	int result;
@@ -1388,11 +1388,13 @@
 	if (dev->state != USB_STATE_ADDRESS)
 		usb_disable_device (dev, 1);	// Skip ep0
 
-	i = dev->bus_mA - cp->desc.bMaxPower * 2;
-	if (i < 0)
-		dev_warn(&dev->dev, "new config #%d exceeds power "
-				"limit by %dmA\n",
-				configuration, -i);
+	if (cp) {
+		i = dev->bus_mA - cp->desc.bMaxPower * 2;
+		if (i < 0)
+			dev_warn(&dev->dev, "new config #%d exceeds power "
+					"limit by %dmA\n",
+					configuration, -i);
+	}
 
 	if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
 			USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
@@ -1488,7 +1490,6 @@
 // synchronous control message convenience routines
 EXPORT_SYMBOL(usb_get_descriptor);
 EXPORT_SYMBOL(usb_get_status);
-EXPORT_SYMBOL(usb_get_string);
 EXPORT_SYMBOL(usb_string);
 
 // synchronous calls that also maintain usbcore state
diff --git a/drivers/usb/core/notify.c b/drivers/usb/core/notify.c
index fbbebab..4b55285 100644
--- a/drivers/usb/core/notify.c
+++ b/drivers/usb/core/notify.c
@@ -13,16 +13,17 @@
 #include <linux/kernel.h>
 #include <linux/notifier.h>
 #include <linux/usb.h>
+#include <linux/mutex.h>
 #include "usb.h"
 
 
 static struct notifier_block *usb_notifier_list;
-static DECLARE_MUTEX(usb_notifier_lock);
+static DEFINE_MUTEX(usb_notifier_lock);
 
 static void usb_notifier_chain_register(struct notifier_block **list,
 					struct notifier_block *n)
 {
-	down(&usb_notifier_lock);
+	mutex_lock(&usb_notifier_lock);
 	while (*list) {
 		if (n->priority > (*list)->priority)
 			break;
@@ -30,13 +31,13 @@
 	}
 	n->next = *list;
 	*list = n;
-	up(&usb_notifier_lock);
+	mutex_unlock(&usb_notifier_lock);
 }
 
 static void usb_notifier_chain_unregister(struct notifier_block **nl,
 				   struct notifier_block *n)
 {
-	down(&usb_notifier_lock);
+	mutex_lock(&usb_notifier_lock);
 	while ((*nl)!=NULL) {
 		if ((*nl)==n) {
 			*nl = n->next;
@@ -45,7 +46,7 @@
 		nl=&((*nl)->next);
 	}
 exit:
-	up(&usb_notifier_lock);
+	mutex_unlock(&usb_notifier_lock);
 }
 
 static int usb_notifier_call_chain(struct notifier_block **n,
@@ -54,7 +55,7 @@
 	int ret=NOTIFY_DONE;
 	struct notifier_block *nb = *n;
 
-	down(&usb_notifier_lock);
+	mutex_lock(&usb_notifier_lock);
 	while (nb) {
 		ret = nb->notifier_call(nb,val,v);
 		if (ret&NOTIFY_STOP_MASK) {
@@ -63,7 +64,7 @@
 		nb = nb->next;
 	}
 exit:
-	up(&usb_notifier_lock);
+	mutex_unlock(&usb_notifier_lock);
 	return ret;
 }
 
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 13d1d36..d7352aa 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -33,6 +33,7 @@
 #include <linux/errno.h>
 #include <linux/smp_lock.h>
 #include <linux/usb.h>
+#include <linux/mutex.h>
 
 #include <asm/io.h>
 #include <asm/scatterlist.h>
@@ -639,7 +640,7 @@
 	struct usb_bus *bus;
 	struct usb_device *dev = NULL;
 	
-	down(&usb_bus_list_lock);
+	mutex_lock(&usb_bus_list_lock);
 	for (buslist = usb_bus_list.next;
 	     buslist != &usb_bus_list; 
 	     buslist = buslist->next) {
@@ -653,7 +654,7 @@
 			goto exit;
 	}
 exit:
-	up(&usb_bus_list_lock);
+	mutex_unlock(&usb_bus_list_lock);
 	return dev;
 }
 
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index ff075a5..d80f718 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -187,6 +187,23 @@
 
 	   Select this only if your OMAP board has a Mini-AB connector.
 
+config USB_GADGET_AT91
+	boolean "AT91 USB Device Port"
+	depends on ARCH_AT91RM9200
+	select USB_GADGET_SELECTED
+	help
+	   Many Atmel AT91 processors (such as the AT91RM2000) have a
+	   full speed USB Device Port with support for five configurable
+	   endpoints (plus endpoint zero).
+
+	   Say "y" to link the driver statically, or "m" to build a
+	   dynamically linked module called "at91_udc" and force all
+	   gadget drivers to also be dynamically linked.
+
+config USB_AT91
+	tristate
+	depends on USB_GADGET_AT91
+	default USB_GADGET
 
 config USB_GADGET_DUMMY_HCD
 	boolean "Dummy HCD (DEVELOPMENT)"
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index d5fd04d..5a28e613 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -7,6 +7,7 @@
 obj-$(CONFIG_USB_GOKU)		+= goku_udc.o
 obj-$(CONFIG_USB_OMAP)		+= omap_udc.o
 obj-$(CONFIG_USB_LH7A40X)	+= lh7a40x_udc.o
+obj-$(CONFIG_USB_AT91)		+= at91_udc.o
 
 #
 # USB gadget drivers
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
new file mode 100644
index 0000000..865858c
--- /dev/null
+++ b/drivers/usb/gadget/at91_udc.c
@@ -0,0 +1,1773 @@
+/*
+ * at91_udc -- driver for at91-series USB peripheral controller
+ *
+ * Copyright (C) 2004 by Thomas Rathbone
+ * Copyright (C) 2005 by HP Labs
+ * Copyright (C) 2005 by 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., 59 Temple Place - Suite 330,
+ * Boston, MA  02111-1307, USA.
+ */
+
+#undef	DEBUG
+#undef	VERBOSE
+#undef	PACKET_TRACE
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/clk.h>
+#include <linux/usb_ch9.h>
+#include <linux/usb_gadget.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/board.h>
+
+#include "at91_udc.h"
+
+
+/*
+ * This controller is simple and PIO-only.  It's used in many AT91-series
+ * ARMv4T controllers, including the at91rm9200 (arm920T, with MMU),
+ * at91sam9261 (arm926ejs, with MMU), and several no-mmu versions.
+ *
+ * This driver expects the board has been wired with two GPIOs suppporting
+ * a VBUS sensing IRQ, and a D+ pullup.  (They may be omitted, but the
+ * testing hasn't covered such cases.)  The pullup is most important; it
+ * provides software control over whether the host enumerates the device.
+ * The VBUS sensing helps during enumeration, and allows both USB clocks
+ * (and the transceiver) to stay gated off until they're necessary, saving
+ * power.  During USB suspend, the 48 MHz clock is gated off.
+ */
+
+#define	DRIVER_VERSION	"8 March 2005"
+
+static const char driver_name [] = "at91_udc";
+static const char ep0name[] = "ep0";
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Read from a UDP register.
+ */
+static inline unsigned long at91_udp_read(unsigned int reg)
+{
+	void __iomem *udp_base = (void __iomem *)AT91_VA_BASE_UDP;
+
+	return __raw_readl(udp_base + reg);
+}
+
+/*
+ * Write to a UDP register.
+ */
+static inline void at91_udp_write(unsigned int reg, unsigned long value)
+{
+	void __iomem *udp_base = (void __iomem *)AT91_VA_BASE_UDP;
+
+	__raw_writel(value, udp_base + reg);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+
+#include <linux/seq_file.h>
+
+static const char debug_filename[] = "driver/udc";
+
+#define FOURBITS "%s%s%s%s"
+#define EIGHTBITS FOURBITS FOURBITS
+
+static void proc_ep_show(struct seq_file *s, struct at91_ep *ep)
+{
+	static char		*types[] = {
+		"control", "out-iso", "out-bulk", "out-int",
+		"BOGUS",   "in-iso",  "in-bulk",  "in-int"};
+
+	u32			csr;
+	struct at91_request	*req;
+	unsigned long	flags;
+
+	local_irq_save(flags);
+
+	csr = __raw_readl(ep->creg);
+
+	/* NOTE:  not collecting per-endpoint irq statistics... */
+
+	seq_printf(s, "\n");
+	seq_printf(s, "%s, maxpacket %d %s%s %s%s\n",
+			ep->ep.name, ep->ep.maxpacket,
+			ep->is_in ? "in" : "out",
+			ep->is_iso ? " iso" : "",
+			ep->is_pingpong
+				? (ep->fifo_bank ? "pong" : "ping")
+				: "",
+			ep->stopped ? " stopped" : "");
+	seq_printf(s, "csr %08x rxbytes=%d %s %s %s" EIGHTBITS "\n",
+		csr,
+		(csr & 0x07ff0000) >> 16,
+		(csr & (1 << 15)) ? "enabled" : "disabled",
+		(csr & (1 << 11)) ? "DATA1" : "DATA0",
+		types[(csr & 0x700) >> 8],
+
+		/* iff type is control then print current direction */
+		(!(csr & 0x700))
+			? ((csr & (1 << 7)) ? " IN" : " OUT")
+			: "",
+		(csr & (1 << 6)) ? " rxdatabk1" : "",
+		(csr & (1 << 5)) ? " forcestall" : "",
+		(csr & (1 << 4)) ? " txpktrdy" : "",
+
+		(csr & (1 << 3)) ? " stallsent" : "",
+		(csr & (1 << 2)) ? " rxsetup" : "",
+		(csr & (1 << 1)) ? " rxdatabk0" : "",
+		(csr & (1 << 0)) ? " txcomp" : "");
+	if (list_empty (&ep->queue))
+		seq_printf(s, "\t(queue empty)\n");
+
+	else list_for_each_entry (req, &ep->queue, queue) {
+		unsigned	length = req->req.actual;
+
+		seq_printf(s, "\treq %p len %d/%d buf %p\n",
+				&req->req, length,
+				req->req.length, req->req.buf);
+	}
+	local_irq_restore(flags);
+}
+
+static void proc_irq_show(struct seq_file *s, const char *label, u32 mask)
+{
+	int i;
+
+	seq_printf(s, "%s %04x:%s%s" FOURBITS, label, mask,
+		(mask & (1 << 13)) ? " wakeup" : "",
+		(mask & (1 << 12)) ? " endbusres" : "",
+
+		(mask & (1 << 11)) ? " sofint" : "",
+		(mask & (1 << 10)) ? " extrsm" : "",
+		(mask & (1 << 9)) ? " rxrsm" : "",
+		(mask & (1 << 8)) ? " rxsusp" : "");
+	for (i = 0; i < 8; i++) {
+		if (mask & (1 << i))
+			seq_printf(s, " ep%d", i);
+	}
+	seq_printf(s, "\n");
+}
+
+static int proc_udc_show(struct seq_file *s, void *unused)
+{
+	struct at91_udc	*udc = s->private;
+	struct at91_ep	*ep;
+	u32		tmp;
+
+	seq_printf(s, "%s: version %s\n", driver_name, DRIVER_VERSION);
+
+	seq_printf(s, "vbus %s, pullup %s, %s powered%s, gadget %s\n\n",
+		udc->vbus ? "present" : "off",
+		udc->enabled
+			? (udc->vbus ? "active" : "enabled")
+			: "disabled",
+		udc->selfpowered ? "self" : "VBUS",
+		udc->suspended ? ", suspended" : "",
+		udc->driver ? udc->driver->driver.name : "(none)");
+
+	/* don't access registers when interface isn't clocked */
+	if (!udc->clocked) {
+		seq_printf(s, "(not clocked)\n");
+		return 0;
+	}
+
+	tmp = at91_udp_read(AT91_UDP_FRM_NUM);
+	seq_printf(s, "frame %05x:%s%s frame=%d\n", tmp,
+		(tmp & AT91_UDP_FRM_OK) ? " ok" : "",
+		(tmp & AT91_UDP_FRM_ERR) ? " err" : "",
+		(tmp & AT91_UDP_NUM));
+
+	tmp = at91_udp_read(AT91_UDP_GLB_STAT);
+	seq_printf(s, "glbstate %02x:%s" FOURBITS "\n", tmp,
+		(tmp & AT91_UDP_RMWUPE) ? " rmwupe" : "",
+		(tmp & AT91_UDP_RSMINPR) ? " rsminpr" : "",
+		(tmp & AT91_UDP_ESR) ? " esr" : "",
+		(tmp & AT91_UDP_CONFG) ? " confg" : "",
+		(tmp & AT91_UDP_FADDEN) ? " fadden" : "");
+
+	tmp = at91_udp_read(AT91_UDP_FADDR);
+	seq_printf(s, "faddr   %03x:%s fadd=%d\n", tmp,
+		(tmp & AT91_UDP_FEN) ? " fen" : "",
+		(tmp & AT91_UDP_FADD));
+
+	proc_irq_show(s, "imr   ", at91_udp_read(AT91_UDP_IMR));
+	proc_irq_show(s, "isr   ", at91_udp_read(AT91_UDP_ISR));
+
+	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);
+		}
+	}
+	return 0;
+}
+
+static int proc_udc_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, proc_udc_show, PDE(inode)->data);
+}
+
+static struct file_operations proc_ops = {
+	.open		= proc_udc_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static void create_debug_file(struct at91_udc *udc)
+{
+	struct proc_dir_entry *pde;
+
+	pde = create_proc_entry (debug_filename, 0, NULL);
+	udc->pde = pde;
+	if (pde == NULL)
+		return;
+
+	pde->proc_fops = &proc_ops;
+	pde->data = udc;
+}
+
+static void remove_debug_file(struct at91_udc *udc)
+{
+	if (udc->pde)
+		remove_proc_entry(debug_filename, NULL);
+}
+
+#else
+
+static inline void create_debug_file(struct at91_udc *udc) {}
+static inline void remove_debug_file(struct at91_udc *udc) {}
+
+#endif
+
+
+/*-------------------------------------------------------------------------*/
+
+static void done(struct at91_ep *ep, struct at91_request *req, int status)
+{
+	unsigned	stopped = ep->stopped;
+
+	list_del_init(&req->queue);
+	if (req->req.status == -EINPROGRESS)
+		req->req.status = status;
+	else
+		status = req->req.status;
+	if (status && status != -ESHUTDOWN)
+		VDBG("%s done %p, status %d\n", ep->ep.name, req, status);
+
+	ep->stopped = 1;
+	req->req.complete(&ep->ep, &req->req);
+	ep->stopped = stopped;
+
+	/* ep0 is always ready; other endpoints need a non-empty queue */
+	if (list_empty(&ep->queue) && ep->int_mask != (1 << 0))
+		at91_udp_write(AT91_UDP_IDR, ep->int_mask);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* bits indicating OUT fifo has data ready */
+#define	RX_DATA_READY	(AT91_UDP_RX_DATA_BK0 | AT91_UDP_RX_DATA_BK1)
+
+/*
+ * Endpoint FIFO CSR bits have a mix of bits, making it unsafe to just write
+ * back most of the value you just read (because of side effects, including
+ * bits that may change after reading and before writing).
+ *
+ * Except when changing a specific bit, always write values which:
+ *  - clear SET_FX bits (setting them could change something)
+ *  - set CLR_FX bits (clearing them could change something)
+ *
+ * There are also state bits like FORCESTALL, EPEDS, DIR, and EPTYPE
+ * that shouldn't normally be changed.
+ */
+#define	SET_FX	(AT91_UDP_TXPKTRDY)
+#define	CLR_FX	(RX_DATA_READY | AT91_UDP_RXSETUP | AT91_UDP_STALLSENT | AT91_UDP_TXCOMP)
+
+/* pull OUT packet data from the endpoint's fifo */
+static int read_fifo (struct at91_ep *ep, struct at91_request *req)
+{
+	u32 __iomem	*creg = ep->creg;
+	u8 __iomem	*dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0));
+	u32		csr;
+	u8		*buf;
+	unsigned int	count, bufferspace, is_done;
+
+	buf = req->req.buf + req->req.actual;
+	bufferspace = req->req.length - req->req.actual;
+
+	/*
+	 * there might be nothing to read if ep_queue() calls us,
+	 * or if we already emptied both pingpong buffers
+	 */
+rescan:
+	csr = __raw_readl(creg);
+	if ((csr & RX_DATA_READY) == 0)
+		return 0;
+
+	count = (csr & AT91_UDP_RXBYTECNT) >> 16;
+	if (count > ep->ep.maxpacket)
+		count = ep->ep.maxpacket;
+	if (count > bufferspace) {
+		DBG("%s buffer overflow\n", ep->ep.name);
+		req->req.status = -EOVERFLOW;
+		count = bufferspace;
+	}
+	__raw_readsb(dreg, buf, count);
+
+	/* release and swap pingpong mem bank */
+	csr |= CLR_FX;
+	if (ep->is_pingpong) {
+		if (ep->fifo_bank == 0) {
+			csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0);
+			ep->fifo_bank = 1;
+		} else {
+			csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK1);
+			ep->fifo_bank = 0;
+		}
+	} else
+		csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0);
+	__raw_writel(csr, creg);
+
+	req->req.actual += count;
+	is_done = (count < ep->ep.maxpacket);
+	if (count == bufferspace)
+		is_done = 1;
+
+	PACKET("%s %p out/%d%s\n", ep->ep.name, &req->req, count,
+			is_done ? " (done)" : "");
+
+	/*
+	 * avoid extra trips through IRQ logic for packets already in
+	 * the fifo ... maybe preventing an extra (expensive) OUT-NAK
+	 */
+	if (is_done)
+		done(ep, req, 0);
+	else if (ep->is_pingpong) {
+		bufferspace -= count;
+		buf += count;
+		goto rescan;
+	}
+
+	return is_done;
+}
+
+/* load fifo for an IN packet */
+static int write_fifo(struct at91_ep *ep, struct at91_request *req)
+{
+	u32 __iomem	*creg = ep->creg;
+	u32		csr = __raw_readl(creg);
+	u8 __iomem	*dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0));
+	unsigned	total, count, is_last;
+
+	/*
+	 * TODO: allow for writing two packets to the fifo ... that'll
+	 * reduce the amount of IN-NAKing, but probably won't affect
+	 * throughput much.  (Unlike preventing OUT-NAKing!)
+	 */
+
+	/*
+	 * If ep_queue() calls us, the queue is empty and possibly in
+	 * odd states like TXCOMP not yet cleared (we do it, saving at
+	 * least one IRQ) or the fifo not yet being free.  Those aren't
+	 * issues normally (IRQ handler fast path).
+	 */
+	if (unlikely(csr & (AT91_UDP_TXCOMP | AT91_UDP_TXPKTRDY))) {
+		if (csr & AT91_UDP_TXCOMP) {
+			csr |= CLR_FX;
+			csr &= ~(SET_FX | AT91_UDP_TXCOMP);
+			__raw_writel(csr, creg);
+			csr = __raw_readl(creg);
+		}
+		if (csr & AT91_UDP_TXPKTRDY)
+			return 0;
+	}
+
+	total = req->req.length - req->req.actual;
+	if (ep->ep.maxpacket < total) {
+		count = ep->ep.maxpacket;
+		is_last = 0;
+	} else {
+		count = total;
+		is_last = (count < ep->ep.maxpacket) || !req->req.zero;
+	}
+
+	/*
+	 * Write the packet, maybe it's a ZLP.
+	 *
+	 * NOTE:  incrementing req->actual before we receive the ACK means
+	 * gadget driver IN bytecounts can be wrong in fault cases.  That's
+	 * fixable with PIO drivers like this one (save "count" here, and
+	 * do the increment later on TX irq), but not for most DMA hardware.
+	 *
+	 * So all gadget drivers must accept that potential error.  Some
+	 * hardware supports precise fifo status reporting, letting them
+	 * recover when the actual bytecount matters (e.g. for USB Test
+	 * and Measurement Class devices).
+	 */
+	__raw_writesb(dreg, req->req.buf + req->req.actual, count);
+	csr &= ~SET_FX;
+	csr |= CLR_FX | AT91_UDP_TXPKTRDY;
+	__raw_writel(csr, creg);
+	req->req.actual += count;
+
+	PACKET("%s %p in/%d%s\n", ep->ep.name, &req->req, count,
+			is_last ? " (done)" : "");
+	if (is_last)
+		done(ep, req, 0);
+	return is_last;
+}
+
+static void nuke(struct at91_ep *ep, int status)
+{
+	struct at91_request *req;
+
+	// terminer chaque requete dans la queue
+	ep->stopped = 1;
+	if (list_empty(&ep->queue))
+		return;
+
+	VDBG("%s %s\n", __FUNCTION__, ep->ep.name);
+	while (!list_empty(&ep->queue)) {
+		req = list_entry(ep->queue.next, struct at91_request, queue);
+		done(ep, req, status);
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int at91_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+	struct at91_ep	*ep = container_of(_ep, struct at91_ep, ep);
+	struct at91_udc	*dev = ep->udc;
+	u16		maxpacket;
+	u32		tmp;
+	unsigned long	flags;
+
+	if (!_ep || !ep
+			|| !desc || ep->desc
+			|| _ep->name == ep0name
+			|| desc->bDescriptorType != USB_DT_ENDPOINT
+			|| (maxpacket = le16_to_cpu(desc->wMaxPacketSize)) == 0
+			|| maxpacket > ep->maxpacket) {
+		DBG("bad ep or descriptor\n");
+		return -EINVAL;
+	}
+
+	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) {
+		DBG("bogus device state\n");
+		return -ESHUTDOWN;
+	}
+
+	tmp = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+	switch (tmp) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		DBG("only one control endpoint\n");
+		return -EINVAL;
+	case USB_ENDPOINT_XFER_INT:
+		if (maxpacket > 64)
+			goto bogus_max;
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+		switch (maxpacket) {
+		case 8:
+		case 16:
+		case 32:
+		case 64:
+			goto ok;
+		}
+bogus_max:
+		DBG("bogus maxpacket %d\n", maxpacket);
+		return -EINVAL;
+	case USB_ENDPOINT_XFER_ISOC:
+		if (!ep->is_pingpong) {
+			DBG("iso requires double buffering\n");
+			return -EINVAL;
+		}
+		break;
+	}
+
+ok:
+	local_irq_save(flags);
+
+	/* initialize endpoint to match this descriptor */
+	ep->is_in = (desc->bEndpointAddress & USB_DIR_IN) != 0;
+	ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC);
+	ep->stopped = 0;
+	if (ep->is_in)
+		tmp |= 0x04;
+	tmp <<= 8;
+	tmp |= AT91_UDP_EPEDS;
+	__raw_writel(tmp, ep->creg);
+
+	ep->desc = desc;
+	ep->ep.maxpacket = maxpacket;
+
+	/*
+	 * reset/init endpoint fifo.  NOTE:  leaves fifo_bank alone,
+	 * since endpoint resets don't reset hw pingpong state.
+	 */
+	at91_udp_write(AT91_UDP_RST_EP, ep->int_mask);
+	at91_udp_write(AT91_UDP_RST_EP, 0);
+
+	local_irq_restore(flags);
+	return 0;
+}
+
+static int at91_ep_disable (struct usb_ep * _ep)
+{
+	struct at91_ep	*ep = container_of(_ep, struct at91_ep, ep);
+	unsigned long	flags;
+
+	if (ep == &ep->udc->ep[0])
+		return -EINVAL;
+
+	local_irq_save(flags);
+
+	nuke(ep, -ESHUTDOWN);
+
+	/* restore the endpoint's pristine config */
+	ep->desc = NULL;
+	ep->ep.maxpacket = ep->maxpacket;
+
+	/* reset fifos and endpoint */
+	if (ep->udc->clocked) {
+		at91_udp_write(AT91_UDP_RST_EP, ep->int_mask);
+		at91_udp_write(AT91_UDP_RST_EP, 0);
+		__raw_writel(0, ep->creg);
+	}
+
+	local_irq_restore(flags);
+	return 0;
+}
+
+/*
+ * this is a PIO-only driver, so there's nothing
+ * interesting for request or buffer allocation.
+ */
+
+static struct usb_request *at91_ep_alloc_request (struct usb_ep *_ep, unsigned int gfp_flags)
+{
+	struct at91_request *req;
+
+	req = kcalloc(1, sizeof (struct at91_request), SLAB_KERNEL);
+	if (!req)
+		return NULL;
+
+	INIT_LIST_HEAD(&req->queue);
+	return &req->req;
+}
+
+static void at91_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct at91_request *req;
+
+	req = container_of(_req, struct at91_request, req);
+	BUG_ON(!list_empty(&req->queue));
+	kfree(req);
+}
+
+static void *at91_ep_alloc_buffer(
+	struct usb_ep *_ep,
+	unsigned bytes,
+	dma_addr_t *dma,
+	gfp_t gfp_flags)
+{
+	*dma = ~0;
+	return kmalloc(bytes, gfp_flags);
+}
+
+static void at91_ep_free_buffer(
+	struct usb_ep *ep,
+	void *buf,
+	dma_addr_t dma,
+	unsigned bytes)
+{
+	kfree(buf);
+}
+
+static int at91_ep_queue(struct usb_ep *_ep,
+			struct usb_request *_req, gfp_t gfp_flags)
+{
+	struct at91_request	*req;
+	struct at91_ep		*ep;
+	struct at91_udc		*dev;
+	int			status;
+	unsigned long		flags;
+
+	req = container_of(_req, struct at91_request, req);
+	ep = container_of(_ep, struct at91_ep, ep);
+
+	if (!_req || !_req->complete
+			|| !_req->buf || !list_empty(&req->queue)) {
+		DBG("invalid request\n");
+		return -EINVAL;
+	}
+
+	if (!_ep || (!ep->desc && ep->ep.name != ep0name)) {
+		DBG("invalid ep\n");
+		return -EINVAL;
+	}
+
+	dev = ep->udc;
+
+	if (!dev || !dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) {
+		DBG("invalid device\n");
+		return -EINVAL;
+	}
+
+	_req->status = -EINPROGRESS;
+	_req->actual = 0;
+
+	local_irq_save(flags);
+
+	/* try to kickstart any empty and idle queue */
+	if (list_empty(&ep->queue) && !ep->stopped) {
+		int	is_ep0;
+
+		/*
+		 * If this control request has a non-empty DATA stage, this
+		 * will start that stage.  It works just like a non-control
+		 * request (until the status stage starts, maybe early).
+		 *
+		 * If the data stage is empty, then this starts a successful
+		 * IN/STATUS stage.  (Unsuccessful ones use set_halt.)
+		 */
+		is_ep0 = (ep->ep.name == ep0name);
+		if (is_ep0) {
+			u32	tmp;
+
+			if (!dev->req_pending) {
+				status = -EINVAL;
+				goto done;
+			}
+
+			/*
+			 * defer changing CONFG until after the gadget driver
+			 * reconfigures the endpoints.
+			 */
+			if (dev->wait_for_config_ack) {
+				tmp = at91_udp_read(AT91_UDP_GLB_STAT);
+				tmp ^= AT91_UDP_CONFG;
+				VDBG("toggle config\n");
+				at91_udp_write(AT91_UDP_GLB_STAT, tmp);
+			}
+			if (req->req.length == 0) {
+ep0_in_status:
+				PACKET("ep0 in/status\n");
+				status = 0;
+				tmp = __raw_readl(ep->creg);
+				tmp &= ~SET_FX;
+				tmp |= CLR_FX | AT91_UDP_TXPKTRDY;
+				__raw_writel(tmp, ep->creg);
+				dev->req_pending = 0;
+				goto done;
+			}
+		}
+
+		if (ep->is_in)
+			status = write_fifo(ep, req);
+		else {
+			status = read_fifo(ep, req);
+
+			/* IN/STATUS stage is otherwise triggered by irq */
+			if (status && is_ep0)
+				goto ep0_in_status;
+		}
+	} else
+		status = 0;
+
+	if (req && !status) {
+		list_add_tail (&req->queue, &ep->queue);
+		at91_udp_write(AT91_UDP_IER, ep->int_mask);
+	}
+done:
+	local_irq_restore(flags);
+	return (status < 0) ? status : 0;
+}
+
+static int at91_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct at91_ep	*ep;
+	struct at91_request	*req;
+
+	ep = container_of(_ep, struct at91_ep, ep);
+	if (!_ep || ep->ep.name == ep0name)
+		return -EINVAL;
+
+	/* make sure it's actually queued on this endpoint */
+	list_for_each_entry (req, &ep->queue, queue) {
+		if (&req->req == _req)
+			break;
+	}
+	if (&req->req != _req)
+		return -EINVAL;
+
+	done(ep, req, -ECONNRESET);
+	return 0;
+}
+
+static int at91_ep_set_halt(struct usb_ep *_ep, int value)
+{
+	struct at91_ep	*ep = container_of(_ep, struct at91_ep, ep);
+	u32 __iomem	*creg;
+	u32		csr;
+	unsigned long	flags;
+	int		status = 0;
+
+	if (!_ep || ep->is_iso || !ep->udc->clocked)
+		return -EINVAL;
+
+	creg = ep->creg;
+	local_irq_save(flags);
+
+	csr = __raw_readl(creg);
+
+	/*
+	 * fail with still-busy IN endpoints, ensuring correct sequencing
+	 * of data tx then stall.  note that the fifo rx bytecount isn't
+	 * completely accurate as a tx bytecount.
+	 */
+	if (ep->is_in && (!list_empty(&ep->queue) || (csr >> 16) != 0))
+		status = -EAGAIN;
+	else {
+		csr |= CLR_FX;
+		csr &= ~SET_FX;
+		if (value) {
+			csr |= AT91_UDP_FORCESTALL;
+			VDBG("halt %s\n", ep->ep.name);
+		} else {
+			at91_udp_write(AT91_UDP_RST_EP, ep->int_mask);
+			at91_udp_write(AT91_UDP_RST_EP, 0);
+			csr &= ~AT91_UDP_FORCESTALL;
+		}
+		__raw_writel(csr, creg);
+	}
+
+	local_irq_restore(flags);
+	return status;
+}
+
+static struct usb_ep_ops at91_ep_ops = {
+	.enable		= at91_ep_enable,
+	.disable	= at91_ep_disable,
+	.alloc_request	= at91_ep_alloc_request,
+	.free_request	= at91_ep_free_request,
+	.alloc_buffer	= at91_ep_alloc_buffer,
+	.free_buffer	= at91_ep_free_buffer,
+	.queue		= at91_ep_queue,
+	.dequeue	= at91_ep_dequeue,
+	.set_halt	= at91_ep_set_halt,
+	// there's only imprecise fifo status reporting
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int at91_get_frame(struct usb_gadget *gadget)
+{
+	if (!to_udc(gadget)->clocked)
+		return -EINVAL;
+	return at91_udp_read(AT91_UDP_FRM_NUM) & AT91_UDP_NUM;
+}
+
+static int at91_wakeup(struct usb_gadget *gadget)
+{
+	struct at91_udc	*udc = to_udc(gadget);
+	u32		glbstate;
+	int		status = -EINVAL;
+	unsigned long	flags;
+
+	DBG("%s\n", __FUNCTION__ );
+	local_irq_save(flags);
+
+	if (!udc->clocked || !udc->suspended)
+		goto done;
+
+	/* NOTE:  some "early versions" handle ESR differently ... */
+
+	glbstate = at91_udp_read(AT91_UDP_GLB_STAT);
+	if (!(glbstate & AT91_UDP_ESR))
+		goto done;
+	glbstate |= AT91_UDP_ESR;
+	at91_udp_write(AT91_UDP_GLB_STAT, glbstate);
+
+done:
+	local_irq_restore(flags);
+	return status;
+}
+
+/* reinit == restore inital software state */
+static void udc_reinit(struct at91_udc *udc)
+{
+	u32 i;
+
+	INIT_LIST_HEAD(&udc->gadget.ep_list);
+	INIT_LIST_HEAD(&udc->gadget.ep0->ep_list);
+
+	for (i = 0; i < NUM_ENDPOINTS; i++) {
+		struct at91_ep *ep = &udc->ep[i];
+
+		if (i != 0)
+			list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+		ep->desc = NULL;
+		ep->stopped = 0;
+		ep->fifo_bank = 0;
+		ep->ep.maxpacket = ep->maxpacket;
+		// initialiser une queue par endpoint
+		INIT_LIST_HEAD(&ep->queue);
+	}
+}
+
+static void stop_activity(struct at91_udc *udc)
+{
+	struct usb_gadget_driver *driver = udc->driver;
+	int i;
+
+	if (udc->gadget.speed == USB_SPEED_UNKNOWN)
+		driver = NULL;
+	udc->gadget.speed = USB_SPEED_UNKNOWN;
+
+	for (i = 0; i < NUM_ENDPOINTS; i++) {
+		struct at91_ep *ep = &udc->ep[i];
+		ep->stopped = 1;
+		nuke(ep, -ESHUTDOWN);
+	}
+	if (driver)
+		driver->disconnect(&udc->gadget);
+
+	udc_reinit(udc);
+}
+
+static void clk_on(struct at91_udc *udc)
+{
+	if (udc->clocked)
+		return;
+	udc->clocked = 1;
+	clk_enable(udc->iclk);
+	clk_enable(udc->fclk);
+}
+
+static void clk_off(struct at91_udc *udc)
+{
+	if (!udc->clocked)
+		return;
+	udc->clocked = 0;
+	udc->gadget.speed = USB_SPEED_UNKNOWN;
+	clk_disable(udc->iclk);
+	clk_disable(udc->fclk);
+}
+
+/*
+ * activate/deactivate link with host; minimize power usage for
+ * inactive links by cutting clocks and transceiver power.
+ */
+static void pullup(struct at91_udc *udc, int is_on)
+{
+	if (!udc->enabled || !udc->vbus)
+		is_on = 0;
+	DBG("%sactive\n", is_on ? "" : "in");
+	if (is_on) {
+		clk_on(udc);
+		at91_udp_write(AT91_UDP_TXVC, 0);
+		at91_set_gpio_value(udc->board.pullup_pin, 1);
+	} else  {
+		stop_activity(udc);
+		at91_udp_write(AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
+		at91_set_gpio_value(udc->board.pullup_pin, 0);
+		clk_off(udc);
+
+		// REVISIT:  with transceiver disabled, will D- float
+		// so that a host would falsely detect a device?
+	}
+}
+
+/* vbus is here!  turn everything on that's ready */
+static int at91_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+	struct at91_udc	*udc = to_udc(gadget);
+	unsigned long	flags;
+
+	// VDBG("vbus %s\n", is_active ? "on" : "off");
+	local_irq_save(flags);
+	udc->vbus = (is_active != 0);
+	pullup(udc, is_active);
+	local_irq_restore(flags);
+	return 0;
+}
+
+static int at91_pullup(struct usb_gadget *gadget, int is_on)
+{
+	struct at91_udc	*udc = to_udc(gadget);
+	unsigned long	flags;
+
+	local_irq_save(flags);
+	udc->enabled = is_on = !!is_on;
+	pullup(udc, is_on);
+	local_irq_restore(flags);
+	return 0;
+}
+
+static int at91_set_selfpowered(struct usb_gadget *gadget, int is_on)
+{
+	struct at91_udc	*udc = to_udc(gadget);
+	unsigned long	flags;
+
+	local_irq_save(flags);
+	udc->selfpowered = (is_on != 0);
+	local_irq_restore(flags);
+	return 0;
+}
+
+static const struct usb_gadget_ops at91_udc_ops = {
+	.get_frame		= at91_get_frame,
+	.wakeup			= at91_wakeup,
+	.set_selfpowered	= at91_set_selfpowered,
+	.vbus_session		= at91_vbus_session,
+	.pullup			= at91_pullup,
+
+	/*
+	 * VBUS-powered devices may also also want to support bigger
+	 * power budgets after an appropriate SET_CONFIGURATION.
+	 */
+	// .vbus_power		= at91_vbus_power,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int handle_ep(struct at91_ep *ep)
+{
+	struct at91_request	*req;
+	u32 __iomem		*creg = ep->creg;
+	u32			csr = __raw_readl(creg);
+
+	if (!list_empty(&ep->queue))
+		req = list_entry(ep->queue.next,
+			struct at91_request, queue);
+	else
+		req = NULL;
+
+	if (ep->is_in) {
+		if (csr & (AT91_UDP_STALLSENT | AT91_UDP_TXCOMP)) {
+			csr |= CLR_FX;
+			csr &= ~(SET_FX | AT91_UDP_STALLSENT | AT91_UDP_TXCOMP);
+			__raw_writel(csr, creg);
+		}
+		if (req)
+			return write_fifo(ep, req);
+
+	} else {
+		if (csr & AT91_UDP_STALLSENT) {
+			/* STALLSENT bit == ISOERR */
+			if (ep->is_iso && req)
+				req->req.status = -EILSEQ;
+			csr |= CLR_FX;
+			csr &= ~(SET_FX | AT91_UDP_STALLSENT);
+			__raw_writel(csr, creg);
+			csr = __raw_readl(creg);
+		}
+		if (req && (csr & RX_DATA_READY))
+			return read_fifo(ep, req);
+	}
+	return 0;
+}
+
+union setup {
+	u8			raw[8];
+	struct usb_ctrlrequest	r;
+};
+
+static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
+{
+	u32 __iomem	*creg = ep->creg;
+	u8 __iomem	*dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0));
+	unsigned	rxcount, i = 0;
+	u32		tmp;
+	union setup	pkt;
+	int		status = 0;
+
+	/* read and ack SETUP; hard-fail for bogus packets */
+	rxcount = (csr & AT91_UDP_RXBYTECNT) >> 16;
+	if (likely(rxcount == 8)) {
+		while (rxcount--)
+			pkt.raw[i++] = __raw_readb(dreg);
+		if (pkt.r.bRequestType & USB_DIR_IN) {
+			csr |= AT91_UDP_DIR;
+			ep->is_in = 1;
+		} else {
+			csr &= ~AT91_UDP_DIR;
+			ep->is_in = 0;
+		}
+	} else {
+		// REVISIT this happens sometimes under load; why??
+		ERR("SETUP len %d, csr %08x\n", rxcount, csr);
+		status = -EINVAL;
+	}
+	csr |= CLR_FX;
+	csr &= ~(SET_FX | AT91_UDP_RXSETUP);
+	__raw_writel(csr, creg);
+	udc->wait_for_addr_ack = 0;
+	udc->wait_for_config_ack = 0;
+	ep->stopped = 0;
+	if (unlikely(status != 0))
+		goto stall;
+
+#define w_index		le16_to_cpu(pkt.r.wIndex)
+#define w_value		le16_to_cpu(pkt.r.wValue)
+#define w_length	le16_to_cpu(pkt.r.wLength)
+
+	VDBG("SETUP %02x.%02x v%04x i%04x l%04x\n",
+			pkt.r.bRequestType, pkt.r.bRequest,
+			w_value, w_index, w_length);
+
+	/*
+	 * A few standard requests get handled here, ones that touch
+	 * hardware ... notably for device and endpoint features.
+	 */
+	udc->req_pending = 1;
+	csr = __raw_readl(creg);
+	csr |= CLR_FX;
+	csr &= ~SET_FX;
+	switch ((pkt.r.bRequestType << 8) | pkt.r.bRequest) {
+
+	case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
+			| USB_REQ_SET_ADDRESS:
+		__raw_writel(csr | AT91_UDP_TXPKTRDY, creg);
+		udc->addr = w_value;
+		udc->wait_for_addr_ack = 1;
+		udc->req_pending = 0;
+		/* FADDR is set later, when we ack host STATUS */
+		return;
+
+	case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
+			| USB_REQ_SET_CONFIGURATION:
+		tmp = at91_udp_read(AT91_UDP_GLB_STAT) & AT91_UDP_CONFG;
+		if (pkt.r.wValue)
+			udc->wait_for_config_ack = (tmp == 0);
+		else
+			udc->wait_for_config_ack = (tmp != 0);
+		if (udc->wait_for_config_ack)
+			VDBG("wait for config\n");
+		/* CONFG is toggled later, if gadget driver succeeds */
+		break;
+
+	/*
+	 * Hosts may set or clear remote wakeup status, and
+	 * devices may report they're VBUS powered.
+	 */
+	case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
+			| USB_REQ_GET_STATUS:
+		tmp = (udc->selfpowered << USB_DEVICE_SELF_POWERED);
+		if (at91_udp_read(AT91_UDP_GLB_STAT) & AT91_UDP_ESR)
+			tmp |= (1 << USB_DEVICE_REMOTE_WAKEUP);
+		PACKET("get device status\n");
+		__raw_writeb(tmp, dreg);
+		__raw_writeb(0, dreg);
+		goto write_in;
+		/* then STATUS starts later, automatically */
+	case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
+			| USB_REQ_SET_FEATURE:
+		if (w_value != USB_DEVICE_REMOTE_WAKEUP)
+			goto stall;
+		tmp = at91_udp_read(AT91_UDP_GLB_STAT);
+		tmp |= AT91_UDP_ESR;
+		at91_udp_write(AT91_UDP_GLB_STAT, tmp);
+		goto succeed;
+	case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
+			| USB_REQ_CLEAR_FEATURE:
+		if (w_value != USB_DEVICE_REMOTE_WAKEUP)
+			goto stall;
+		tmp = at91_udp_read(AT91_UDP_GLB_STAT);
+		tmp &= ~AT91_UDP_ESR;
+		at91_udp_write(AT91_UDP_GLB_STAT, tmp);
+		goto succeed;
+
+	/*
+	 * Interfaces have no feature settings; this is pretty useless.
+	 * we won't even insist the interface exists...
+	 */
+	case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE) << 8)
+			| USB_REQ_GET_STATUS:
+		PACKET("get interface status\n");
+		__raw_writeb(0, dreg);
+		__raw_writeb(0, dreg);
+		goto write_in;
+		/* then STATUS starts later, automatically */
+	case ((USB_TYPE_STANDARD|USB_RECIP_INTERFACE) << 8)
+			| USB_REQ_SET_FEATURE:
+	case ((USB_TYPE_STANDARD|USB_RECIP_INTERFACE) << 8)
+			| USB_REQ_CLEAR_FEATURE:
+		goto stall;
+
+	/*
+	 * Hosts may clear bulk/intr endpoint halt after the gadget
+	 * driver sets it (not widely used); or set it (for testing)
+	 */
+	case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT) << 8)
+			| USB_REQ_GET_STATUS:
+		tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
+		ep = &udc->ep[tmp];
+		if (tmp > NUM_ENDPOINTS || (tmp && !ep->desc))
+			goto stall;
+
+		if (tmp) {
+			if ((w_index & USB_DIR_IN)) {
+				if (!ep->is_in)
+					goto stall;
+			} else if (ep->is_in)
+				goto stall;
+		}
+		PACKET("get %s status\n", ep->ep.name);
+		if (__raw_readl(ep->creg) & AT91_UDP_FORCESTALL)
+			tmp = (1 << USB_ENDPOINT_HALT);
+		else
+			tmp = 0;
+		__raw_writeb(tmp, dreg);
+		__raw_writeb(0, dreg);
+		goto write_in;
+		/* then STATUS starts later, automatically */
+	case ((USB_TYPE_STANDARD|USB_RECIP_ENDPOINT) << 8)
+			| USB_REQ_SET_FEATURE:
+		tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
+		ep = &udc->ep[tmp];
+		if (w_value != USB_ENDPOINT_HALT || tmp > NUM_ENDPOINTS)
+			goto stall;
+		if (!ep->desc || ep->is_iso)
+			goto stall;
+		if ((w_index & USB_DIR_IN)) {
+			if (!ep->is_in)
+				goto stall;
+		} else if (ep->is_in)
+			goto stall;
+
+		tmp = __raw_readl(ep->creg);
+		tmp &= ~SET_FX;
+		tmp |= CLR_FX | AT91_UDP_FORCESTALL;
+		__raw_writel(tmp, ep->creg);
+		goto succeed;
+	case ((USB_TYPE_STANDARD|USB_RECIP_ENDPOINT) << 8)
+			| USB_REQ_CLEAR_FEATURE:
+		tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
+		ep = &udc->ep[tmp];
+		if (w_value != USB_ENDPOINT_HALT || tmp > NUM_ENDPOINTS)
+			goto stall;
+		if (tmp == 0)
+			goto succeed;
+		if (!ep->desc || ep->is_iso)
+			goto stall;
+		if ((w_index & USB_DIR_IN)) {
+			if (!ep->is_in)
+				goto stall;
+		} else if (ep->is_in)
+			goto stall;
+
+		at91_udp_write(AT91_UDP_RST_EP, ep->int_mask);
+		at91_udp_write(AT91_UDP_RST_EP, 0);
+		tmp = __raw_readl(ep->creg);
+		tmp |= CLR_FX;
+		tmp &= ~(SET_FX | AT91_UDP_FORCESTALL);
+		__raw_writel(tmp, ep->creg);
+		if (!list_empty(&ep->queue))
+			handle_ep(ep);
+		goto succeed;
+	}
+
+#undef w_value
+#undef w_index
+#undef w_length
+
+	/* pass request up to the gadget driver */
+	status = udc->driver->setup(&udc->gadget, &pkt.r);
+	if (status < 0) {
+stall:
+		VDBG("req %02x.%02x protocol STALL; stat %d\n",
+				pkt.r.bRequestType, pkt.r.bRequest, status);
+		csr |= AT91_UDP_FORCESTALL;
+		__raw_writel(csr, creg);
+		udc->req_pending = 0;
+	}
+	return;
+
+succeed:
+	/* immediate successful (IN) STATUS after zero length DATA */
+	PACKET("ep0 in/status\n");
+write_in:
+	csr |= AT91_UDP_TXPKTRDY;
+	__raw_writel(csr, creg);
+	udc->req_pending = 0;
+	return;
+}
+
+static void handle_ep0(struct at91_udc *udc)
+{
+	struct at91_ep		*ep0 = &udc->ep[0];
+	u32 __iomem		*creg = ep0->creg;
+	u32			csr = __raw_readl(creg);
+	struct at91_request	*req;
+
+	if (unlikely(csr & AT91_UDP_STALLSENT)) {
+		nuke(ep0, -EPROTO);
+		udc->req_pending = 0;
+		csr |= CLR_FX;
+		csr &= ~(SET_FX | AT91_UDP_STALLSENT | AT91_UDP_FORCESTALL);
+		__raw_writel(csr, creg);
+		VDBG("ep0 stalled\n");
+		csr = __raw_readl(creg);
+	}
+	if (csr & AT91_UDP_RXSETUP) {
+		nuke(ep0, 0);
+		udc->req_pending = 0;
+		handle_setup(udc, ep0, csr);
+		return;
+	}
+
+	if (list_empty(&ep0->queue))
+		req = NULL;
+	else
+		req = list_entry(ep0->queue.next, struct at91_request, queue);
+
+	/* host ACKed an IN packet that we sent */
+	if (csr & AT91_UDP_TXCOMP) {
+		csr |= CLR_FX;
+		csr &= ~(SET_FX | AT91_UDP_TXCOMP);
+
+		/* write more IN DATA? */
+		if (req && ep0->is_in) {
+			if (handle_ep(ep0))
+				udc->req_pending = 0;
+
+		/*
+		 * Ack after:
+		 *  - last IN DATA packet (including GET_STATUS)
+		 *  - IN/STATUS for OUT DATA
+		 *  - IN/STATUS for any zero-length DATA stage
+		 * except for the IN DATA case, the host should send
+		 * an OUT status later, which we'll ack.
+		 */
+		} else {
+			udc->req_pending = 0;
+			__raw_writel(csr, creg);
+
+			/*
+			 * SET_ADDRESS takes effect only after the STATUS
+			 * (to the original address) gets acked.
+			 */
+			if (udc->wait_for_addr_ack) {
+				u32	tmp;
+
+				at91_udp_write(AT91_UDP_FADDR, AT91_UDP_FEN | udc->addr);
+				tmp = at91_udp_read(AT91_UDP_GLB_STAT);
+				tmp &= ~AT91_UDP_FADDEN;
+				if (udc->addr)
+					tmp |= AT91_UDP_FADDEN;
+				at91_udp_write(AT91_UDP_GLB_STAT, tmp);
+
+				udc->wait_for_addr_ack = 0;
+				VDBG("address %d\n", udc->addr);
+			}
+		}
+	}
+
+	/* OUT packet arrived ... */
+	else if (csr & AT91_UDP_RX_DATA_BK0) {
+		csr |= CLR_FX;
+		csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0);
+
+		/* OUT DATA stage */
+		if (!ep0->is_in) {
+			if (req) {
+				if (handle_ep(ep0)) {
+					/* send IN/STATUS */
+					PACKET("ep0 in/status\n");
+					csr = __raw_readl(creg);
+					csr &= ~SET_FX;
+					csr |= CLR_FX | AT91_UDP_TXPKTRDY;
+					__raw_writel(csr, creg);
+					udc->req_pending = 0;
+				}
+			} else if (udc->req_pending) {
+				/*
+				 * AT91 hardware has a hard time with this
+				 * "deferred response" mode for control-OUT
+				 * transfers.  (For control-IN it's fine.)
+				 *
+				 * The normal solution leaves OUT data in the
+				 * fifo until the gadget driver is ready.
+				 * We couldn't do that here without disabling
+				 * the IRQ that tells about SETUP packets,
+				 * e.g. when the host gets impatient...
+				 *
+				 * Working around it by copying into a buffer
+				 * would almost be a non-deferred response,
+				 * except that it wouldn't permit reliable
+				 * stalling of the request.  Instead, demand
+				 * that gadget drivers not use this mode.
+				 */
+				DBG("no control-OUT deferred responses!\n");
+				__raw_writel(csr | AT91_UDP_FORCESTALL, creg);
+				udc->req_pending = 0;
+			}
+
+		/* STATUS stage for control-IN; ack.  */
+		} else {
+			PACKET("ep0 out/status ACK\n");
+			__raw_writel(csr, creg);
+
+			/* "early" status stage */
+			if (req)
+				done(ep0, req, 0);
+		}
+	}
+}
+
+static irqreturn_t at91_udc_irq (int irq, void *_udc, struct pt_regs *r)
+{
+	struct at91_udc		*udc = _udc;
+	u32			rescans = 5;
+
+	while (rescans--) {
+		u32	status = at91_udp_read(AT91_UDP_ISR);
+
+		status &= at91_udp_read(AT91_UDP_IMR);
+		if (!status)
+			break;
+
+		/* USB reset irq:  not maskable */
+		if (status & AT91_UDP_ENDBUSRES) {
+			at91_udp_write(AT91_UDP_IDR, ~MINIMUS_INTERRUPTUS);
+			at91_udp_write(AT91_UDP_IER, MINIMUS_INTERRUPTUS);
+			/* Atmel code clears this irq twice */
+			at91_udp_write(AT91_UDP_ICR, AT91_UDP_ENDBUSRES);
+			at91_udp_write(AT91_UDP_ICR, AT91_UDP_ENDBUSRES);
+			VDBG("end bus reset\n");
+			udc->addr = 0;
+			stop_activity(udc);
+
+			/* enable ep0 */
+			at91_udp_write(AT91_UDP_CSR(0), AT91_UDP_EPEDS | AT91_UDP_EPTYPE_CTRL);
+			udc->gadget.speed = USB_SPEED_FULL;
+			udc->suspended = 0;
+			at91_udp_write(AT91_UDP_IER, AT91_UDP_EP(0));
+
+			/*
+			 * NOTE:  this driver keeps clocks off unless the
+			 * USB host is present.  That saves power, and also
+			 * eliminates IRQs (reset, resume, suspend) that can
+			 * otherwise flood from the controller.  If your
+			 * board doesn't support VBUS detection, suspend and
+			 * resume irq logic may need more attention...
+			 */
+
+		/* host initiated suspend (3+ms bus idle) */
+		} else if (status & AT91_UDP_RXSUSP) {
+			at91_udp_write(AT91_UDP_IDR, AT91_UDP_RXSUSP);
+			at91_udp_write(AT91_UDP_IER, AT91_UDP_RXRSM);
+			at91_udp_write(AT91_UDP_ICR, AT91_UDP_RXSUSP);
+			// VDBG("bus suspend\n");
+			if (udc->suspended)
+				continue;
+			udc->suspended = 1;
+
+			/*
+			 * NOTE:  when suspending a VBUS-powered device, the
+			 * gadget driver should switch into slow clock mode
+			 * and then into standby to avoid drawing more than
+			 * 500uA power (2500uA for some high-power configs).
+			 */
+			if (udc->driver && udc->driver->suspend)
+				udc->driver->suspend(&udc->gadget);
+
+		/* host initiated resume */
+		} else if (status & AT91_UDP_RXRSM) {
+			at91_udp_write(AT91_UDP_IDR, AT91_UDP_RXRSM);
+			at91_udp_write(AT91_UDP_IER, AT91_UDP_RXSUSP);
+			at91_udp_write(AT91_UDP_ICR, AT91_UDP_RXRSM);
+			// VDBG("bus resume\n");
+			if (!udc->suspended)
+				continue;
+			udc->suspended = 0;
+
+			/*
+			 * NOTE:  for a VBUS-powered device, the gadget driver
+			 * would normally want to switch out of slow clock
+			 * mode into normal mode.
+			 */
+			if (udc->driver && udc->driver->resume)
+				udc->driver->resume(&udc->gadget);
+
+		/* endpoint IRQs are cleared by handling them */
+		} else {
+			int		i;
+			unsigned	mask = 1;
+			struct at91_ep	*ep = &udc->ep[1];
+
+			if (status & mask)
+				handle_ep0(udc);
+			for (i = 1; i < NUM_ENDPOINTS; i++) {
+				mask <<= 1;
+				if (status & mask)
+					handle_ep(ep);
+				ep++;
+			}
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct at91_udc controller = {
+	.gadget = {
+		.ops = &at91_udc_ops,
+		.ep0 = &controller.ep[0].ep,
+		.name = driver_name,
+		.dev = {
+			.bus_id = "gadget"
+		}
+	},
+	.ep[0] = {
+		.ep = {
+			.name	= ep0name,
+			.ops	= &at91_ep_ops,
+		},
+		.udc		= &controller,
+		.maxpacket	= 8,
+		.creg		= (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(0)),
+		.int_mask	= 1 << 0,
+	},
+	.ep[1] = {
+		.ep = {
+			.name	= "ep1",
+			.ops	= &at91_ep_ops,
+		},
+		.udc		= &controller,
+		.is_pingpong	= 1,
+		.maxpacket	= 64,
+		.creg		= (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(1)),
+		.int_mask	= 1 << 1,
+	},
+	.ep[2] = {
+		.ep = {
+			.name	= "ep2",
+			.ops	= &at91_ep_ops,
+		},
+		.udc		= &controller,
+		.is_pingpong	= 1,
+		.maxpacket	= 64,
+		.creg		= (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(2)),
+		.int_mask	= 1 << 2,
+	},
+	.ep[3] = {
+		.ep = {
+			/* could actually do bulk too */
+			.name	= "ep3-int",
+			.ops	= &at91_ep_ops,
+		},
+		.udc		= &controller,
+		.maxpacket	= 8,
+		.creg		= (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(3)),
+		.int_mask	= 1 << 3,
+	},
+	.ep[4] = {
+		.ep = {
+			.name	= "ep4",
+			.ops	= &at91_ep_ops,
+		},
+		.udc		= &controller,
+		.is_pingpong	= 1,
+		.maxpacket	= 256,
+		.creg		= (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(4)),
+		.int_mask	= 1 << 4,
+	},
+	.ep[5] = {
+		.ep = {
+			.name	= "ep5",
+			.ops	= &at91_ep_ops,
+		},
+		.udc		= &controller,
+		.is_pingpong	= 1,
+		.maxpacket	= 256,
+		.creg		= (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(5)),
+		.int_mask	= 1 << 5,
+	},
+	/* ep6 and ep7 are also reserved */
+};
+
+static irqreturn_t at91_vbus_irq(int irq, void *_udc, struct pt_regs *r)
+{
+	struct at91_udc	*udc = _udc;
+	unsigned	value;
+
+	/* vbus needs at least brief debouncing */
+	udelay(10);
+	value = at91_get_gpio_value(udc->board.vbus_pin);
+	if (value != udc->vbus)
+		at91_vbus_session(&udc->gadget, value);
+
+	return IRQ_HANDLED;
+}
+
+int usb_gadget_register_driver (struct usb_gadget_driver *driver)
+{
+	struct at91_udc	*udc = &controller;
+	int		retval;
+
+	if (!driver
+			|| driver->speed != USB_SPEED_FULL
+			|| !driver->bind
+			|| !driver->unbind
+			|| !driver->setup) {
+		DBG("bad parameter.\n");
+		return -EINVAL;
+	}
+
+	if (udc->driver) {
+		DBG("UDC already has a gadget driver\n");
+		return -EBUSY;
+	}
+
+	udc->driver = driver;
+	udc->gadget.dev.driver = &driver->driver;
+	udc->gadget.dev.driver_data = &driver->driver;
+	udc->enabled = 1;
+	udc->selfpowered = 1;
+
+	retval = driver->bind(&udc->gadget);
+	if (retval) {
+		DBG("driver->bind() returned %d\n", retval);
+		udc->driver = NULL;
+		return retval;
+	}
+
+	local_irq_disable();
+	pullup(udc, 1);
+	local_irq_enable();
+
+	DBG("bound to %s\n", driver->driver.name);
+	return 0;
+}
+EXPORT_SYMBOL (usb_gadget_register_driver);
+
+int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
+{
+	struct at91_udc *udc = &controller;
+
+	if (!driver || driver != udc->driver)
+		return -EINVAL;
+
+	local_irq_disable();
+	udc->enabled = 0;
+	pullup(udc, 0);
+	local_irq_enable();
+
+	driver->unbind(&udc->gadget);
+	udc->driver = NULL;
+
+	DBG("unbound from %s\n", driver->driver.name);
+	return 0;
+}
+EXPORT_SYMBOL (usb_gadget_unregister_driver);
+
+/*-------------------------------------------------------------------------*/
+
+static void at91udc_shutdown(struct platform_device *dev)
+{
+	/* force disconnect on reboot */
+	pullup(platform_get_drvdata(dev), 0);
+}
+
+static int __devinit at91udc_probe(struct platform_device *pdev)
+{
+	struct device	*dev = &pdev->dev;
+	struct at91_udc	*udc;
+	int		retval;
+
+	if (!dev->platform_data) {
+		/* small (so we copy it) but critical! */
+		DBG("missing platform_data\n");
+		return -ENODEV;
+	}
+
+	if (!request_mem_region(AT91_BASE_UDP, SZ_16K, driver_name)) {
+		DBG("someone's using UDC memory\n");
+		return -EBUSY;
+	}
+
+	/* init software state */
+	udc = &controller;
+	udc->gadget.dev.parent = dev;
+	udc->board = *(struct at91_udc_data *) dev->platform_data;
+	udc->pdev = pdev;
+	udc_reinit(udc);
+	udc->enabled = 0;
+
+	/* get interface and function clocks */
+	udc->iclk = clk_get(dev, "udc_clk");
+	udc->fclk = clk_get(dev, "udpck");
+	if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) {
+		DBG("clocks missing\n");
+		return -ENODEV;
+	}
+
+	retval = device_register(&udc->gadget.dev);
+	if (retval < 0)
+		goto fail0;
+
+	/* disable everything until there's a gadget driver and vbus */
+	pullup(udc, 0);
+
+	/* request UDC and maybe VBUS irqs */
+	if (request_irq(AT91_ID_UDP, at91_udc_irq, SA_INTERRUPT, driver_name, udc)) {
+		DBG("request irq %d failed\n", AT91_ID_UDP);
+		retval = -EBUSY;
+		goto fail1;
+	}
+	if (udc->board.vbus_pin > 0) {
+		if (request_irq(udc->board.vbus_pin, at91_vbus_irq, SA_INTERRUPT, driver_name, udc)) {
+			DBG("request vbus irq %d failed\n", udc->board.vbus_pin);
+			free_irq(AT91_ID_UDP, udc);
+			retval = -EBUSY;
+			goto fail1;
+		}
+	} else {
+		DBG("no VBUS detection, assuming always-on\n");
+		udc->vbus = 1;
+	}
+	dev_set_drvdata(dev, udc);
+	create_debug_file(udc);
+
+	INFO("%s version %s\n", driver_name, DRIVER_VERSION);
+	return 0;
+
+fail1:
+	device_unregister(&udc->gadget.dev);
+fail0:
+	release_mem_region(AT91_VA_BASE_UDP, SZ_16K);
+	DBG("%s probe failed, %d\n", driver_name, retval);
+	return retval;
+}
+
+static int __devexit at91udc_remove(struct platform_device *dev)
+{
+	struct at91_udc *udc = platform_get_drvdata(dev);
+
+	DBG("remove\n");
+
+	pullup(udc, 0);
+
+	if (udc->driver != 0)
+		usb_gadget_unregister_driver(udc->driver);
+
+	remove_debug_file(udc);
+	if (udc->board.vbus_pin > 0)
+		free_irq(udc->board.vbus_pin, udc);
+	free_irq(AT91_ID_UDP, udc);
+	device_unregister(&udc->gadget.dev);
+	release_mem_region(AT91_BASE_UDP, SZ_16K);
+
+	clk_put(udc->iclk);
+	clk_put(udc->fclk);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int at91udc_suspend(struct platform_device *dev, u32 state, u32 level)
+{
+	struct at91_udc *udc = platform_get_drvdata(dev);
+
+	/*
+	 * The "safe" suspend transitions are opportunistic ... e.g. when
+	 * the USB link is suspended (48MHz clock autogated off), or when
+	 * it's disconnected (programmatically gated off, elsewhere).
+	 * Then we can suspend, and the chip can enter slow clock mode.
+	 *
+	 * The problem case is some component (user mode?) suspending this
+	 * device while it's active, with the 48 MHz clock in use.  There
+	 * are two basic approaches:  (a) veto suspend levels involving slow
+	 * clock mode, (b) disconnect, so 48 MHz will no longer be in use
+	 * and we can enter slow clock mode.  This uses (b) for now, since
+	 * it's simplest until AT91 PM exists and supports the other option.
+	 */
+	if (udc->vbus && !udc->suspended)
+		pullup(udc, 0);
+	return 0;
+}
+
+static int at91udc_resume(struct platform_device *dev, u32 level)
+{
+	struct at91_udc *udc = platform_get_drvdata(dev);
+
+	/* maybe reconnect to host; if so, clocks on */
+	pullup(udc, 1);
+	return 0;
+}
+#else
+#define	at91udc_suspend	NULL
+#define	at91udc_resume	NULL
+#endif
+
+static struct platform_driver at91_udc = {
+	.probe		= at91udc_probe,
+	.remove		= __devexit_p(at91udc_remove),
+	.shutdown	= at91udc_shutdown,
+	.suspend	= at91udc_suspend,
+	.resume 	= at91udc_resume,
+	.driver		= {
+		.name	= (char *) driver_name,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __devinit udc_init_module(void)
+{
+	return platform_driver_register(&at91_udc);
+}
+module_init(udc_init_module);
+
+static void __devexit udc_exit_module(void)
+{
+	platform_driver_unregister(&at91_udc);
+}
+module_exit(udc_exit_module);
+
+MODULE_DESCRIPTION("AT91RM9200 udc driver");
+MODULE_AUTHOR("Thomas Rathbone, David Brownell");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h
new file mode 100644
index 0000000..5a4799c
--- /dev/null
+++ b/drivers/usb/gadget/at91_udc.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2004 by Thomas Rathbone, HP Labs
+ * Copyright (C) 2005 by Ivan Kokshaysky
+ * Copyright (C) 2006 by SAN People
+ *
+ * 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 AT91_UDC_H
+#define AT91_UDC_H
+
+/*
+ * USB Device Port (UDP) registers.
+ * Based on AT91RM9200 datasheet revision E.
+ */
+
+#define AT91_UDP_FRM_NUM	0x00		/* Frame Number Register */
+#define     AT91_UDP_NUM	(0x7ff <<  0)	/* Frame Number */
+#define     AT91_UDP_FRM_ERR	(1     << 16)	/* Frame Error */
+#define     AT91_UDP_FRM_OK	(1     << 17)	/* Frame OK */
+
+#define AT91_UDP_GLB_STAT	0x04		/* Global State Register */
+#define     AT91_UDP_FADDEN	(1 <<  0)	/* Function Address Enable */
+#define     AT91_UDP_CONFG	(1 <<  1)	/* Configured */
+#define     AT91_UDP_ESR	(1 <<  2)	/* Enable Send Resume */
+#define     AT91_UDP_RSMINPR	(1 <<  3)	/* Resume has been sent */
+#define     AT91_UDP_RMWUPE	(1 <<  4)	/* Remote Wake Up Enable */
+
+#define AT91_UDP_FADDR		0x08		/* Function Address Register */
+#define     AT91_UDP_FADD	(0x7f << 0)	/* Function Address Value */
+#define     AT91_UDP_FEN	(1    << 8)	/* Function Enable */
+
+#define AT91_UDP_IER		0x10		/* Interrupt Enable Register */
+#define AT91_UDP_IDR		0x14		/* Interrupt Disable Register */
+#define AT91_UDP_IMR		0x18		/* Interrupt Mask Register */
+
+#define AT91_UDP_ISR		0x1c		/* Interrupt Status Register */
+#define     AT91_UDP_EP(n)	(1 << (n))	/* Endpoint Interrupt Status */
+#define     AT91_UDP_RXSUSP	(1 <<  8) 	/* USB Suspend Interrupt Status */
+#define     AT91_UDP_RXRSM	(1 <<  9)	/* USB Resume Interrupt Status */
+#define     AT91_UDP_EXTRSM	(1 << 10)	/* External Resume Interrupt Status */
+#define     AT91_UDP_SOFINT	(1 << 11)	/* Start of Frame Interrupt Status */
+#define     AT91_UDP_ENDBUSRES	(1 << 12)	/* End of Bus Reset Interrpt Status */
+#define     AT91_UDP_WAKEUP	(1 << 13)	/* USB Wakeup Interrupt Status */
+
+#define AT91_UDP_ICR		0x20		/* Interrupt Clear Register */
+#define AT91_UDP_RST_EP		0x28		/* Reset Endpoint Register */
+
+#define AT91_UDP_CSR(n)		(0x30+((n)*4))	/* Endpoint Control/Status Registers 0-7 */
+#define     AT91_UDP_TXCOMP	(1 <<  0)	/* Generates IN packet with data previously written in DPR */
+#define     AT91_UDP_RX_DATA_BK0 (1 <<  1)	/* Receive Data Bank 0 */
+#define     AT91_UDP_RXSETUP	(1 <<  2)	/* Send STALL to the host */
+#define     AT91_UDP_STALLSENT	(1 <<  3)	/* Stall Sent / Isochronous error (Isochronous endpoints) */
+#define     AT91_UDP_TXPKTRDY	(1 <<  4)	/* Transmit Packet Ready */
+#define     AT91_UDP_FORCESTALL	(1 <<  5)	/* Force Stall */
+#define     AT91_UDP_RX_DATA_BK1 (1 <<  6)	/* Receive Data Bank 1 */
+#define     AT91_UDP_DIR	(1 <<  7)	/* Transfer Direction */
+#define     AT91_UDP_EPTYPE	(7 <<  8)	/* Endpoint Type */
+#define		AT91_UDP_EPTYPE_CTRL		(0 <<  8)
+#define		AT91_UDP_EPTYPE_ISO_OUT		(1 <<  8)
+#define		AT91_UDP_EPTYPE_BULK_OUT	(2 <<  8)
+#define		AT91_UDP_EPTYPE_INT_OUT		(3 <<  8)
+#define		AT91_UDP_EPTYPE_ISO_IN		(5 <<  8)
+#define		AT91_UDP_EPTYPE_BULK_IN		(6 <<  8)
+#define		AT91_UDP_EPTYPE_INT_IN		(7 <<  8)
+#define     AT91_UDP_DTGLE	(1 << 11)	/* Data Toggle */
+#define     AT91_UDP_EPEDS	(1 << 15)	/* Endpoint Enable/Disable */
+#define     AT91_UDP_RXBYTECNT	(0x7ff << 16)	/* Number of bytes in FIFO */
+
+#define AT91_UDP_FDR(n)		(0x50+((n)*4))	/* Endpoint FIFO Data Registers 0-7 */
+
+#define AT91_UDP_TXVC		0x74		/* Transceiver Control Register */
+#define     AT91_UDP_TXVC_TXVDIS (1 << 8)	/* Transceiver Disable */
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * controller driver data structures
+ */
+
+#define	NUM_ENDPOINTS	6
+
+/*
+ * hardware won't disable bus reset, or resume while the controller
+ * is suspended ... watching suspend helps keep the logic symmetric.
+ */
+#define	MINIMUS_INTERRUPTUS \
+	(AT91_UDP_ENDBUSRES | AT91_UDP_RXRSM | AT91_UDP_RXSUSP)
+
+struct at91_ep {
+	struct usb_ep			ep;
+	struct list_head		queue;
+	struct at91_udc			*udc;
+	void __iomem			*creg;
+
+	unsigned			maxpacket:16;
+	u8				int_mask;
+	unsigned			is_pingpong:1;
+
+	unsigned			stopped:1;
+	unsigned			is_in:1;
+	unsigned			is_iso:1;
+	unsigned			fifo_bank:1;
+
+	const struct usb_endpoint_descriptor
+					*desc;
+};
+
+/*
+ * driver is non-SMP, and just blocks IRQs whenever it needs
+ * access protection for chip registers or driver state
+ */
+struct at91_udc {
+	struct usb_gadget		gadget;
+	struct at91_ep			ep[NUM_ENDPOINTS];
+	struct usb_gadget_driver	*driver;
+	unsigned			vbus:1;
+	unsigned			enabled:1;
+	unsigned			clocked:1;
+	unsigned			suspended:1;
+	unsigned			req_pending:1;
+	unsigned			wait_for_addr_ack:1;
+	unsigned			wait_for_config_ack:1;
+	unsigned			selfpowered:1;
+	u8				addr;
+	struct at91_udc_data		board;
+	struct clk			*iclk, *fclk;
+	struct platform_device		*pdev;
+	struct proc_dir_entry		*pde;
+};
+
+static inline struct at91_udc *to_udc(struct usb_gadget *g)
+{
+	return container_of(g, struct at91_udc, gadget);
+}
+
+struct at91_request {
+	struct usb_request		req;
+	struct list_head		queue;
+};
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+#define DBG(stuff...)		printk(KERN_DEBUG "udc: " stuff)
+#else
+#define DBG(stuff...)		do{}while(0)
+#endif
+
+#ifdef VERBOSE
+#    define VDBG		DBG
+#else
+#    define VDBG(stuff...)	do{}while(0)
+#endif
+
+#ifdef PACKET_TRACE
+#    define PACKET		VDBG
+#else
+#    define PACKET(stuff...)	do{}while(0)
+#endif
+
+#define ERR(stuff...)		printk(KERN_ERR "udc: " stuff)
+#define WARN(stuff...)		printk(KERN_WARNING "udc: " stuff)
+#define INFO(stuff...)		printk(KERN_INFO "udc: " stuff)
+
+#endif
+
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index 9734cb7..42ce41d 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -478,10 +478,9 @@
 		return NULL;
 	ep = usb_ep_to_dummy_ep (_ep);
 
-	req = kmalloc (sizeof *req, mem_flags);
+	req = kzalloc(sizeof(*req), mem_flags);
 	if (!req)
 		return NULL;
-	memset (req, 0, sizeof *req);
 	INIT_LIST_HEAD (&req->queue);
 	return &req->req;
 }
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index afc84cf..c3d8e5c 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -182,33 +182,37 @@
  * parameters are in UTF-8 (superset of ASCII's 7 bit characters).
  */
 
-static ushort __initdata idVendor;
+static ushort idVendor;
 module_param(idVendor, ushort, S_IRUGO);
 MODULE_PARM_DESC(idVendor, "USB Vendor ID");
 
-static ushort __initdata idProduct;
+static ushort idProduct;
 module_param(idProduct, ushort, S_IRUGO);
 MODULE_PARM_DESC(idProduct, "USB Product ID");
 
-static ushort __initdata bcdDevice;
+static ushort bcdDevice;
 module_param(bcdDevice, ushort, S_IRUGO);
 MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
 
-static char *__initdata iManufacturer;
+static char *iManufacturer;
 module_param(iManufacturer, charp, S_IRUGO);
 MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
 
-static char *__initdata iProduct;
+static char *iProduct;
 module_param(iProduct, charp, S_IRUGO);
 MODULE_PARM_DESC(iProduct, "USB Product string");
 
+static char *iSerialNumber;
+module_param(iSerialNumber, charp, S_IRUGO);
+MODULE_PARM_DESC(iSerialNumber, "SerialNumber");
+
 /* initial value, changed by "ifconfig usb0 hw ether xx:xx:xx:xx:xx:xx" */
-static char *__initdata dev_addr;
+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 *__initdata host_addr;
+static char *host_addr;
 module_param(host_addr, charp, S_IRUGO);
 MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
 
@@ -253,6 +257,14 @@
 #define DEV_CONFIG_CDC
 #endif
 
+#ifdef CONFIG_USB_GADGET_MUSBHSFC
+#define DEV_CONFIG_CDC
+#endif
+
+#ifdef CONFIG_USB_GADGET_MUSBHDRC
+#define DEV_CONFIG_CDC
+#endif
+
 
 /* For CDC-incapable hardware, choose the simple cdc subset.
  * Anything that talks bulk (without notable bugs) can do this.
@@ -395,6 +407,7 @@
 #define STRING_CDC			7
 #define STRING_SUBSET			8
 #define STRING_RNDIS			9
+#define STRING_SERIALNUMBER		10
 
 /* holds our biggest descriptor (or RNDIS response) */
 #define USB_BUFSIZ	256
@@ -862,6 +875,7 @@
 
 static char				manufacturer [50];
 static char				product_desc [40] = DRIVER_DESC;
+static char				serial_number [20];
 
 #ifdef	DEV_CONFIG_CDC
 /* address that the host will use ... usually assigned at random */
@@ -872,6 +886,7 @@
 static struct usb_string		strings [] = {
 	{ STRING_MANUFACTURER,	manufacturer, },
 	{ STRING_PRODUCT,	product_desc, },
+	{ STRING_SERIALNUMBER,	serial_number, },
 	{ STRING_DATA,		"Ethernet Data", },
 #ifdef	DEV_CONFIG_CDC
 	{ STRING_CDC,		"CDC Ethernet", },
@@ -1549,7 +1564,8 @@
 {
 	struct eth_dev	*dev = netdev_priv(net);
 
-	// FIXME if rndis, don't change while link's live
+	if (dev->rndis)
+		return -EBUSY;
 
 	if (new_mtu <= ETH_HLEN || new_mtu > ETH_FRAME_LEN)
 		return -ERANGE;
@@ -2116,7 +2132,7 @@
 }
 
 
-static void
+static void __exit
 eth_unbind (struct usb_gadget *gadget)
 {
 	struct eth_dev		*dev = get_gadget_data (gadget);
@@ -2153,7 +2169,7 @@
 	return 0;
 }
 
-static void __init get_ether_addr (const char *str, u8 *dev_addr)
+static int __init get_ether_addr(const char *str, u8 *dev_addr)
 {
 	if (str) {
 		unsigned	i;
@@ -2168,9 +2184,10 @@
 			dev_addr [i] = num;
 		}
 		if (is_valid_ether_addr (dev_addr))
-			return;
+			return 0;
 	}
 	random_ether_addr(dev_addr);
+	return 1;
 }
 
 static int __init
@@ -2268,6 +2285,10 @@
 		strlcpy (manufacturer, iManufacturer, sizeof manufacturer);
 	if (iProduct)
 		strlcpy (product_desc, iProduct, sizeof product_desc);
+	if (iSerialNumber) {
+		device_desc.iSerialNumber = STRING_SERIALNUMBER,
+		strlcpy(serial_number, iSerialNumber, sizeof serial_number);
+	}
 
 	/* all we really need is bulk IN/OUT */
 	usb_ep_autoconfig_reset (gadget);
@@ -2377,9 +2398,13 @@
 	 * The host side address is used with CDC and RNDIS, and commonly
 	 * ends up in a persistent config database.
 	 */
-	get_ether_addr(dev_addr, net->dev_addr);
+	if (get_ether_addr(dev_addr, net->dev_addr))
+		dev_warn(&gadget->dev,
+			"using random %s ethernet address\n", "self");
 	if (cdc || rndis) {
-		get_ether_addr(host_addr, dev->host_mac);
+		if (get_ether_addr(host_addr, dev->host_mac))
+			dev_warn(&gadget->dev,
+				"using random %s ethernet address\n", "host");
 #ifdef	DEV_CONFIG_CDC
 		snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X",
 			dev->host_mac [0], dev->host_mac [1],
@@ -2523,7 +2548,7 @@
 
 	.function	= (char *) driver_desc,
 	.bind		= eth_bind,
-	.unbind		= eth_unbind,
+	.unbind		= __exit_p(eth_unbind),
 
 	.setup		= eth_setup,
 	.disconnect	= eth_disconnect,
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index de59c58..cf3be29 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -3678,7 +3678,7 @@
 	kref_put(&fsg->ref, fsg_release);
 }
 
-static void fsg_unbind(struct usb_gadget *gadget)
+static void __exit fsg_unbind(struct usb_gadget *gadget)
 {
 	struct fsg_dev		*fsg = get_gadget_data(gadget);
 	int			i;
@@ -4064,7 +4064,7 @@
 #endif
 	.function	= (char *) longname,
 	.bind		= fsg_bind,
-	.unbind		= fsg_unbind,
+	.unbind		= __exit_p(fsg_unbind),
 	.disconnect	= fsg_disconnect,
 	.setup		= fsg_setup,
 	.suspend	= fsg_suspend,
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index 8cbae21..c408140 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -3,9 +3,9 @@
  * gadget drivers or other code that needs to deal with them, and which
  * autoconfigures instead of using early binding to the hardware.
  *
- * This could eventually work like the ARM mach_is_*() stuff, driven by
+ * 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 the runtime comparisons in typical one-choice cases.)
+ * (And avoiding all runtime comparisons in typical one-choice configs!)
  *
  * NOTE:  some of these controller drivers may not be available yet.
  */
@@ -93,6 +93,26 @@
 #define gadget_is_imx(g)	0
 #endif
 
+/* Mentor high speed function controller */
+#ifdef CONFIG_USB_GADGET_MUSBHSFC
+#define gadget_is_musbhsfc(g)	!strcmp("musbhsfc_udc", (g)->name)
+#else
+#define gadget_is_musbhsfc(g)	0
+#endif
+
+/* Mentor high speed "dual role" controller, peripheral mode */
+#ifdef CONFIG_USB_GADGET_MUSBHDRC
+#define gadget_is_musbhdrc(g)	!strcmp("musbhdrc_udc", (g)->name)
+#else
+#define gadget_is_musbhdrc(g)	0
+#endif
+
+#ifdef CONFIG_USB_GADGET_MPC8272
+#define gadget_is_mpc8272(g)	!strcmp("mpc8272_udc", (g)->name)
+#else
+#define gadget_is_mpc8272(g)	0
+#endif
+
 // CONFIG_USB_GADGET_SX2
 // CONFIG_USB_GADGET_AU1X00
 // ...
@@ -143,5 +163,11 @@
 		return 0x13;
 	else if (gadget_is_imx(gadget))
 		return 0x14;
+	else if (gadget_is_musbhsfc(gadget))
+		return 0x15;
+	else if (gadget_is_musbhdrc(gadget))
+		return 0x16;
+	else if (gadget_is_mpc8272(gadget))
+		return 0x17;
 	return -ENOENT;
 }
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index b0f3cd6..66b81bb 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -275,11 +275,10 @@
 
 	if (!_ep)
 		return NULL;
-	req = kmalloc(sizeof *req, gfp_flags);
+	req = kzalloc(sizeof *req, gfp_flags);
 	if (!req)
 		return NULL;
 
-	memset(req, 0, sizeof *req);
 	req->req.dma = DMA_ADDR_INVALID;
 	INIT_LIST_HEAD(&req->queue);
 	return &req->req;
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index 0aab7d2..b44cfda 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -170,10 +170,9 @@
 {
 	struct dev_data		*dev;
 
-	dev = kmalloc (sizeof *dev, GFP_KERNEL);
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (!dev)
 		return NULL;
-	memset (dev, 0, sizeof *dev);
 	dev->state = STATE_DEV_DISABLED;
 	atomic_set (&dev->count, 1);
 	spin_lock_init (&dev->lock);
@@ -1592,10 +1591,9 @@
 	gadget_for_each_ep (ep, dev->gadget) {
 		struct ep_data	*data;
 
-		data = kmalloc (sizeof *data, GFP_KERNEL);
+		data = kzalloc(sizeof(*data), GFP_KERNEL);
 		if (!data)
 			goto enomem;
-		memset (data, 0, sizeof data);
 		data->state = STATE_EP_DISABLED;
 		init_MUTEX (&data->lock);
 		init_waitqueue_head (&data->wait);
diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c
index 1a362c5e..0d3424e 100644
--- a/drivers/usb/gadget/lh7a40x_udc.c
+++ b/drivers/usb/gadget/lh7a40x_udc.c
@@ -1114,11 +1114,10 @@
 
 	DEBUG("%s, %p\n", __FUNCTION__, ep);
 
-	req = kmalloc(sizeof *req, gfp_flags);
+	req = kzalloc(sizeof(*req), gfp_flags);
 	if (!req)
 		return 0;
 
-	memset(req, 0, sizeof *req);
 	INIT_LIST_HEAD(&req->queue);
 
 	return &req->req;
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index 67b13ab..fb73dc1 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -386,11 +386,10 @@
 		return NULL;
 	ep = container_of (_ep, struct net2280_ep, ep);
 
-	req = kmalloc (sizeof *req, gfp_flags);
+	req = kzalloc(sizeof(*req), gfp_flags);
 	if (!req)
 		return NULL;
 
-	memset (req, 0, sizeof *req);
 	req->req.dma = DMA_ADDR_INVALID;
 	INIT_LIST_HEAD (&req->queue);
 
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index a8972d7..fbea514 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -273,9 +273,8 @@
 {
 	struct omap_req	*req;
 
-	req = kmalloc(sizeof *req, gfp_flags);
+	req = kzalloc(sizeof(*req), gfp_flags);
 	if (req) {
-		memset (req, 0, sizeof *req);
 		req->req.dma = DMA_ADDR_INVALID;
 		INIT_LIST_HEAD (&req->queue);
 	}
@@ -2586,11 +2585,10 @@
 	/* UDC_PULLUP_EN gates the chip clock */
 	// OTG_SYSCON_1_REG |= DEV_IDLE_EN;
 
-	udc = kmalloc (sizeof *udc, SLAB_KERNEL);
+	udc = kzalloc(sizeof(*udc), SLAB_KERNEL);
 	if (!udc)
 		return -ENOMEM;
 
-	memset(udc, 0, sizeof *udc);
 	spin_lock_init (&udc->lock);
 
 	udc->gadget.ops = &omap_gadget_ops;
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
index bb028c5..680f7fc 100644
--- a/drivers/usb/gadget/pxa2xx_udc.c
+++ b/drivers/usb/gadget/pxa2xx_udc.c
@@ -335,11 +335,10 @@
 {
 	struct pxa2xx_request *req;
 
-	req = kmalloc (sizeof *req, gfp_flags);
+	req = kzalloc(sizeof(*req), gfp_flags);
 	if (!req)
 		return NULL;
 
-	memset (req, 0, sizeof *req);
 	INIT_LIST_HEAD (&req->queue);
 	return &req->req;
 }
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index ba9acd5..b992546 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -369,7 +369,7 @@
 #endif /* CONFIG_USB_GADGET_DUALSPEED */
 	.function =		GS_LONG_NAME,
 	.bind =			gs_bind,
-	.unbind =		gs_unbind,
+	.unbind =		__exit_p(gs_unbind),
 	.setup =		gs_setup,
 	.disconnect =		gs_disconnect,
 	.driver = {
@@ -1413,7 +1413,7 @@
  * Called on module load.  Allocates and initializes the device
  * structure and a control request.
  */
-static int gs_bind(struct usb_gadget *gadget)
+static int __init gs_bind(struct usb_gadget *gadget)
 {
 	int ret;
 	struct usb_ep *ep;
@@ -1538,7 +1538,7 @@
  * Called on module unload.  Frees the control request and device
  * structure.
  */
-static void gs_unbind(struct usb_gadget *gadget)
+static void __exit gs_unbind(struct usb_gadget *gadget)
 {
 	struct gs_dev *dev = get_gadget_data(gadget);
 
@@ -2178,10 +2178,9 @@
 		return -EIO;
 
 	for (i=0; i<GS_NUM_PORTS; i++) {
-		if ((port=(struct gs_port *)kmalloc(sizeof(struct gs_port), kmalloc_flags)) == NULL)
+		if ((port=kzalloc(sizeof(struct gs_port), kmalloc_flags)) == NULL)
 			return -ENOMEM;
 
-		memset(port, 0, sizeof(struct gs_port));
 		port->port_dev = dev;
 		port->port_num = i;
 		port->port_line_coding.dwDTERate = cpu_to_le32(GS_DEFAULT_DTE_RATE);
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index ae7a1c0..51424f6 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -1119,7 +1119,7 @@
 
 /*-------------------------------------------------------------------------*/
 
-static void
+static void __exit
 zero_unbind (struct usb_gadget *gadget)
 {
 	struct zero_dev		*dev = get_gadget_data (gadget);
@@ -1136,7 +1136,7 @@
 	set_gadget_data (gadget, NULL);
 }
 
-static int
+static int __init
 zero_bind (struct usb_gadget *gadget)
 {
 	struct zero_dev		*dev;
@@ -1188,10 +1188,9 @@
 
 
 	/* ok, we made sense of the hardware ... */
-	dev = kmalloc (sizeof *dev, SLAB_KERNEL);
+	dev = kzalloc(sizeof(*dev), SLAB_KERNEL);
 	if (!dev)
 		return -ENOMEM;
-	memset (dev, 0, sizeof *dev);
 	spin_lock_init (&dev->lock);
 	dev->gadget = gadget;
 	set_gadget_data (gadget, dev);
@@ -1224,12 +1223,6 @@
 		loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 	}
 
-	if (gadget->is_otg) {
-		otg_descriptor.bmAttributes |= USB_OTG_HNP,
-		source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-		loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-	}
-
 	usb_gadget_set_selfpowered (gadget);
 
 	init_timer (&dev->resume);
@@ -1294,7 +1287,7 @@
 #endif
 	.function	= (char *) longname,
 	.bind		= zero_bind,
-	.unbind		= zero_unbind,
+	.unbind		= __exit_p(zero_unbind),
 
 	.setup		= zero_setup,
 	.disconnect	= zero_disconnect,
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index be3fd9b..e27b79a3 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -6,7 +6,7 @@
 
 config USB_EHCI_HCD
 	tristate "EHCI HCD (USB 2.0) support"
-	depends on USB && PCI
+	depends on USB && USB_ARCH_HAS_EHCI
 	---help---
 	  The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0
 	  "high speed" (480 Mbit/sec, 60 Mbyte/sec) host controller hardware.
diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c
new file mode 100644
index 0000000..63eadee
--- /dev/null
+++ b/drivers/usb/host/ehci-au1xxx.c
@@ -0,0 +1,297 @@
+/*
+ * EHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 2000-2004 David Brownell <dbrownell@users.sourceforge.net>
+ *
+ * Bus Glue for AMD Alchemy Au1xxx
+ *
+ * Based on "ohci-au1xxx.c" by Matt Porter <mporter@kernel.crashing.org>
+ *
+ * Modified for AMD Alchemy Au1200 EHC
+ *  by K.Boge <karsten.boge@amd.com>
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <linux/platform_device.h>
+#include <asm/mach-au1x00/au1000.h>
+
+#ifndef CONFIG_SOC_AU1200
+#error "this Alchemy chip doesn't have EHCI"
+#else				/* Au1200 */
+
+#define USB_HOST_CONFIG   (USB_MSR_BASE + USB_MSR_MCFG)
+#define USB_MCFG_PFEN     (1<<31)
+#define USB_MCFG_RDCOMB   (1<<30)
+#define USB_MCFG_SSDEN    (1<<23)
+#define USB_MCFG_PHYPLLEN (1<<19)
+#define USB_MCFG_EHCCLKEN (1<<17)
+#define USB_MCFG_UCAM     (1<<7)
+#define USB_MCFG_EBMEN    (1<<3)
+#define USB_MCFG_EMEMEN   (1<<2)
+
+#define USBH_ENABLE_CE    (USB_MCFG_PHYPLLEN | USB_MCFG_EHCCLKEN)
+
+#ifdef CONFIG_DMA_COHERENT
+#define USBH_ENABLE_INIT  (USBH_ENABLE_CE \
+                         | USB_MCFG_PFEN | USB_MCFG_RDCOMB \
+                         | USB_MCFG_SSDEN | USB_MCFG_UCAM \
+                         | USB_MCFG_EBMEN | USB_MCFG_EMEMEN)
+#else
+#define USBH_ENABLE_INIT  (USBH_ENABLE_CE \
+                         | USB_MCFG_PFEN | USB_MCFG_RDCOMB \
+                         | USB_MCFG_SSDEN \
+                         | USB_MCFG_EBMEN | USB_MCFG_EMEMEN)
+#endif
+#define USBH_DISABLE      (USB_MCFG_EBMEN | USB_MCFG_EMEMEN)
+
+#endif				/* Au1200 */
+
+extern int usb_disabled(void);
+
+/*-------------------------------------------------------------------------*/
+
+static void au1xxx_start_ehc(struct platform_device *dev)
+{
+	pr_debug(__FILE__ ": starting Au1xxx EHCI USB Controller\n");
+
+	/* write HW defaults again in case Yamon cleared them */
+	if (au_readl(USB_HOST_CONFIG) == 0) {
+		au_writel(0x00d02000, USB_HOST_CONFIG);
+		au_readl(USB_HOST_CONFIG);
+		udelay(1000);
+	}
+	/* enable host controller */
+	au_writel(USBH_ENABLE_CE | au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
+	au_readl(USB_HOST_CONFIG);
+	udelay(1000);
+	au_writel(USBH_ENABLE_INIT | au_readl(USB_HOST_CONFIG),
+		  USB_HOST_CONFIG);
+	au_readl(USB_HOST_CONFIG);
+	udelay(1000);
+
+	pr_debug(__FILE__ ": Clock to USB host has been enabled\n");
+}
+
+static void au1xxx_stop_ehc(struct platform_device *dev)
+{
+	pr_debug(__FILE__ ": stopping Au1xxx EHCI USB Controller\n");
+
+	/* Disable mem */
+	au_writel(~USBH_DISABLE & au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
+	udelay(1000);
+	/* Disable clock */
+	au_writel(~USB_MCFG_EHCCLKEN & au_readl(USB_HOST_CONFIG),
+		  USB_HOST_CONFIG);
+	au_readl(USB_HOST_CONFIG);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+/**
+ * usb_ehci_au1xxx_probe - initialize Au1xxx-based HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ */
+int usb_ehci_au1xxx_probe(const struct hc_driver *driver,
+			  struct usb_hcd **hcd_out, struct platform_device *dev)
+{
+	int retval;
+	struct usb_hcd *hcd;
+	struct ehci_hcd *ehci;
+
+#if defined(CONFIG_SOC_AU1200) && defined(CONFIG_DMA_COHERENT)
+
+	/* Au1200 AB USB does not support coherent memory */
+	if (!(read_c0_prid() & 0xff)) {
+		pr_info("%s: this is chip revision AB!\n", dev->dev.name);
+		pr_info("%s: update your board or re-configure the kernel\n",
+			dev->dev.name);
+		return -ENODEV;
+	}
+#endif
+
+	au1xxx_start_ehc(dev);
+
+	if (dev->resource[1].flags != IORESOURCE_IRQ) {
+		pr_debug("resource[1] is not IORESOURCE_IRQ");
+		retval = -ENOMEM;
+	}
+	hcd = usb_create_hcd(driver, &dev->dev, "Au1xxx");
+	if (!hcd)
+		return -ENOMEM;
+	hcd->rsrc_start = dev->resource[0].start;
+	hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+		pr_debug("request_mem_region failed");
+		retval = -EBUSY;
+		goto err1;
+	}
+
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs) {
+		pr_debug("ioremap failed");
+		retval = -ENOMEM;
+		goto err2;
+	}
+
+	ehci = hcd_to_ehci(hcd);
+	ehci->caps = hcd->regs;
+	ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
+	/* cache this readonly data; minimize chip reads */
+	ehci->hcs_params = readl(&ehci->caps->hcs_params);
+
+	/* ehci_hcd_init(hcd_to_ehci(hcd)); */
+
+	retval =
+	    usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT | SA_SHIRQ);
+	if (retval == 0)
+		return retval;
+
+	au1xxx_stop_ehc(dev);
+	iounmap(hcd->regs);
+err2:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err1:
+	usb_put_hcd(hcd);
+	return retval;
+}
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_ehci_hcd_au1xxx_remove - shutdown processing for Au1xxx-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_ehci_hcd_au1xxx_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ */
+void usb_ehci_au1xxx_remove(struct usb_hcd *hcd, struct platform_device *dev)
+{
+	usb_remove_hcd(hcd);
+	iounmap(hcd->regs);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
+	au1xxx_stop_ehc(dev);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ehci_au1xxx_hc_driver = {
+	.description = hcd_name,
+	.product_desc = "Au1xxx EHCI",
+	.hcd_priv_size = sizeof(struct ehci_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq = ehci_irq,
+	.flags = HCD_MEMORY | HCD_USB2,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.reset = ehci_init,
+	.start = ehci_run,
+	.stop = ehci_stop,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue = ehci_urb_enqueue,
+	.urb_dequeue = ehci_urb_dequeue,
+	.endpoint_disable = ehci_endpoint_disable,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number = ehci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data = ehci_hub_status_data,
+	.hub_control = ehci_hub_control,
+#ifdef	CONFIG_PM
+	.hub_suspend = ehci_hub_suspend,
+	.hub_resume = ehci_hub_resume,
+#endif
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int ehci_hcd_au1xxx_drv_probe(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct usb_hcd *hcd = NULL;
+	int ret;
+
+	pr_debug("In ehci_hcd_au1xxx_drv_probe\n");
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	ret = usb_ehci_au1xxx_probe(&ehci_au1xxx_hc_driver, &hcd, pdev);
+	return ret;
+}
+
+static int ehci_hcd_au1xxx_drv_remove(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+	usb_ehci_au1xxx_remove(hcd, pdev);
+	return 0;
+}
+
+ /*TBD*/
+/*static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+	return 0;
+}
+static int ehci_hcd_au1xxx_drv_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+	return 0;
+}
+*/
+static struct device_driver ehci_hcd_au1xxx_driver = {
+	.name = "au1xxx-ehci",
+	.bus = &platform_bus_type,
+	.probe = ehci_hcd_au1xxx_drv_probe,
+	.remove = ehci_hcd_au1xxx_drv_remove,
+	/*.suspend      = ehci_hcd_au1xxx_drv_suspend, */
+	/*.resume       = ehci_hcd_au1xxx_drv_resume, */
+};
+
+static int __init ehci_hcd_au1xxx_init(void)
+{
+	pr_debug(DRIVER_INFO " (Au1xxx)\n");
+
+	return driver_register(&ehci_hcd_au1xxx_driver);
+}
+
+static void __exit ehci_hcd_au1xxx_cleanup(void)
+{
+	driver_unregister(&ehci_hcd_au1xxx_driver);
+}
+
+module_init(ehci_hcd_au1xxx_init);
+module_exit(ehci_hcd_au1xxx_cleanup);
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
new file mode 100644
index 0000000..f985f121
--- /dev/null
+++ b/drivers/usb/host/ehci-fsl.c
@@ -0,0 +1,366 @@
+/*
+ * (C) Copyright David Brownell 2000-2002
+ * Copyright (c) 2005 MontaVista Software
+ *
+ * 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.
+ *
+ * Ported to 834x by Randy Vinson <rvinson@mvista.com> using code provided
+ * by Hunter Wu.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/fsl_devices.h>
+
+#include "ehci-fsl.h"
+
+/* FIXME: Power Managment is un-ported so temporarily disable it */
+#undef CONFIG_PM
+
+/* PCI-based HCs are common, but plenty of non-PCI HCs are used too */
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+/**
+ * usb_hcd_fsl_probe - initialize FSL-based HCDs
+ * @drvier: Driver to be used for this HCD
+ * @pdev: USB Host Controller being probed
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller.
+ *
+ */
+int usb_hcd_fsl_probe(const struct hc_driver *driver,
+		      struct platform_device *pdev)
+{
+	struct fsl_usb2_platform_data *pdata;
+	struct usb_hcd *hcd;
+	struct resource *res;
+	int irq;
+	int retval;
+	unsigned int temp;
+
+	pr_debug("initializing FSL-SOC USB Controller\n");
+
+	/* Need platform data for setup */
+	pdata = (struct fsl_usb2_platform_data *)pdev->dev.platform_data;
+	if (!pdata) {
+		dev_err(&pdev->dev,
+			"No platform data for %s.\n", pdev->dev.bus_id);
+		return -ENODEV;
+	}
+
+	/*
+	 * This is a host mode driver, verify that we're supposed to be
+	 * in host mode.
+	 */
+	if (!((pdata->operating_mode == FSL_USB2_DR_HOST) ||
+	      (pdata->operating_mode == FSL_USB2_MPH_HOST))) {
+		dev_err(&pdev->dev,
+			"Non Host Mode configured for %s. Wrong driver linked.\n",
+			pdev->dev.bus_id);
+		return -ENODEV;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res) {
+		dev_err(&pdev->dev,
+			"Found HC with no IRQ. Check %s setup!\n",
+			pdev->dev.bus_id);
+		return -ENODEV;
+	}
+	irq = res->start;
+
+	hcd = usb_create_hcd(driver, &pdev->dev, pdev->dev.bus_id);
+	if (!hcd) {
+		retval = -ENOMEM;
+		goto err1;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev,
+			"Found HC with no register addr. Check %s setup!\n",
+			pdev->dev.bus_id);
+		retval = -ENODEV;
+		goto err2;
+	}
+	hcd->rsrc_start = res->start;
+	hcd->rsrc_len = res->end - res->start + 1;
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
+				driver->description)) {
+		dev_dbg(&pdev->dev, "controller already in use\n");
+		retval = -EBUSY;
+		goto err2;
+	}
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+
+	if (hcd->regs == NULL) {
+		dev_dbg(&pdev->dev, "error mapping memory\n");
+		retval = -EFAULT;
+		goto err3;
+	}
+
+	/* Enable USB controller */
+	temp = in_be32(hcd->regs + 0x500);
+	out_be32(hcd->regs + 0x500, temp | 0x4);
+
+	/* Set to Host mode */
+	temp = in_le32(hcd->regs + 0x1a8);
+	out_le32(hcd->regs + 0x1a8, temp | 0x3);
+
+	retval = usb_add_hcd(hcd, irq, SA_SHIRQ);
+	if (retval != 0)
+		goto err4;
+	return retval;
+
+      err4:
+	iounmap(hcd->regs);
+      err3:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+      err2:
+	usb_put_hcd(hcd);
+      err1:
+	dev_err(&pdev->dev, "init %s fail, %d\n", pdev->dev.bus_id, retval);
+	return retval;
+}
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_fsl_remove - shutdown processing for FSL-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_fsl_probe().
+ *
+ */
+void usb_hcd_fsl_remove(struct usb_hcd *hcd, struct platform_device *pdev)
+{
+	usb_remove_hcd(hcd);
+	iounmap(hcd->regs);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
+}
+
+static void mpc83xx_setup_phy(struct ehci_hcd *ehci,
+			      enum fsl_usb2_phy_modes phy_mode,
+			      unsigned int port_offset)
+{
+	u32 portsc = 0;
+	switch (phy_mode) {
+	case FSL_USB2_PHY_ULPI:
+		portsc |= PORT_PTS_ULPI;
+		break;
+	case FSL_USB2_PHY_SERIAL:
+		portsc |= PORT_PTS_SERIAL;
+		break;
+	case FSL_USB2_PHY_UTMI_WIDE:
+		portsc |= PORT_PTS_PTW;
+		/* fall through */
+	case FSL_USB2_PHY_UTMI:
+		portsc |= PORT_PTS_UTMI;
+		break;
+	case FSL_USB2_PHY_NONE:
+		break;
+	}
+	writel(portsc, &ehci->regs->port_status[port_offset]);
+}
+
+static void mpc83xx_usb_setup(struct usb_hcd *hcd)
+{
+	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+	struct fsl_usb2_platform_data *pdata;
+	void __iomem *non_ehci = hcd->regs;
+
+	pdata =
+	    (struct fsl_usb2_platform_data *)hcd->self.controller->
+	    platform_data;
+	/* Enable PHY interface in the control reg. */
+	out_be32(non_ehci + FSL_SOC_USB_CTRL, 0x00000004);
+	out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0000001b);
+
+	if (pdata->operating_mode == FSL_USB2_DR_HOST)
+		mpc83xx_setup_phy(ehci, pdata->phy_mode, 0);
+
+	if (pdata->operating_mode == FSL_USB2_MPH_HOST) {
+		unsigned int chip, rev, svr;
+
+		svr = mfspr(SPRN_SVR);
+		chip = svr >> 16;
+		rev = (svr >> 4) & 0xf;
+
+		/* Deal with USB Erratum #14 on MPC834x Rev 1.0 & 1.1 chips */
+		if ((rev == 1) && (chip >= 0x8050) && (chip <= 0x8055))
+			ehci->has_fsl_port_bug = 1;
+
+		if (pdata->port_enables & FSL_USB2_PORT0_ENABLED)
+			mpc83xx_setup_phy(ehci, pdata->phy_mode, 0);
+		if (pdata->port_enables & FSL_USB2_PORT1_ENABLED)
+			mpc83xx_setup_phy(ehci, pdata->phy_mode, 1);
+	}
+
+	/* put controller in host mode. */
+	writel(0x00000003, non_ehci + FSL_SOC_USB_USBMODE);
+	out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c);
+	out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040);
+	out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
+}
+
+/* called after powerup, by probe or system-pm "wakeup" */
+static int ehci_fsl_reinit(struct ehci_hcd *ehci)
+{
+	mpc83xx_usb_setup(ehci_to_hcd(ehci));
+	ehci_port_power(ehci, 0);
+
+	return 0;
+}
+
+/* called during probe() after chip reset completes */
+static int ehci_fsl_setup(struct usb_hcd *hcd)
+{
+	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+	int retval;
+
+	/* EHCI registers start at offset 0x100 */
+	ehci->caps = hcd->regs + 0x100;
+	ehci->regs = hcd->regs + 0x100 +
+	    HC_LENGTH(readl(&ehci->caps->hc_capbase));
+	dbg_hcs_params(ehci, "reset");
+	dbg_hcc_params(ehci, "reset");
+
+	/* cache this readonly data; minimize chip reads */
+	ehci->hcs_params = readl(&ehci->caps->hcs_params);
+
+	retval = ehci_halt(ehci);
+	if (retval)
+		return retval;
+
+	/* data structure init */
+	retval = ehci_init(hcd);
+	if (retval)
+		return retval;
+
+	ehci->is_tdi_rh_tt = 1;
+
+	ehci->sbrn = 0x20;
+
+	ehci_reset(ehci);
+
+	retval = ehci_fsl_reinit(ehci);
+	return retval;
+}
+
+static const struct hc_driver ehci_fsl_hc_driver = {
+	.description = hcd_name,
+	.product_desc = "Freescale On-Chip EHCI Host Controller",
+	.hcd_priv_size = sizeof(struct ehci_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq = ehci_irq,
+	.flags = HCD_USB2,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.reset = ehci_fsl_setup,
+	.start = ehci_run,
+#ifdef	CONFIG_PM
+	.suspend = ehci_bus_suspend,
+	.resume = ehci_bus_resume,
+#endif
+	.stop = ehci_stop,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue = ehci_urb_enqueue,
+	.urb_dequeue = ehci_urb_dequeue,
+	.endpoint_disable = ehci_endpoint_disable,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number = ehci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data = ehci_hub_status_data,
+	.hub_control = ehci_hub_control,
+	.bus_suspend = ehci_bus_suspend,
+	.bus_resume = ehci_bus_resume,
+};
+
+static int ehci_fsl_drv_probe(struct platform_device *pdev)
+{
+	if (usb_disabled())
+		return -ENODEV;
+
+	return usb_hcd_fsl_probe(&ehci_fsl_hc_driver, pdev);
+}
+
+static int ehci_fsl_drv_remove(struct platform_device *pdev)
+{
+	struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+	usb_hcd_fsl_remove(hcd, pdev);
+
+	return 0;
+}
+
+static struct platform_driver ehci_fsl_dr_driver = {
+	.probe = ehci_fsl_drv_probe,
+	.remove = ehci_fsl_drv_remove,
+	.driver = {
+		   .name = "fsl-usb2-dr",
+		   },
+};
+
+static struct platform_driver ehci_fsl_mph_driver = {
+	.probe = ehci_fsl_drv_probe,
+	.remove = ehci_fsl_drv_remove,
+	.driver = {
+		   .name = "fsl-usb2-mph",
+		   },
+};
+
+static int __init ehci_fsl_init(void)
+{
+	int retval;
+
+	pr_debug("%s: block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd\n",
+		 hcd_name,
+		 sizeof(struct ehci_qh), sizeof(struct ehci_qtd),
+		 sizeof(struct ehci_itd), sizeof(struct ehci_sitd));
+
+	retval = platform_driver_register(&ehci_fsl_dr_driver);
+	if (retval)
+		return retval;
+
+	return platform_driver_register(&ehci_fsl_mph_driver);
+}
+
+static void __exit ehci_fsl_cleanup(void)
+{
+	platform_driver_unregister(&ehci_fsl_mph_driver);
+	platform_driver_unregister(&ehci_fsl_dr_driver);
+}
+
+module_init(ehci_fsl_init);
+module_exit(ehci_fsl_cleanup);
diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h
new file mode 100644
index 0000000..caac0d1
--- /dev/null
+++ b/drivers/usb/host/ehci-fsl.h
@@ -0,0 +1,37 @@
+/* Copyright (c) 2005 freescale semiconductor
+ * Copyright (c) 2005 MontaVista Software
+ *
+ * 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 _EHCI_FSL_H
+#define _EHCI_FSL_H
+
+/* offsets for the non-ehci registers in the FSL SOC USB controller */
+#define FSL_SOC_USB_ULPIVP	0x170
+#define FSL_SOC_USB_PORTSC1	0x184
+#define PORT_PTS_MSK		(3<<30)
+#define PORT_PTS_UTMI		(0<<30)
+#define PORT_PTS_ULPI		(2<<30)
+#define	PORT_PTS_SERIAL		(3<<30)
+#define PORT_PTS_PTW		(1<<28)
+#define FSL_SOC_USB_PORTSC2	0x188
+#define FSL_SOC_USB_USBMODE	0x1a8
+#define FSL_SOC_USB_SNOOP1	0x400	/* NOTE: big-endian */
+#define FSL_SOC_USB_SNOOP2	0x404	/* NOTE: big-endian */
+#define FSL_SOC_USB_AGECNTTHRSH	0x408	/* NOTE: big-endian */
+#define FSL_SOC_USB_SICTRL	0x40c	/* NOTE: big-endian */
+#define FSL_SOC_USB_PRICTRL	0x410	/* NOTE: big-endian */
+#define FSL_SOC_USB_CTRL	0x500	/* NOTE: big-endian */
+#endif				/* _EHCI_FSL_H */
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 9dd3d14..79f2d8b 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -889,8 +889,19 @@
 
 #ifdef CONFIG_PCI
 #include "ehci-pci.c"
+#define	EHCI_BUS_GLUED
 #endif
 
-#if !defined(CONFIG_PCI)
+#ifdef CONFIG_PPC_83xx
+#include "ehci-fsl.c"
+#define	EHCI_BUS_GLUED
+#endif
+
+#ifdef CONFIG_SOC_AU1X00
+#include "ehci-au1xxx.c"
+#define	EHCI_BUS_GLUED
+#endif
+
+#ifndef	EHCI_BUS_GLUED
 #error "missing bus glue for ehci-hcd"
 #endif
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 69b0b9b..d03e3ca 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -359,6 +359,8 @@
 		case USB_PORT_FEAT_SUSPEND:
 			if (temp & PORT_RESET)
 				goto error;
+			if (ehci->no_selective_suspend)
+				break;
 			if (temp & PORT_SUSPEND) {
 				if ((temp & PORT_PE) == 0)
 					goto error;
@@ -514,6 +516,8 @@
 		temp &= ~PORT_RWC_BITS;
 		switch (wValue) {
 		case USB_PORT_FEAT_SUSPEND:
+			if (ehci->no_selective_suspend)
+				break;
 			if ((temp & PORT_PE) == 0
 					|| (temp & PORT_RESET) != 0)
 				goto error;
diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c
index 91c2ab4..766061e 100644
--- a/drivers/usb/host/ehci-mem.c
+++ b/drivers/usb/host/ehci-mem.c
@@ -75,7 +75,6 @@
 	}
 	if (qh->dummy)
 		ehci_qtd_free (ehci, qh->dummy);
-	usb_put_dev (qh->dev);
 	dma_pool_free (ehci->qh_pool, qh, qh->qh_dma);
 }
 
@@ -221,13 +220,9 @@
 		ehci->periodic [i] = EHCI_LIST_END;
 
 	/* software shadow of hardware table */
-	ehci->pshadow = kmalloc (ehci->periodic_size * sizeof (void *), flags);
-	if (ehci->pshadow == NULL) {
-		goto fail;
-	}
-	memset (ehci->pshadow, 0, ehci->periodic_size * sizeof (void *));
-
-	return 0;
+	ehci->pshadow = kcalloc(ehci->periodic_size, sizeof(void *), flags);
+	if (ehci->pshadow != NULL)
+		return 0;
 
 fail:
 	ehci_dbg (ehci, "couldn't init memory\n");
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 3a6687d..1e03f1a 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -106,11 +106,11 @@
 		}
 		break;
 	case PCI_VENDOR_ID_NVIDIA:
+		switch (pdev->device) {
 		/* NVidia reports that certain chips don't handle
 		 * QH, ITD, or SITD addresses above 2GB.  (But TD,
 		 * data buffer, and periodic schedule are normal.)
 		 */
-		switch (pdev->device) {
 		case 0x003c:	/* MCP04 */
 		case 0x005b:	/* CK804 */
 		case 0x00d8:	/* CK8 */
@@ -120,6 +120,14 @@
 				ehci_warn(ehci, "can't enable NVidia "
 					"workaround for >2GB RAM\n");
 			break;
+		/* Some NForce2 chips have problems with selective suspend;
+		 * fixed in newer silicon.
+		 */
+		case 0x0068:
+			pci_read_config_dword(pdev, PCI_REVISION_ID, &temp);
+			if ((temp & 0xff) < 0xa4)
+				ehci->no_selective_suspend = 1;
+			break;
 		}
 		break;
 	}
@@ -163,6 +171,21 @@
 			device_init_wakeup(&pdev->dev, 1);
 	}
 
+#ifdef	CONFIG_USB_SUSPEND
+	/* REVISIT: the controller works fine for wakeup iff the root hub
+	 * itself is "globally" suspended, but usbcore currently doesn't
+	 * understand such things.
+	 *
+	 * System suspend currently expects to be able to suspend the entire
+	 * device tree, device-at-a-time.  If we failed selective suspend
+	 * reports, system suspend would fail; so the root hub code must claim
+	 * success.  That's lying to usbcore, and it matters for for runtime
+	 * PM scenarios with selective suspend and remote wakeup...
+	 */
+	if (ehci->no_selective_suspend && device_can_wakeup(&pdev->dev))
+		ehci_warn(ehci, "selective suspend/wakeup unavailable\n");
+#endif
+
 	retval = ehci_pci_reinit(ehci, pdev);
 done:
 	return retval;
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 9b13bf2..e469221 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -702,7 +702,7 @@
 	}
 
 	/* support for tt scheduling, and access to toggles */
-	qh->dev = usb_get_dev (urb->dev);
+	qh->dev = urb->dev;
 
 	/* using TT? */
 	switch (urb->dev->speed) {
@@ -721,7 +721,14 @@
 		info1 |= maxp << 16;
 
 		info2 |= (EHCI_TUNE_MULT_TT << 30);
-		info2 |= urb->dev->ttport << 23;
+
+		/* Some Freescale processors have an erratum in which the
+		 * port number in the queue head was 0..N-1 instead of 1..N.
+		 */
+		if (ehci_has_fsl_portno_bug(ehci))
+			info2 |= (urb->dev->ttport-1) << 23;
+		else
+			info2 |= urb->dev->ttport << 23;
 
 		/* set the address of the TT; for TDI's integrated
 		 * root hub tt, leave it zeroed.
@@ -1015,12 +1022,14 @@
 	/* stop async schedule right now? */
 	if (unlikely (qh == ehci->async)) {
 		/* can't get here without STS_ASS set */
-		if (ehci_to_hcd(ehci)->state != HC_STATE_HALT) {
+		if (ehci_to_hcd(ehci)->state != HC_STATE_HALT
+				&& !ehci->reclaim) {
+			/* ... and CMD_IAAD clear */
 			writel (cmd & ~CMD_ASE, &ehci->regs->command);
 			wmb ();
 			// handshake later, if we need to
+			timer_action_done (ehci, TIMER_ASYNC_OFF);
 		}
-		timer_action_done (ehci, TIMER_ASYNC_OFF);
 		return;
 	} 
 
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index ebcca97..5871944 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -707,6 +707,7 @@
 	} else {
 		u32		addr;
 		int		think_time;
+		int		hs_transfers;
 
 		addr = dev->ttport << 24;
 		if (!ehci_is_TDI(ehci)
@@ -719,6 +720,7 @@
 		think_time = dev->tt ? dev->tt->think_time : 0;
 		stream->tt_usecs = NS_TO_US (think_time + usb_calc_bus_time (
 				dev->speed, is_input, 1, maxp));
+		hs_transfers = max (1u, (maxp + 187) / 188);
 		if (is_input) {
 			u32	tmp;
 
@@ -727,12 +729,11 @@
 			stream->usecs = HS_USECS_ISO (1);
 			stream->raw_mask = 1;
 
-			/* pessimistic c-mask */
-			tmp = usb_calc_bus_time (USB_SPEED_FULL, 1, 0, maxp)
-					/ (125 * 1000);
-			stream->raw_mask |= 3 << (tmp + 9);
+			/* c-mask as specified in USB 2.0 11.18.4 3.c */
+			tmp = (1 << (hs_transfers + 2)) - 1;
+			stream->raw_mask |= tmp << (8 + 2);
 		} else
-			stream->raw_mask = smask_out [maxp / 188];
+			stream->raw_mask = smask_out [hs_transfers - 1];
 		bandwidth = stream->usecs + stream->c_usecs;
 		bandwidth /= 1 << (interval + 2);
 
@@ -863,9 +864,8 @@
 	int			size = sizeof *iso_sched;
 
 	size += packets * sizeof (struct ehci_iso_packet);
-	iso_sched = kmalloc (size, mem_flags);
+	iso_sched = kzalloc(size, mem_flags);
 	if (likely (iso_sched != NULL)) {
-		memset(iso_sched, 0, size);
 		INIT_LIST_HEAD (&iso_sched->td_list);
 	}
 	return iso_sched;
@@ -1398,7 +1398,7 @@
 	 */
 
 	/* give urb back to the driver ... can be out-of-order */
-	dev = usb_get_dev (urb->dev);
+	dev = urb->dev;
 	ehci_urb_done (ehci, urb, regs);
 	urb = NULL;
 
@@ -1417,7 +1417,6 @@
 			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
 	}
 	iso_stream_put (ehci, stream);
-	usb_put_dev (dev);
 
 	return 1;
 }
@@ -1764,7 +1763,7 @@
 	 */
 
 	/* give urb back to the driver */
-	dev = usb_get_dev (urb->dev);
+	dev = urb->dev;
 	ehci_urb_done (ehci, urb, regs);
 	urb = NULL;
 
@@ -1783,7 +1782,6 @@
 			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
 	}
 	iso_stream_put (ehci, stream);
-	usb_put_dev (dev);
 
 	return 1;
 }
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 18e257c..679c1cd 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -88,7 +88,12 @@
 	unsigned long		next_statechange;
 	u32			command;
 
+	/* SILICON QUIRKS */
 	unsigned		is_tdi_rh_tt:1;	/* TDI roothub with TT */
+	unsigned		no_selective_suspend:1;
+	unsigned		has_fsl_port_bug:1; /* FreeScale */
+
+	u8			sbrn;		/* packed release number */
 
 	/* irq statistics */
 #ifdef EHCI_STATS
@@ -97,7 +102,6 @@
 #else
 #	define COUNT(x) do {} while (0)
 #endif
-	u8			sbrn;		/* packed release number */
 };
 
 /* convert between an HCD pointer and the corresponding EHCI_HCD */ 
@@ -638,6 +642,18 @@
 
 /*-------------------------------------------------------------------------*/
 
+#ifdef CONFIG_PPC_83xx
+/* Some Freescale processors have an erratum in which the TT
+ * port number in the queue head was 0..N-1 instead of 1..N.
+ */
+#define	ehci_has_fsl_portno_bug(e)		((e)->has_fsl_port_bug)
+#else
+#define	ehci_has_fsl_portno_bug(e)		(0)
+#endif
+
+
+/*-------------------------------------------------------------------------*/
+
 #ifndef DEBUG
 #define STUB_DEBUG_FILES
 #endif	/* DEBUG */
diff --git a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c
index 641268d..2fe7fd1 100644
--- a/drivers/usb/host/hc_crisv10.c
+++ b/drivers/usb/host/hc_crisv10.c
@@ -2137,10 +2137,9 @@
 	urb->status = -EINPROGRESS;
 
 	/* Setup the hcpriv data. */
-	urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
+	urb_priv = kzalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
 	assert(urb_priv != NULL);
 	/* This sets rx_offset to 0. */
-	memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
 	urb_priv->urb_state = NOT_STARTED;
 	urb->hcpriv = urb_priv;
 
@@ -2475,10 +2474,9 @@
 	urb->status = -EINPROGRESS;
 
 	/* Setup the hcpriv data. */
-	urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
+	urb_priv = kzalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
 	assert(urb_priv != NULL);
 	/* This sets rx_offset to 0. */
-	memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
 	urb_priv->urb_state = NOT_STARTED;
 	urb->hcpriv = urb_priv;
 
@@ -2767,9 +2765,8 @@
 	maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
 	interval = urb->interval;
 
-	urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
+	urb_priv = kzalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
 	assert(urb_priv != NULL);
-	memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
 	urb->hcpriv = urb_priv;
 
 	first_ep = &TxIntrEPList[0];
@@ -2997,9 +2994,8 @@
 
 	prev_sb_desc = next_sb_desc = temp_sb_desc = NULL;
 
-	urb_priv = kmalloc(sizeof(etrax_urb_priv_t), GFP_ATOMIC);
+	urb_priv = kzalloc(sizeof(etrax_urb_priv_t), GFP_ATOMIC);
 	assert(urb_priv != NULL);
-	memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
 
 	urb->hcpriv = urb_priv;
 	urb_priv->epid = epid;
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index 972ce04..e99210b 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -724,7 +724,7 @@
 		ep = hep->hcpriv;
 	else {
 		INIT_LIST_HEAD(&ep->schedule);
-		ep->udev = usb_get_dev(udev);
+		ep->udev = udev;
 		ep->epnum = epnum;
 		ep->maxpacket = usb_maxpacket(udev, urb->pipe, is_out);
 		usb_settoggle(udev, epnum, is_out, 0);
@@ -891,7 +891,6 @@
 	if (!list_empty(&hep->urb_list))
 		WARN("ep %p not empty?\n", ep);
 
-	usb_put_dev(ep->udev);
 	kfree(ep);
 	hep->hcpriv = NULL;
 }
@@ -1553,7 +1552,7 @@
 
 /*----------------------------------------------------------------*/
 
-static int __init_or_module isp116x_remove(struct platform_device *pdev)
+static int isp116x_remove(struct platform_device *pdev)
 {
 	struct usb_hcd *hcd = platform_get_drvdata(pdev);
 	struct isp116x *isp116x;
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
new file mode 100644
index 0000000..980030d6
--- /dev/null
+++ b/drivers/usb/host/ohci-at91.c
@@ -0,0 +1,306 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ *  Copyright (C) 2004 SAN People (Pty) Ltd.
+ *  Copyright (C) 2005 Thibaut VARENE <varenet@parisc-linux.org>
+ *
+ * AT91RM9200 Bus Glue
+ *
+ * Based on fragments of 2.4 driver by Rick Bronson.
+ * Based on ohci-omap.c
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+#include <asm/arch/board.h>
+
+#ifndef CONFIG_ARCH_AT91RM9200
+#error "This file is AT91RM9200 bus glue.  CONFIG_ARCH_AT91RM9200 must be defined."
+#endif
+
+/* interface and function clocks */
+static struct clk *iclk, *fclk;
+
+extern int usb_disabled(void);
+
+/*-------------------------------------------------------------------------*/
+
+static void at91_start_hc(struct platform_device *pdev)
+{
+	struct usb_hcd *hcd = platform_get_drvdata(pdev);
+	struct ohci_regs __iomem *regs = hcd->regs;
+
+	dev_dbg(&pdev->dev, "starting AT91RM9200 OHCI USB Controller\n");
+
+	/*
+	 * Start the USB clocks.
+	 */
+	clk_enable(iclk);
+	clk_enable(fclk);
+
+	/*
+	 * The USB host controller must remain in reset.
+	 */
+	writel(0, &regs->control);
+}
+
+static void at91_stop_hc(struct platform_device *pdev)
+{
+	struct usb_hcd *hcd = platform_get_drvdata(pdev);
+	struct ohci_regs __iomem *regs = hcd->regs;
+
+	dev_dbg(&pdev->dev, "stopping AT91RM9200 OHCI USB Controller\n");
+
+	/*
+	 * Put the USB host controller into reset.
+	 */
+	writel(0, &regs->control);
+
+	/*
+	 * Stop the USB clocks.
+	 */
+	clk_disable(fclk);
+	clk_disable(iclk);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int usb_hcd_at91_remove (struct usb_hcd *, struct platform_device *);
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+
+/**
+ * usb_hcd_at91_probe - initialize AT91RM9200-based HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ * Store this function in the HCD's struct pci_driver as probe().
+ */
+int usb_hcd_at91_probe (const struct hc_driver *driver, struct platform_device *pdev)
+{
+	int retval;
+	struct usb_hcd *hcd = NULL;
+
+	if (pdev->num_resources != 2) {
+		pr_debug("hcd probe: invalid num_resources");
+		return -ENODEV;
+	}
+
+	if ((pdev->resource[0].flags != IORESOURCE_MEM) || (pdev->resource[1].flags != IORESOURCE_IRQ)) {
+		pr_debug("hcd probe: invalid resource type\n");
+		return -ENODEV;
+	}
+
+	hcd = usb_create_hcd(driver, &pdev->dev, "at91rm9200");
+	if (!hcd)
+		return -ENOMEM;
+	hcd->rsrc_start = pdev->resource[0].start;
+	hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+		pr_debug("request_mem_region failed\n");
+		retval = -EBUSY;
+		goto err1;
+	}
+
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs) {
+		pr_debug("ioremap failed\n");
+		retval = -EIO;
+		goto err2;
+	}
+
+	iclk = clk_get(&pdev->dev, "ohci_clk");
+	fclk = clk_get(&pdev->dev, "uhpck");
+
+	at91_start_hc(pdev);
+	ohci_hcd_init(hcd_to_ohci(hcd));
+
+	retval = usb_add_hcd(hcd, pdev->resource[1].start, SA_INTERRUPT);
+	if (retval == 0)
+		return retval;
+
+	/* Error handling */
+	at91_stop_hc(pdev);
+
+	clk_put(fclk);
+	clk_put(iclk);
+
+	iounmap(hcd->regs);
+
+ err2:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+
+ err1:
+	usb_put_hcd(hcd);
+	return retval;
+}
+
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_at91_remove - shutdown processing for AT91RM9200-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_at91_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ */
+static int usb_hcd_at91_remove (struct usb_hcd *hcd, struct platform_device *pdev)
+{
+	usb_remove_hcd(hcd);
+	at91_stop_hc(pdev);
+	iounmap(hcd->regs);
+ 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+
+ 	clk_put(fclk);
+ 	clk_put(iclk);
+ 	fclk = iclk = NULL;
+
+	dev_set_drvdata(&pdev->dev, NULL);
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int __devinit
+ohci_at91_start (struct usb_hcd *hcd)
+{
+//	struct at91_ohci_data	*board = hcd->self.controller->platform_data;
+	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
+	int			ret;
+
+	if ((ret = ohci_init(ohci)) < 0)
+		return ret;
+
+	if ((ret = ohci_run(ohci)) < 0) {
+		err("can't start %s", hcd->self.bus_name);
+		ohci_stop(hcd);
+		return ret;
+	}
+//	hcd->self.root_hub->maxchild = board->ports;
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ohci_at91_hc_driver = {
+	.description =		hcd_name,
+	.product_desc =		"AT91RM9200 OHCI",
+	.hcd_priv_size =	sizeof(struct ohci_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq =			ohci_irq,
+	.flags =		HCD_USB11 | HCD_MEMORY,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.start =		ohci_at91_start,
+	.stop =			ohci_stop,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue =		ohci_urb_enqueue,
+	.urb_dequeue =		ohci_urb_dequeue,
+	.endpoint_disable =	ohci_endpoint_disable,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number =	ohci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data =	ohci_hub_status_data,
+	.hub_control =		ohci_hub_control,
+
+#ifdef CONFIG_PM
+	.hub_suspend =		ohci_hub_suspend,
+	.hub_resume =		ohci_hub_resume,
+#endif
+	.start_port_reset =	ohci_start_port_reset,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int ohci_hcd_at91_drv_probe(struct platform_device *dev)
+{
+	return usb_hcd_at91_probe(&ohci_at91_hc_driver, dev);
+}
+
+static int ohci_hcd_at91_drv_remove(struct platform_device *dev)
+{
+	return usb_hcd_at91_remove(platform_get_drvdata(dev), dev);
+}
+
+#ifdef CONFIG_PM
+static int ohci_hcd_at91_drv_suspend(struct platform_device *dev, u32 state, u32 level)
+{
+	printk("%s(%s:%d): not implemented yet\n",
+		__func__, __FILE__, __LINE__);
+
+	clk_disable(fclk);
+
+	return 0;
+}
+
+static int ohci_hcd_at91_drv_resume(struct platform_device *dev, u32 state)
+{
+	printk("%s(%s:%d): not implemented yet\n",
+		__func__, __FILE__, __LINE__);
+
+	clk_enable(fclk);
+
+	return 0;
+}
+#else
+#define ohci_hcd_at91_drv_suspend NULL
+#define ohci_hcd_at91_drv_resume  NULL
+#endif
+
+static struct platform_driver ohci_hcd_at91_driver = {
+	.probe		= ohci_hcd_at91_drv_probe,
+	.remove		= ohci_hcd_at91_drv_remove,
+	.suspend	= ohci_hcd_at91_drv_suspend,
+	.resume		= ohci_hcd_at91_drv_resume,
+	.driver		= {
+		.name	= "at91rm9200-ohci",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init ohci_hcd_at91_init (void)
+{
+	if (usb_disabled())
+		return -ENODEV;
+
+	return platform_driver_register(&ohci_hcd_at91_driver);
+}
+
+static void __exit ohci_hcd_at91_cleanup (void)
+{
+	platform_driver_unregister(&ohci_hcd_at91_driver);
+}
+
+module_init (ohci_hcd_at91_init);
+module_exit (ohci_hcd_at91_cleanup);
diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c
index db280ca..a1c8b3b 100644
--- a/drivers/usb/host/ohci-au1xxx.c
+++ b/drivers/usb/host/ohci-au1xxx.c
@@ -23,6 +23,8 @@
 
 #include <asm/mach-au1x00/au1000.h>
 
+#ifndef	CONFIG_SOC_AU1200
+
 #define USBH_ENABLE_BE (1<<0)
 #define USBH_ENABLE_C  (1<<1)
 #define USBH_ENABLE_E  (1<<2)
@@ -37,21 +39,68 @@
 #error not byte order defined
 #endif
 
+#else   /* Au1200 */
+
+#define USB_HOST_CONFIG    (USB_MSR_BASE + USB_MSR_MCFG)
+#define USB_MCFG_PFEN     (1<<31)
+#define USB_MCFG_RDCOMB   (1<<30)
+#define USB_MCFG_SSDEN    (1<<23)
+#define USB_MCFG_OHCCLKEN (1<<16)
+#define USB_MCFG_UCAM     (1<<7)
+#define USB_MCFG_OBMEN    (1<<1)
+#define USB_MCFG_OMEMEN   (1<<0)
+
+#define USBH_ENABLE_CE    USB_MCFG_OHCCLKEN
+#ifdef CONFIG_DMA_COHERENT
+#define USBH_ENABLE_INIT  (USB_MCFG_OHCCLKEN \
+                         | USB_MCFG_PFEN | USB_MCFG_RDCOMB \
+                         | USB_MCFG_SSDEN | USB_MCFG_UCAM \
+                         | USB_MCFG_OBMEN | USB_MCFG_OMEMEN)
+#else
+#define USBH_ENABLE_INIT  (USB_MCFG_OHCCLKEN \
+                         | USB_MCFG_PFEN | USB_MCFG_RDCOMB \
+                         | USB_MCFG_SSDEN \
+                         | USB_MCFG_OBMEN | USB_MCFG_OMEMEN)
+#endif
+#define USBH_DISABLE      (USB_MCFG_OBMEN | USB_MCFG_OMEMEN)
+
+#endif  /* Au1200 */
+
 extern int usb_disabled(void);
 
 /*-------------------------------------------------------------------------*/
 
-static void au1xxx_start_hc(struct platform_device *dev)
+static void au1xxx_start_ohc(struct platform_device *dev)
 {
 	printk(KERN_DEBUG __FILE__
 		": starting Au1xxx OHCI USB Controller\n");
 
 	/* enable host controller */
+
+#ifndef CONFIG_SOC_AU1200
+
 	au_writel(USBH_ENABLE_CE, USB_HOST_CONFIG);
 	udelay(1000);
 	au_writel(USBH_ENABLE_INIT, USB_HOST_CONFIG);
 	udelay(1000);
 
+#else   /* Au1200 */
+
+	/* write HW defaults again in case Yamon cleared them */
+	if (au_readl(USB_HOST_CONFIG) == 0) {
+		au_writel(0x00d02000, USB_HOST_CONFIG);
+		au_readl(USB_HOST_CONFIG);
+		udelay(1000);
+	}
+	au_writel(USBH_ENABLE_CE | au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
+	au_readl(USB_HOST_CONFIG);
+	udelay(1000);
+	au_writel(USBH_ENABLE_INIT | au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
+	au_readl(USB_HOST_CONFIG);
+	udelay(1000);
+
+#endif  /* Au1200 */
+
 	/* wait for reset complete (read register twice; see au1500 errata) */
 	while (au_readl(USB_HOST_CONFIG),
 		!(au_readl(USB_HOST_CONFIG) & USBH_ENABLE_RD))
@@ -61,13 +110,25 @@
 	": Clock to USB host has been enabled \n");
 }
 
-static void au1xxx_stop_hc(struct platform_device *dev)
+static void au1xxx_stop_ohc(struct platform_device *dev)
 {
 	printk(KERN_DEBUG __FILE__
 	       ": stopping Au1xxx OHCI USB Controller\n");
 
+#ifndef CONFIG_SOC_AU1200
+
 	/* Disable clock */
 	au_writel(au_readl(USB_HOST_CONFIG) & ~USBH_ENABLE_CE, USB_HOST_CONFIG);
+
+#else   /* Au1200 */
+
+	/* Disable mem */
+	au_writel(~USBH_DISABLE & au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
+	udelay(1000);
+	/* Disable clock */
+	au_writel(~USBH_ENABLE_CE & au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
+	au_readl(USB_HOST_CONFIG);
+#endif  /* Au1200 */
 }
 
 
@@ -78,7 +139,7 @@
 
 
 /**
- * usb_hcd_au1xxx_probe - initialize Au1xxx-based HCDs
+ * usb_ohci_au1xxx_probe - initialize Au1xxx-based HCDs
  * Context: !in_interrupt()
  *
  * Allocates basic resources for this USB host controller, and
@@ -86,14 +147,25 @@
  * through the hotplug entry's driver_data.
  *
  */
-int usb_hcd_au1xxx_probe (const struct hc_driver *driver,
+static int usb_ohci_au1xxx_probe(const struct hc_driver *driver,
 			  struct platform_device *dev)
 {
 	int retval;
 	struct usb_hcd *hcd;
 
-	if(dev->resource[1].flags != IORESOURCE_IRQ) {
-		pr_debug ("resource[1] is not IORESOURCE_IRQ");
+#if defined(CONFIG_SOC_AU1200) && defined(CONFIG_DMA_COHERENT)
+	/* Au1200 AB USB does not support coherent memory */
+	if (!(read_c0_prid() & 0xff)) {
+		pr_info("%s: this is chip revision AB !!\n",
+			dev->dev.name);
+		pr_info("%s: update your board or re-configure the kernel\n",
+			dev->dev.name);
+		return -ENODEV;
+	}
+#endif
+
+	if (dev->resource[1].flags != IORESOURCE_IRQ) {
+		pr_debug("resource[1] is not IORESOURCE_IRQ\n");
 		return -ENOMEM;
 	}
 
@@ -104,26 +176,26 @@
 	hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
 
 	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-		pr_debug("request_mem_region failed");
+		pr_debug("request_mem_region failed\n");
 		retval = -EBUSY;
 		goto err1;
 	}
 
 	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
 	if (!hcd->regs) {
-		pr_debug("ioremap failed");
+		pr_debug("ioremap failed\n");
 		retval = -ENOMEM;
 		goto err2;
 	}
 
-	au1xxx_start_hc(dev);
+	au1xxx_start_ohc(dev);
 	ohci_hcd_init(hcd_to_ohci(hcd));
 
-	retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT);
+	retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT | SA_SHIRQ);
 	if (retval == 0)
 		return retval;
 
-	au1xxx_stop_hc(dev);
+	au1xxx_stop_ohc(dev);
 	iounmap(hcd->regs);
  err2:
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
@@ -146,10 +218,10 @@
  * context, normally "rmmod", "apmd", or something similar.
  *
  */
-void usb_hcd_au1xxx_remove (struct usb_hcd *hcd, struct platform_device *dev)
+static void usb_ohci_au1xxx_remove(struct usb_hcd *hcd, struct platform_device *dev)
 {
 	usb_remove_hcd(hcd);
-	au1xxx_stop_hc(dev);
+	au1xxx_stop_ohc(dev);
 	iounmap(hcd->regs);
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 	usb_put_hcd(hcd);
@@ -235,7 +307,7 @@
 	if (usb_disabled())
 		return -ENODEV;
 
-	ret = usb_hcd_au1xxx_probe(&ohci_au1xxx_hc_driver, pdev);
+	ret = usb_ohci_au1xxx_probe(&ohci_au1xxx_hc_driver, pdev);
 	return ret;
 }
 
@@ -243,7 +315,7 @@
 {
 	struct usb_hcd *hcd = platform_get_drvdata(pdev);
 
-	usb_hcd_au1xxx_remove(hcd, pdev);
+	usb_ohci_au1xxx_remove(hcd, pdev);
 	return 0;
 }
 	/*TBD*/
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index a4b1240..544f758 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -443,11 +443,16 @@
 static int ohci_init (struct ohci_hcd *ohci)
 {
 	int ret;
+	struct usb_hcd *hcd = ohci_to_hcd(ohci);
 
 	disable (ohci);
-	ohci->regs = ohci_to_hcd(ohci)->regs;
+	ohci->regs = hcd->regs;
 	ohci->next_statechange = jiffies;
 
+	/* REVISIT this BIOS handshake is now moved into PCI "quirks", and
+	 * was never needed for most non-PCI systems ... remove the code?
+	 */
+
 #ifndef IR_DISABLE
 	/* SMM owns the HC?  not for long! */
 	if (!no_handshake && ohci_readl (ohci,
@@ -478,8 +483,10 @@
 
 	/* Disable HC interrupts */
 	ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
-	// flush the writes
-	(void) ohci_readl (ohci, &ohci->regs->control);
+
+	/* flush the writes, and save key bits like RWC */
+	if (ohci_readl (ohci, &ohci->regs->control) & OHCI_CTRL_RWC)
+		ohci->hc_control |= OHCI_CTRL_RWC;
 
 	/* Read the number of ports unless overridden */
 	if (ohci->num_ports == 0)
@@ -488,16 +495,19 @@
 	if (ohci->hcca)
 		return 0;
 
-	ohci->hcca = dma_alloc_coherent (ohci_to_hcd(ohci)->self.controller,
+	ohci->hcca = dma_alloc_coherent (hcd->self.controller,
 			sizeof *ohci->hcca, &ohci->hcca_dma, 0);
 	if (!ohci->hcca)
 		return -ENOMEM;
 
 	if ((ret = ohci_mem_init (ohci)) < 0)
-		ohci_stop (ohci_to_hcd(ohci));
+		ohci_stop (hcd);
+	else {
+		register_reboot_notifier (&ohci->reboot_notifier);
+		create_debug_files (ohci);
+	}
 
 	return ret;
-
 }
 
 /*-------------------------------------------------------------------------*/
@@ -510,6 +520,7 @@
 {
   	u32			mask, temp;
 	int			first = ohci->fminterval == 0;
+	struct usb_hcd		*hcd = ohci_to_hcd(ohci);
 
 	disable (ohci);
 
@@ -525,18 +536,17 @@
 		/* also: power/overcurrent flags in roothub.a */
 	}
 
-  	/* Reset USB nearly "by the book".  RemoteWakeupConnected
-	 * saved if boot firmware (BIOS/SMM/...) told us it's connected
-	 * (for OHCI integrated on mainboard, it normally is)
+  	/* Reset USB nearly "by the book".  RemoteWakeupConnected was
+	 * saved if boot firmware (BIOS/SMM/...) told us it's connected,
+	 * or if bus glue did the same (e.g. for PCI add-in cards with
+	 * PCI PM support).
 	 */
-	ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
 	ohci_dbg (ohci, "resetting from state '%s', control = 0x%x\n",
 			hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
-			ohci->hc_control);
-
-	if (ohci->hc_control & OHCI_CTRL_RWC
-			&& !(ohci->flags & OHCI_QUIRK_AMD756))
-		ohci_to_hcd(ohci)->can_wakeup = 1;
+			ohci_readl (ohci, &ohci->regs->control));
+	if ((ohci->hc_control & OHCI_CTRL_RWC) != 0
+			&& !device_may_wakeup(hcd->self.controller))
+		device_init_wakeup(hcd->self.controller, 1);
 
 	switch (ohci->hc_control & OHCI_CTRL_HCFS) {
 	case OHCI_USB_OPER:
@@ -632,7 +642,7 @@
 	ohci->hc_control &= OHCI_CTRL_RWC;
  	ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
  	ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
-	ohci_to_hcd(ohci)->state = HC_STATE_RUNNING;
+	hcd->state = HC_STATE_RUNNING;
 
 	/* wake on ConnectStatusChange, matching external hubs */
 	ohci_writel (ohci, RH_HS_DRWE, &ohci->regs->roothub.status);
@@ -667,15 +677,10 @@
 
 	// POTPGT delay is bits 24-31, in 2 ms units.
 	mdelay ((temp >> 23) & 0x1fe);
-	ohci_to_hcd(ohci)->state = HC_STATE_RUNNING;
+	hcd->state = HC_STATE_RUNNING;
 
 	ohci_dump (ohci, 1);
 
-	if (ohci_to_hcd(ohci)->self.root_hub == NULL) {
-		register_reboot_notifier (&ohci->reboot_notifier);
-		create_debug_files (ohci);
-	}
-
 	return 0;
 }
 
@@ -905,6 +910,10 @@
 #include "ohci-ppc-soc.c"
 #endif
 
+#ifdef CONFIG_ARCH_AT91RM9200
+#include "ohci-at91.c"
+#endif
+
 #if !(defined(CONFIG_PCI) \
       || defined(CONFIG_SA1111) \
       || defined(CONFIG_ARCH_S3C2410) \
@@ -913,6 +922,7 @@
       || defined (CONFIG_PXA27x) \
       || defined (CONFIG_SOC_AU1X00) \
       || defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \
+      || defined (CONFIG_ARCH_AT91RM9200) \
 	)
 #error "missing bus glue for ohci-hcd"
 #endif
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index 4b2226d..0bb972b58 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -107,7 +107,7 @@
 			&ohci->regs->intrstatus);
 
 	/* maybe resume can wake root hub */
-	if (hcd->remote_wakeup)
+	if (device_may_wakeup(&ohci_to_hcd(ohci)->self.root_hub->dev))
 		ohci->hc_control |= OHCI_CTRL_RWE;
 	else
 		ohci->hc_control &= ~OHCI_CTRL_RWE;
@@ -246,9 +246,9 @@
 	(void) ohci_readl (ohci, &ohci->regs->control);
 	msleep (3);
 
-	temp = OHCI_CONTROL_INIT | OHCI_USB_OPER;
-	if (hcd->can_wakeup)
-		temp |= OHCI_CTRL_RWC;
+	temp = ohci->hc_control;
+	temp &= OHCI_CTRL_RWC;
+	temp |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
 	ohci->hc_control = temp;
 	ohci_writel (ohci, temp, &ohci->regs->control);
 	(void) ohci_readl (ohci, &ohci->regs->control);
@@ -302,7 +302,7 @@
 {
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 	int		i, changed = 0, length = 1;
-	int		can_suspend = hcd->can_wakeup;
+	int		can_suspend = device_may_wakeup(&hcd->self.root_hub->dev);
 	unsigned long	flags;
 
 	spin_lock_irqsave (&ohci->lock, flags);
@@ -354,7 +354,7 @@
 		 */
 		if (!(status & RH_PS_CCS))
 			continue;
-		if ((status & RH_PS_PSS) && hcd->remote_wakeup)
+		if ((status & RH_PS_PSS) && can_suspend)
 			continue;
 		can_suspend = 0;
 	}
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 3785b3f..ca19abe 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -286,7 +286,7 @@
 int usb_hcd_omap_probe (const struct hc_driver *driver,
 			  struct platform_device *pdev)
 {
-	int retval;
+	int retval, irq;
 	struct usb_hcd *hcd = 0;
 	struct ohci_hcd *ohci;
 
@@ -329,7 +329,12 @@
 	if (retval < 0)
 		goto err2;
 
-	retval = usb_add_hcd(hcd, platform_get_irq(pdev, 0), SA_INTERRUPT);
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		retval = -ENXIO;
+		goto err2;
+	}
+	retval = usb_add_hcd(hcd, irq, SA_INTERRUPT);
 	if (retval == 0)
 		return retval;
 
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index 1b09dde..1bfe96f 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -35,7 +35,10 @@
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 	int		ret;
 
-	if(hcd->self.controller && hcd->self.controller->bus == &pci_bus_type) {
+	/* REVISIT this whole block should move to reset(), which handles
+	 * all the other one-time init.
+	 */
+	if (hcd->self.controller) {
 		struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
 
 		/* AMD 756, for most chips (early revs), corrupts register
@@ -45,7 +48,8 @@
 				&& pdev->device == 0x740c) {
 			ohci->flags = OHCI_QUIRK_AMD756;
 			ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
-			// also somewhat erratum 10 (suspend/resume issues)
+			/* also erratum 10 (suspend/resume issues) */
+			device_init_wakeup(&hcd->self.root_hub->dev, 0);
 		}
 
 		/* FIXME for some of the early AMD 760 southbridges, OHCI
@@ -88,6 +92,13 @@
 			ohci_dbg (ohci,
 				"enabled Compaq ZFMicro chipset quirk\n");
 		}
+
+		/* RWC may not be set for add-in PCI cards, since boot
+		 * firmware probably ignored them.  This transfers PCI
+		 * PM wakeup capabilities (once the PCI layer is fixed).
+		 */
+		if (device_may_wakeup(&pdev->dev))
+			ohci->hc_control |= OHCI_CTRL_RWC;
 	}
 
 	/* NOTE: there may have already been a first reset, to
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 517360b..a923430 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -853,7 +853,7 @@
 
 	} else {
 		INIT_LIST_HEAD(&ep->schedule);
-		ep->udev = usb_get_dev(udev);
+		ep->udev = udev;
 		ep->epnum = epnum;
 		ep->maxpacket = usb_maxpacket(udev, urb->pipe, is_out);
 		ep->defctrl = SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENABLE;
@@ -1052,7 +1052,6 @@
 	if (!list_empty(&hep->urb_list))
 		WARN("ep %p not empty?\n", ep);
 
-	usb_put_dev(ep->udev);
 	kfree(ep);
 	hep->hcpriv = NULL;
 }
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index 5832953..e123931 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -17,10 +17,13 @@
 
 #include "uhci-hcd.h"
 
-static struct dentry *uhci_debugfs_root = NULL;
+#define uhci_debug_operations (* (struct file_operations *) NULL)
+static struct dentry *uhci_debugfs_root;
+
+#ifdef DEBUG
 
 /* Handle REALLY large printks so we don't overflow buffers */
-static inline void lprintk(char *buf)
+static void lprintk(char *buf)
 {
 	char *p;
 
@@ -90,13 +93,59 @@
 	return out - buf;
 }
 
+static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space)
+{
+	char *out = buf;
+	struct uhci_td *td;
+	int i, nactive, ninactive;
+
+	if (len < 200)
+		return 0;
+
+	out += sprintf(out, "urb_priv [%p] ", urbp);
+	out += sprintf(out, "urb [%p] ", urbp->urb);
+	out += sprintf(out, "qh [%p] ", urbp->qh);
+	out += sprintf(out, "Dev=%d ", usb_pipedevice(urbp->urb->pipe));
+	out += sprintf(out, "EP=%x(%s) ", usb_pipeendpoint(urbp->urb->pipe),
+			(usb_pipein(urbp->urb->pipe) ? "IN" : "OUT"));
+
+	switch (usb_pipetype(urbp->urb->pipe)) {
+	case PIPE_ISOCHRONOUS: out += sprintf(out, "ISO"); break;
+	case PIPE_INTERRUPT: out += sprintf(out, "INT"); break;
+	case PIPE_BULK: out += sprintf(out, "BLK"); break;
+	case PIPE_CONTROL: out += sprintf(out, "CTL"); break;
+	}
+
+	out += sprintf(out, "%s", (urbp->fsbr ? " FSBR" : ""));
+
+	if (urbp->urb->status != -EINPROGRESS)
+		out += sprintf(out, " Status=%d", urbp->urb->status);
+	out += sprintf(out, "\n");
+
+	i = nactive = ninactive = 0;
+	list_for_each_entry(td, &urbp->td_list, list) {
+		if (++i <= 10 || debug > 2) {
+			out += sprintf(out, "%*s%d: ", space + 2, "", i);
+			out += uhci_show_td(td, out, len - (out - buf), 0);
+		} else {
+			if (td_status(td) & TD_CTRL_ACTIVE)
+				++nactive;
+			else
+				++ninactive;
+		}
+	}
+	if (nactive + ninactive > 0)
+		out += sprintf(out, "%*s[skipped %d inactive and %d active "
+				"TDs]\n",
+				space, "", ninactive, nactive);
+
+	return out - buf;
+}
+
 static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
 {
 	char *out = buf;
-	struct urb_priv *urbp;
-	struct list_head *head, *tmp;
-	struct uhci_td *td;
-	int i = 0, checked = 0, prevactive = 0;
+	int i, nurbs;
 	__le32 element = qh_element(qh);
 
 	/* Try to make sure there's enough memory */
@@ -118,86 +167,40 @@
 	if (!(element & ~(UHCI_PTR_QH | UHCI_PTR_DEPTH)))
 		out += sprintf(out, "%*s  Element is NULL (bug?)\n", space, "");
 
-	if (!qh->urbp) {
-		out += sprintf(out, "%*s  urbp == NULL\n", space, "");
-		goto out;
-	}
+	if (list_empty(&qh->queue)) {
+		out += sprintf(out, "%*s  queue is empty\n", space, "");
+	} else {
+		struct urb_priv *urbp = list_entry(qh->queue.next,
+				struct urb_priv, node);
+		struct uhci_td *td = list_entry(urbp->td_list.next,
+				struct uhci_td, list);
 
-	urbp = qh->urbp;
-
-	head = &urbp->td_list;
-	tmp = head->next;
-
-	td = list_entry(tmp, struct uhci_td, list);
-
-	if (cpu_to_le32(td->dma_handle) != (element & ~UHCI_PTR_BITS))
-		out += sprintf(out, "%*s Element != First TD\n", space, "");
-
-	while (tmp != head) {
-		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
-
-		tmp = tmp->next;
-
-		out += sprintf(out, "%*s%d: ", space + 2, "", i++);
-		out += uhci_show_td(td, out, len - (out - buf), 0);
-
-		if (i > 10 && !checked && prevactive && tmp != head &&
-		    debug <= 2) {
-			struct list_head *ntmp = tmp;
-			struct uhci_td *ntd = td;
-			int active = 1, ni = i;
-
-			checked = 1;
-
-			while (ntmp != head && ntmp->next != head && active) {
-				ntd = list_entry(ntmp, struct uhci_td, list);
-
-				ntmp = ntmp->next;
-
-				active = td_status(ntd) & TD_CTRL_ACTIVE;
-
-				ni++;
-			}
-
-			if (active && ni > i) {
-				out += sprintf(out, "%*s[skipped %d active TDs]\n", space, "", ni - i);
-				tmp = ntmp;
-				td = ntd;
-				i = ni;
-			}
+		if (cpu_to_le32(td->dma_handle) != (element & ~UHCI_PTR_BITS))
+			out += sprintf(out, "%*s Element != First TD\n",
+					space, "");
+		i = nurbs = 0;
+		list_for_each_entry(urbp, &qh->queue, node) {
+			if (++i <= 10)
+				out += uhci_show_urbp(urbp, out,
+						len - (out - buf), space + 2);
+			else
+				++nurbs;
 		}
-
-		prevactive = td_status(td) & TD_CTRL_ACTIVE;
+		if (nurbs > 0)
+			out += sprintf(out, "%*s Skipped %d URBs\n",
+					space, "", nurbs);
 	}
 
-	if (list_empty(&urbp->queue_list) || urbp->queued)
-		goto out;
-
-	out += sprintf(out, "%*sQueued QHs:\n", -space, "--");
-
-	head = &urbp->queue_list;
-	tmp = head->next;
-
-	while (tmp != head) {
-		struct urb_priv *nurbp = list_entry(tmp, struct urb_priv,
-						queue_list);
-		tmp = tmp->next;
-
-		out += uhci_show_qh(nurbp->qh, out, len - (out - buf), space);
+	if (qh->udev) {
+		out += sprintf(out, "%*s  Dummy TD\n", space, "");
+		out += uhci_show_td(qh->dummy_td, out, len - (out - buf), 0);
 	}
 
-out:
 	return out - buf;
 }
 
-#define show_frame_num()	\
-	if (!shown) {		\
-	  shown = 1;		\
-	  out += sprintf(out, "- Frame %d\n", i); \
-	}
-
-#ifdef CONFIG_PROC_FS
 static const char * const qh_names[] = {
+  "skel_unlink_qh", "skel_iso_qh",
   "skel_int128_qh", "skel_int64_qh",
   "skel_int32_qh", "skel_int16_qh",
   "skel_int8_qh", "skel_int4_qh",
@@ -206,12 +209,6 @@
   "skel_bulk_qh", "skel_term_qh"
 };
 
-#define show_qh_name()		\
-	if (!shown) {		\
-	  shown = 1;		\
-	  out += sprintf(out, "- %s\n", qh_names[i]); \
-	}
-
 static int uhci_show_sc(int port, unsigned short status, char *buf, int len)
 {
 	char *out = buf;
@@ -321,139 +318,29 @@
 	return out - buf;
 }
 
-static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp, char *buf, int len)
-{
-	struct list_head *tmp;
-	char *out = buf;
-	int count = 0;
-
-	if (len < 200)
-		return 0;
-
-	out += sprintf(out, "urb_priv [%p] ", urbp);
-	out += sprintf(out, "urb [%p] ", urbp->urb);
-	out += sprintf(out, "qh [%p] ", urbp->qh);
-	out += sprintf(out, "Dev=%d ", usb_pipedevice(urbp->urb->pipe));
-	out += sprintf(out, "EP=%x(%s) ", usb_pipeendpoint(urbp->urb->pipe), (usb_pipein(urbp->urb->pipe) ? "IN" : "OUT"));
-
-	switch (usb_pipetype(urbp->urb->pipe)) {
-	case PIPE_ISOCHRONOUS: out += sprintf(out, "ISO "); break;
-	case PIPE_INTERRUPT: out += sprintf(out, "INT "); break;
-	case PIPE_BULK: out += sprintf(out, "BLK "); break;
-	case PIPE_CONTROL: out += sprintf(out, "CTL "); break;
-	}
-
-	out += sprintf(out, "%s", (urbp->fsbr ? "FSBR " : ""));
-	out += sprintf(out, "%s", (urbp->fsbr_timeout ? "FSBR_TO " : ""));
-
-	if (urbp->urb->status != -EINPROGRESS)
-		out += sprintf(out, "Status=%d ", urbp->urb->status);
-	//out += sprintf(out, "FSBRtime=%lx ",urbp->fsbrtime);
-
-	count = 0;
-	list_for_each(tmp, &urbp->td_list)
-		count++;
-	out += sprintf(out, "TDs=%d ",count);
-
-	if (urbp->queued)
-		out += sprintf(out, "queued\n");
-	else {
-		count = 0;
-		list_for_each(tmp, &urbp->queue_list)
-			count++;
-		out += sprintf(out, "queued URBs=%d\n", count);
-	}
-
-	return out - buf;
-}
-
-static int uhci_show_lists(struct uhci_hcd *uhci, char *buf, int len)
-{
-	char *out = buf;
-	struct list_head *head, *tmp;
-	int count;
-
-	out += sprintf(out, "Main list URBs:");
-	if (list_empty(&uhci->urb_list))
-		out += sprintf(out, " Empty\n");
-	else {
-		out += sprintf(out, "\n");
-		count = 0;
-		head = &uhci->urb_list;
-		tmp = head->next;
-		while (tmp != head) {
-			struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list);
-
-			out += sprintf(out, "  %d: ", ++count);
-			out += uhci_show_urbp(uhci, urbp, out, len - (out - buf));
-			tmp = tmp->next;
-		}
-	}
-
-	out += sprintf(out, "Remove list URBs:");
-	if (list_empty(&uhci->urb_remove_list))
-		out += sprintf(out, " Empty\n");
-	else {
-		out += sprintf(out, "\n");
-		count = 0;
-		head = &uhci->urb_remove_list;
-		tmp = head->next;
-		while (tmp != head) {
-			struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list);
-
-			out += sprintf(out, "  %d: ", ++count);
-			out += uhci_show_urbp(uhci, urbp, out, len - (out - buf));
-			tmp = tmp->next;
-		}
-	}
-
-	out += sprintf(out, "Complete list URBs:");
-	if (list_empty(&uhci->complete_list))
-		out += sprintf(out, " Empty\n");
-	else {
-		out += sprintf(out, "\n");
-		count = 0;
-		head = &uhci->complete_list;
-		tmp = head->next;
-		while (tmp != head) {
-			struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list);
-
-			out += sprintf(out, "  %d: ", ++count);
-			out += uhci_show_urbp(uhci, urbp, out, len - (out - buf));
-			tmp = tmp->next;
-		}
-	}
-
-	return out - buf;
-}
-
 static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
 {
-	unsigned long flags;
 	char *out = buf;
 	int i, j;
 	struct uhci_qh *qh;
 	struct uhci_td *td;
 	struct list_head *tmp, *head;
 
-	spin_lock_irqsave(&uhci->lock, flags);
-
 	out += uhci_show_root_hub_state(uhci, out, len - (out - buf));
 	out += sprintf(out, "HC status\n");
 	out += uhci_show_status(uhci, out, len - (out - buf));
+	if (debug <= 1)
+		return out - buf;
 
 	out += sprintf(out, "Frame List\n");
 	for (i = 0; i < UHCI_NUMFRAMES; ++i) {
-		int shown = 0;
 		td = uhci->frame_cpu[i];
 		if (!td)
 			continue;
 
-		if (td->dma_handle != (dma_addr_t)uhci->frame[i]) {
-			show_frame_num();
+		out += sprintf(out, "- Frame %d\n", i); \
+		if (td->dma_handle != (dma_addr_t)uhci->frame[i])
 			out += sprintf(out, "    frame list does not match td->dma_handle!\n");
-		}
-		show_frame_num();
 
 		head = &td->fl_list;
 		tmp = head;
@@ -467,14 +354,11 @@
 	out += sprintf(out, "Skeleton QHs\n");
 
 	for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
-		int shown = 0;
+		int cnt = 0;
 
 		qh = uhci->skelqh[i];
-
-		if (debug > 1) {
-			show_qh_name();
-			out += uhci_show_qh(qh, out, len - (out - buf), 4);
-		}
+		out += sprintf(out, "- %s\n", qh_names[i]); \
+		out += uhci_show_qh(qh, out, len - (out - buf), 4);
 
 		/* Last QH is the Terminating QH, it's different */
 		if (i == UHCI_NUM_SKELQH - 1) {
@@ -487,53 +371,37 @@
 			continue;
 		}
 
-		j = (i < 7) ? 7 : i+1;		/* Next skeleton */
-		if (list_empty(&qh->list)) {
-			if (i < UHCI_NUM_SKELQH - 1) {
-				if (qh->link !=
-				    (cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH)) {
-					show_qh_name();
-					out += sprintf(out, "    skeleton QH not linked to next skeleton QH!\n");
-				}
-			}
-
-			continue;
-		}
-
-		show_qh_name();
-
-		head = &qh->list;
+		j = (i < 9) ? 9 : i+1;		/* Next skeleton */
+		head = &qh->node;
 		tmp = head->next;
 
 		while (tmp != head) {
-			qh = list_entry(tmp, struct uhci_qh, list);
-
+			qh = list_entry(tmp, struct uhci_qh, node);
 			tmp = tmp->next;
-
-			out += uhci_show_qh(qh, out, len - (out - buf), 4);
+			if (++cnt <= 10)
+				out += uhci_show_qh(qh, out,
+						len - (out - buf), 4);
 		}
+		if ((cnt -= 10) > 0)
+			out += sprintf(out, "    Skipped %d QHs\n", cnt);
 
-		if (i < UHCI_NUM_SKELQH - 1) {
+		if (i > 1 && i < UHCI_NUM_SKELQH - 1) {
 			if (qh->link !=
 			    (cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH))
 				out += sprintf(out, "    last QH not linked to next skeleton!\n");
 		}
 	}
 
-	if (debug > 2)
-		out += uhci_show_lists(uhci, out, len - (out - buf));
-
-	spin_unlock_irqrestore(&uhci->lock, flags);
-
 	return out - buf;
 }
 
+#ifdef CONFIG_DEBUG_FS
+
 #define MAX_OUTPUT	(64 * 1024)
 
 struct uhci_debug {
 	int size;
 	char *data;
-	struct uhci_hcd *uhci;
 };
 
 static int uhci_debug_open(struct inode *inode, struct file *file)
@@ -541,6 +409,7 @@
 	struct uhci_hcd *uhci = inode->u.generic_ip;
 	struct uhci_debug *up;
 	int ret = -ENOMEM;
+	unsigned long flags;
 
 	lock_kernel();
 	up = kmalloc(sizeof(*up), GFP_KERNEL);
@@ -553,7 +422,11 @@
 		goto out;
 	}
 
-	up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT);
+	up->size = 0;
+	spin_lock_irqsave(&uhci->lock, flags);
+	if (uhci->is_initialized)
+		up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT);
+	spin_unlock_irqrestore(&uhci->lock, flags);
 
 	file->private_data = up;
 
@@ -604,15 +477,32 @@
 	return 0;
 }
 
+#undef uhci_debug_operations
 static struct file_operations uhci_debug_operations = {
+	.owner =	THIS_MODULE,
 	.open =		uhci_debug_open,
 	.llseek =	uhci_debug_lseek,
 	.read =		uhci_debug_read,
 	.release =	uhci_debug_release,
 };
 
-#else	/* CONFIG_DEBUG_FS */
+#endif	/* CONFIG_DEBUG_FS */
 
-#define uhci_debug_operations (* (struct file_operations *) NULL)
+#else	/* DEBUG */
+
+static inline void lprintk(char *buf)
+{}
+
+static inline int uhci_show_qh(struct uhci_qh *qh, char *buf,
+		int len, int space)
+{
+	return 0;
+}
+
+static inline int uhci_sprint_schedule(struct uhci_hcd *uhci,
+		char *buf, int len)
+{
+	return 0;
+}
 
 #endif
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index dfe121d..4edb833 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -54,7 +54,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v2.3"
+#define DRIVER_VERSION "v3.0"
 #define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, \
 Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, \
 Alan Stern"
@@ -68,12 +68,16 @@
  * debug = 3, show all TDs in URBs when dumping
  */
 #ifdef DEBUG
+#define DEBUG_CONFIGURED	1
 static int debug = 1;
-#else
-static int debug = 0;
-#endif
 module_param(debug, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug level");
+
+#else
+#define DEBUG_CONFIGURED	0
+#define debug			0
+#endif
+
 static char *errbuf;
 #define ERRBUF_LEN    (32 * 1024)
 
@@ -338,6 +342,12 @@
 				dev_err(uhci_dev(uhci),
 					"host controller halted, "
 					"very bad!\n");
+				if (debug > 1 && errbuf) {
+					/* Print the schedule for debugging */
+					uhci_sprint_schedule(uhci,
+							errbuf, ERRBUF_LEN);
+					lprintk(errbuf);
+				}
 				hc_died(uhci);
 
 				/* Force a callback in case there are
@@ -376,6 +386,14 @@
 {
 	int i;
 
+	if (DEBUG_CONFIGURED) {
+		spin_lock_irq(&uhci->lock);
+		uhci->is_initialized = 0;
+		spin_unlock_irq(&uhci->lock);
+
+		debugfs_remove(uhci->dentry);
+	}
+
 	for (i = 0; i < UHCI_NUM_SKELQH; i++)
 		uhci_free_qh(uhci, uhci->skelqh[i]);
 
@@ -390,8 +408,6 @@
 	dma_free_coherent(uhci_dev(uhci),
 			UHCI_NUMFRAMES * sizeof(*uhci->frame),
 			uhci->frame, uhci->frame_dma_handle);
-
-	debugfs_remove(uhci->dentry);
 }
 
 static int uhci_reset(struct usb_hcd *hcd)
@@ -474,33 +490,29 @@
 
 	hcd->uses_new_polling = 1;
 
-	dentry = debugfs_create_file(hcd->self.bus_name,
-			S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root, uhci,
-			&uhci_debug_operations);
-	if (!dentry) {
-		dev_err(uhci_dev(uhci),
-				"couldn't create uhci debugfs entry\n");
-		retval = -ENOMEM;
-		goto err_create_debug_entry;
-	}
-	uhci->dentry = dentry;
-
 	uhci->fsbr = 0;
 	uhci->fsbrtimeout = 0;
 
 	spin_lock_init(&uhci->lock);
-	INIT_LIST_HEAD(&uhci->qh_remove_list);
 
 	INIT_LIST_HEAD(&uhci->td_remove_list);
-
-	INIT_LIST_HEAD(&uhci->urb_remove_list);
-
-	INIT_LIST_HEAD(&uhci->urb_list);
-
-	INIT_LIST_HEAD(&uhci->complete_list);
+	INIT_LIST_HEAD(&uhci->idle_qh_list);
 
 	init_waitqueue_head(&uhci->waitqh);
 
+	if (DEBUG_CONFIGURED) {
+		dentry = debugfs_create_file(hcd->self.bus_name,
+				S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root,
+				uhci, &uhci_debug_operations);
+		if (!dentry) {
+			dev_err(uhci_dev(uhci), "couldn't create uhci "
+					"debugfs entry\n");
+			retval = -ENOMEM;
+			goto err_create_debug_entry;
+		}
+		uhci->dentry = dentry;
+	}
+
 	uhci->frame = dma_alloc_coherent(uhci_dev(uhci),
 			UHCI_NUMFRAMES * sizeof(*uhci->frame),
 			&uhci->frame_dma_handle, 0);
@@ -540,7 +552,7 @@
 	}
 
 	for (i = 0; i < UHCI_NUM_SKELQH; i++) {
-		uhci->skelqh[i] = uhci_alloc_qh(uhci);
+		uhci->skelqh[i] = uhci_alloc_qh(uhci, NULL, NULL);
 		if (!uhci->skelqh[i]) {
 			dev_err(uhci_dev(uhci), "unable to allocate QH\n");
 			goto err_alloc_skelqh;
@@ -557,13 +569,17 @@
 			uhci->skel_int16_qh->link =
 			uhci->skel_int8_qh->link =
 			uhci->skel_int4_qh->link =
-			uhci->skel_int2_qh->link =
-			cpu_to_le32(uhci->skel_int1_qh->dma_handle) | UHCI_PTR_QH;
-	uhci->skel_int1_qh->link = cpu_to_le32(uhci->skel_ls_control_qh->dma_handle) | UHCI_PTR_QH;
+			uhci->skel_int2_qh->link = UHCI_PTR_QH |
+			cpu_to_le32(uhci->skel_int1_qh->dma_handle);
 
-	uhci->skel_ls_control_qh->link = cpu_to_le32(uhci->skel_fs_control_qh->dma_handle) | UHCI_PTR_QH;
-	uhci->skel_fs_control_qh->link = cpu_to_le32(uhci->skel_bulk_qh->dma_handle) | UHCI_PTR_QH;
-	uhci->skel_bulk_qh->link = cpu_to_le32(uhci->skel_term_qh->dma_handle) | UHCI_PTR_QH;
+	uhci->skel_int1_qh->link = UHCI_PTR_QH |
+			cpu_to_le32(uhci->skel_ls_control_qh->dma_handle);
+	uhci->skel_ls_control_qh->link = UHCI_PTR_QH |
+			cpu_to_le32(uhci->skel_fs_control_qh->dma_handle);
+	uhci->skel_fs_control_qh->link = UHCI_PTR_QH |
+			cpu_to_le32(uhci->skel_bulk_qh->dma_handle);
+	uhci->skel_bulk_qh->link = UHCI_PTR_QH |
+			cpu_to_le32(uhci->skel_term_qh->dma_handle);
 
 	/* This dummy TD is to work around a bug in Intel PIIX controllers */
 	uhci_fill_td(uhci->term_td, 0, uhci_explen(0) |
@@ -589,15 +605,15 @@
 
 		/*
 		 * ffs (Find First bit Set) does exactly what we need:
-		 * 1,3,5,...  => ffs = 0 => use skel_int2_qh = skelqh[6],
-		 * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[5], etc.
-		 * ffs > 6 => not on any high-period queue, so use
-		 *	skel_int1_qh = skelqh[7].
+		 * 1,3,5,...  => ffs = 0 => use skel_int2_qh = skelqh[8],
+		 * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc.
+		 * ffs >= 7 => not on any high-period queue, so use
+		 *	skel_int1_qh = skelqh[9].
 		 * Add UHCI_NUMFRAMES to insure at least one bit is set.
 		 */
-		irq = 6 - (int) __ffs(i + UHCI_NUMFRAMES);
-		if (irq < 0)
-			irq = 7;
+		irq = 8 - (int) __ffs(i + UHCI_NUMFRAMES);
+		if (irq <= 1)
+			irq = 9;
 
 		/* Only place we don't use the frame list routines */
 		uhci->frame[i] = UHCI_PTR_QH |
@@ -611,6 +627,7 @@
 	mb();
 
 	configure_hc(uhci);
+	uhci->is_initialized = 1;
 	start_rh(uhci);
 	return 0;
 
@@ -767,13 +784,30 @@
 }
 #endif
 
-/* Wait until all the URBs for a particular device/endpoint are gone */
+/* Wait until a particular device/endpoint's QH is idle, and free it */
 static void uhci_hcd_endpoint_disable(struct usb_hcd *hcd,
-		struct usb_host_endpoint *ep)
+		struct usb_host_endpoint *hep)
 {
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+	struct uhci_qh *qh;
 
-	wait_event_interruptible(uhci->waitqh, list_empty(&ep->urb_list));
+	spin_lock_irq(&uhci->lock);
+	qh = (struct uhci_qh *) hep->hcpriv;
+	if (qh == NULL)
+		goto done;
+
+	while (qh->state != QH_STATE_IDLE) {
+		++uhci->num_waiting;
+		spin_unlock_irq(&uhci->lock);
+		wait_event_interruptible(uhci->waitqh,
+				qh->state == QH_STATE_IDLE);
+		spin_lock_irq(&uhci->lock);
+		--uhci->num_waiting;
+	}
+
+	uhci_free_qh(uhci, qh);
+done:
+	spin_unlock_irq(&uhci->lock);
 }
 
 static int uhci_hcd_get_frame_number(struct usb_hcd *hcd)
@@ -857,16 +891,15 @@
 	if (usb_disabled())
 		return -ENODEV;
 
-	if (debug) {
+	if (DEBUG_CONFIGURED) {
 		errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL);
 		if (!errbuf)
 			goto errbuf_failed;
+		uhci_debugfs_root = debugfs_create_dir("uhci", NULL);
+		if (!uhci_debugfs_root)
+			goto debug_failed;
 	}
 
-	uhci_debugfs_root = debugfs_create_dir("uhci", NULL);
-	if (!uhci_debugfs_root)
-		goto debug_failed;
-
 	uhci_up_cachep = kmem_cache_create("uhci_urb_priv",
 		sizeof(struct urb_priv), 0, 0, NULL, NULL);
 	if (!uhci_up_cachep)
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index 8b4b887..4a69c7e 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -28,8 +28,9 @@
 #define   USBSTS_USBINT		0x0001	/* Interrupt due to IOC */
 #define   USBSTS_ERROR		0x0002	/* Interrupt due to error */
 #define   USBSTS_RD		0x0004	/* Resume Detect */
-#define   USBSTS_HSE		0x0008	/* Host System Error - basically PCI problems */
-#define   USBSTS_HCPE		0x0010	/* Host Controller Process Error - the scripts were buggy */
+#define   USBSTS_HSE		0x0008	/* Host System Error: PCI problems */
+#define   USBSTS_HCPE		0x0010	/* Host Controller Process Error:
+					 * the schedule is buggy */
 #define   USBSTS_HCH		0x0020	/* HC Halted */
 
 /* Interrupt enable register */
@@ -47,7 +48,8 @@
 /* USB port status and control registers */
 #define USBPORTSC1	16
 #define USBPORTSC2	18
-#define   USBPORTSC_CCS		0x0001	/* Current Connect Status ("device present") */
+#define   USBPORTSC_CCS		0x0001	/* Current Connect Status
+					 * ("device present") */
 #define   USBPORTSC_CSC		0x0002	/* Connect Status Change */
 #define   USBPORTSC_PE		0x0004	/* Port Enable */
 #define   USBPORTSC_PEC		0x0008	/* Port Enable Change */
@@ -71,15 +73,16 @@
 #define   USBLEGSUP_RWC		0x8f00	/* the R/WC bits */
 #define   USBLEGSUP_RO		0x5040	/* R/O and reserved bits */
 
-#define UHCI_PTR_BITS		cpu_to_le32(0x000F)
-#define UHCI_PTR_TERM		cpu_to_le32(0x0001)
-#define UHCI_PTR_QH		cpu_to_le32(0x0002)
-#define UHCI_PTR_DEPTH		cpu_to_le32(0x0004)
-#define UHCI_PTR_BREADTH	cpu_to_le32(0x0000)
+#define UHCI_PTR_BITS		__constant_cpu_to_le32(0x000F)
+#define UHCI_PTR_TERM		__constant_cpu_to_le32(0x0001)
+#define UHCI_PTR_QH		__constant_cpu_to_le32(0x0002)
+#define UHCI_PTR_DEPTH		__constant_cpu_to_le32(0x0004)
+#define UHCI_PTR_BREADTH	__constant_cpu_to_le32(0x0000)
 
 #define UHCI_NUMFRAMES		1024	/* in the frame list [array] */
 #define UHCI_MAX_SOF_NUMBER	2047	/* in an SOF packet */
-#define CAN_SCHEDULE_FRAMES	1000	/* how far future frames can be scheduled */
+#define CAN_SCHEDULE_FRAMES	1000	/* how far in the future frames
+					 * can be scheduled */
 
 
 /*
@@ -87,38 +90,59 @@
  */
 
 /*
- * One role of a QH is to hold a queue of TDs for some endpoint.  Each QH is
- * used with one URB, and qh->element (updated by the HC) is either:
- *   - the next unprocessed TD for the URB, or
- *   - UHCI_PTR_TERM (when there's no more traffic for this endpoint), or
- *   - the QH for the next URB queued to the same endpoint.
+ * One role of a QH is to hold a queue of TDs for some endpoint.  One QH goes
+ * with each endpoint, and qh->element (updated by the HC) is either:
+ *   - the next unprocessed TD in the endpoint's queue, or
+ *   - UHCI_PTR_TERM (when there's no more traffic for this endpoint).
  *
  * The other role of a QH is to serve as a "skeleton" framelist entry, so we
  * can easily splice a QH for some endpoint into the schedule at the right
  * place.  Then qh->element is UHCI_PTR_TERM.
  *
- * In the frame list, qh->link maintains a list of QHs seen by the HC:
+ * In the schedule, qh->link maintains a list of QHs seen by the HC:
  *     skel1 --> ep1-qh --> ep2-qh --> ... --> skel2 --> ...
+ *
+ * qh->node is the software equivalent of qh->link.  The differences
+ * are that the software list is doubly-linked and QHs in the UNLINKING
+ * state are on the software list but not the hardware schedule.
+ *
+ * For bookkeeping purposes we maintain QHs even for Isochronous endpoints,
+ * but they never get added to the hardware schedule.
  */
+#define QH_STATE_IDLE		1	/* QH is not being used */
+#define QH_STATE_UNLINKING	2	/* QH has been removed from the
+					 * schedule but the hardware may
+					 * still be using it */
+#define QH_STATE_ACTIVE		3	/* QH is on the schedule */
+
 struct uhci_qh {
 	/* Hardware fields */
-	__le32 link;			/* Next queue */
-	__le32 element;			/* Queue element pointer */
+	__le32 link;			/* Next QH in the schedule */
+	__le32 element;			/* Queue element (TD) pointer */
 
 	/* Software fields */
 	dma_addr_t dma_handle;
 
-	struct urb_priv *urbp;
+	struct list_head node;		/* Node in the list of QHs */
+	struct usb_host_endpoint *hep;	/* Endpoint information */
+	struct usb_device *udev;
+	struct list_head queue;		/* Queue of urbps for this QH */
+	struct uhci_qh *skel;		/* Skeleton for this QH */
+	struct uhci_td *dummy_td;	/* Dummy TD to end the queue */
 
-	struct list_head list;
-	struct list_head remove_list;
+	unsigned int unlink_frame;	/* When the QH was unlinked */
+	int state;			/* QH_STATE_xxx; see above */
+
+	unsigned int initial_toggle:1;	/* Endpoint's current toggle value */
+	unsigned int needs_fixup:1;	/* Must fix the TD toggle values */
+	unsigned int is_stopped:1;	/* Queue was stopped by an error */
 } __attribute__((aligned(16)));
 
 /*
  * We need a special accessor for the element pointer because it is
  * subject to asynchronous updates by the controller.
  */
-static __le32 inline qh_element(struct uhci_qh *qh) {
+static inline __le32 qh_element(struct uhci_qh *qh) {
 	__le32 element = qh->element;
 
 	barrier();
@@ -149,11 +173,13 @@
 #define TD_CTRL_ACTLEN_MASK	0x7FF	/* actual length, encoded as n - 1 */
 
 #define TD_CTRL_ANY_ERROR	(TD_CTRL_STALLED | TD_CTRL_DBUFERR | \
-				 TD_CTRL_BABBLE | TD_CTRL_CRCTIME | TD_CTRL_BITSTUFF)
+				 TD_CTRL_BABBLE | TD_CTRL_CRCTIME | \
+				 TD_CTRL_BITSTUFF)
 
 #define uhci_maxerr(err)		((err) << TD_CTRL_C_ERR_SHIFT)
 #define uhci_status_bits(ctrl_sts)	((ctrl_sts) & 0xF60000)
-#define uhci_actual_length(ctrl_sts)	(((ctrl_sts) + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */
+#define uhci_actual_length(ctrl_sts)	(((ctrl_sts) + 1) & \
+			TD_CTRL_ACTLEN_MASK)	/* 1-based */
 
 /*
  * for TD <info>: (a.k.a. Token)
@@ -163,7 +189,7 @@
 #define TD_TOKEN_TOGGLE_SHIFT	19
 #define TD_TOKEN_TOGGLE		(1 << 19)
 #define TD_TOKEN_EXPLEN_SHIFT	21
-#define TD_TOKEN_EXPLEN_MASK	0x7FF		/* expected length, encoded as n - 1 */
+#define TD_TOKEN_EXPLEN_MASK	0x7FF	/* expected length, encoded as n-1 */
 #define TD_TOKEN_PID_MASK	0xFF
 
 #define uhci_explen(len)	((((len) - 1) & TD_TOKEN_EXPLEN_MASK) << \
@@ -187,7 +213,7 @@
  * sw space after the TD entry.
  *
  * td->link points to either another TD (not necessarily for the same urb or
- * even the same endpoint), or nothing (PTR_TERM), or a QH (for queued urbs).
+ * even the same endpoint), or nothing (PTR_TERM), or a QH.
  */
 struct uhci_td {
 	/* Hardware fields */
@@ -210,7 +236,7 @@
  * We need a special accessor for the control/status word because it is
  * subject to asynchronous updates by the controller.
  */
-static u32 inline td_status(struct uhci_td *td) {
+static inline u32 td_status(struct uhci_td *td) {
 	__le32 status = td->status;
 
 	barrier();
@@ -223,17 +249,14 @@
  */
 
 /*
- * The UHCI driver places Interrupt, Control and Bulk into QHs both
- * to group together TDs for one transfer, and also to facilitate queuing
- * of URBs. To make it easy to insert entries into the schedule, we have
- * a skeleton of QHs for each predefined Interrupt latency, low-speed
- * control, full-speed control and terminating QH (see explanation for
- * the terminating QH below).
+ * The UHCI driver uses QHs with Interrupt, Control and Bulk URBs for
+ * automatic queuing. To make it easy to insert entries into the schedule,
+ * we have a skeleton of QHs for each predefined Interrupt latency,
+ * low-speed control, full-speed control, bulk, and terminating QH
+ * (see explanation for the terminating QH below).
  *
  * When we want to add a new QH, we add it to the end of the list for the
- * skeleton QH.
- *
- * For instance, the queue can look like this:
+ * skeleton QH.  For instance, the schedule list can look like this:
  *
  * skel int128 QH
  * dev 1 interrupt QH
@@ -256,26 +279,31 @@
  * - To loop back to the full-speed control queue for full-speed bandwidth
  *   reclamation.
  *
- * Isochronous transfers are stored before the start of the skeleton
- * schedule and don't use QHs. While the UHCI spec doesn't forbid the
- * use of QHs for Isochronous, it doesn't use them either. And the spec
- * says that queues never advance on an error completion status, which
- * makes them totally unsuitable for Isochronous transfers.
+ * There's a special skeleton QH for Isochronous QHs.  It never appears
+ * on the schedule, and Isochronous TDs go on the schedule before the
+ * the skeleton QHs.  The hardware accesses them directly rather than
+ * through their QH, which is used only for bookkeeping purposes.
+ * While the UHCI spec doesn't forbid the use of QHs for Isochronous,
+ * it doesn't use them either.  And the spec says that queues never
+ * advance on an error completion status, which makes them totally
+ * unsuitable for Isochronous transfers.
  */
 
-#define UHCI_NUM_SKELQH		12
-#define skel_int128_qh		skelqh[0]
-#define skel_int64_qh		skelqh[1]
-#define skel_int32_qh		skelqh[2]
-#define skel_int16_qh		skelqh[3]
-#define skel_int8_qh		skelqh[4]
-#define skel_int4_qh		skelqh[5]
-#define skel_int2_qh		skelqh[6]
-#define skel_int1_qh		skelqh[7]
-#define skel_ls_control_qh	skelqh[8]
-#define skel_fs_control_qh	skelqh[9]
-#define skel_bulk_qh		skelqh[10]
-#define skel_term_qh		skelqh[11]
+#define UHCI_NUM_SKELQH		14
+#define skel_unlink_qh		skelqh[0]
+#define skel_iso_qh		skelqh[1]
+#define skel_int128_qh		skelqh[2]
+#define skel_int64_qh		skelqh[3]
+#define skel_int32_qh		skelqh[4]
+#define skel_int16_qh		skelqh[5]
+#define skel_int8_qh		skelqh[6]
+#define skel_int4_qh		skelqh[7]
+#define skel_int2_qh		skelqh[8]
+#define skel_int1_qh		skelqh[9]
+#define skel_ls_control_qh	skelqh[10]
+#define skel_fs_control_qh	skelqh[11]
+#define skel_bulk_qh		skelqh[12]
+#define skel_term_qh		skelqh[13]
 
 /*
  * Search tree for determining where <interval> fits in the skelqh[]
@@ -293,21 +321,21 @@
 	if (interval < 16) {
 		if (interval < 4) {
 			if (interval < 2)
-				return 7;	/* int1 for 0-1 ms */
-			return 6;		/* int2 for 2-3 ms */
+				return 9;	/* int1 for 0-1 ms */
+			return 8;		/* int2 for 2-3 ms */
 		}
 		if (interval < 8)
-			return 5;		/* int4 for 4-7 ms */
-		return 4;			/* int8 for 8-15 ms */
+			return 7;		/* int4 for 4-7 ms */
+		return 6;			/* int8 for 8-15 ms */
 	}
 	if (interval < 64) {
 		if (interval < 32)
-			return 3;		/* int16 for 16-31 ms */
-		return 2;			/* int32 for 32-63 ms */
+			return 5;		/* int16 for 16-31 ms */
+		return 4;			/* int32 for 32-63 ms */
 	}
 	if (interval < 128)
-		return 1;			/* int64 for 64-127 ms */
-	return 0;				/* int128 for 128-255 ms (Max.) */
+		return 3;			/* int64 for 64-127 ms */
+	return 2;				/* int128 for 128-255 ms (Max.) */
 }
 
 
@@ -360,15 +388,16 @@
 
 	struct uhci_td *term_td;	/* Terminating TD, see UHCI bug */
 	struct uhci_qh *skelqh[UHCI_NUM_SKELQH];	/* Skeleton QHs */
+	struct uhci_qh *next_qh;	/* Next QH to scan */
 
 	spinlock_t lock;
 
-	dma_addr_t frame_dma_handle;		/* Hardware frame list */
+	dma_addr_t frame_dma_handle;	/* Hardware frame list */
 	__le32 *frame;
-	void **frame_cpu;			/* CPU's frame list */
+	void **frame_cpu;		/* CPU's frame list */
 
-	int fsbr;				/* Full-speed bandwidth reclamation */
-	unsigned long fsbrtimeout;		/* FSBR delay */
+	int fsbr;			/* Full-speed bandwidth reclamation */
+	unsigned long fsbrtimeout;	/* FSBR delay */
 
 	enum uhci_rh_state rh_state;
 	unsigned long auto_stop_time;		/* When to AUTO_STOP */
@@ -382,6 +411,7 @@
 	unsigned int hc_inaccessible:1;		/* HC is suspended or dead */
 	unsigned int working_RD:1;		/* Suspended root hub doesn't
 						   need to be polled */
+	unsigned int is_initialized:1;		/* Data structure is usable */
 
 	/* Support for port suspend/resume/reset */
 	unsigned long port_c_suspend;		/* Bit-arrays of ports */
@@ -389,27 +419,16 @@
 	unsigned long resuming_ports;
 	unsigned long ports_timeout;		/* Time to stop signalling */
 
-	/* Main list of URBs currently controlled by this HC */
-	struct list_head urb_list;
-
-	/* List of QHs that are done, but waiting to be unlinked (race) */
-	struct list_head qh_remove_list;
-	unsigned int qh_remove_age;		/* Age in frames */
-
 	/* List of TDs that are done, but waiting to be freed (race) */
 	struct list_head td_remove_list;
 	unsigned int td_remove_age;		/* Age in frames */
 
-	/* List of asynchronously unlinked URBs */
-	struct list_head urb_remove_list;
-	unsigned int urb_remove_age;		/* Age in frames */
-
-	/* List of URBs awaiting completion callback */
-	struct list_head complete_list;
+	struct list_head idle_qh_list;		/* Where the idle QHs live */
 
 	int rh_numports;			/* Number of root-hub ports */
 
 	wait_queue_head_t waitqh;		/* endpoint_disable waiters */
+	int num_waiting;			/* Number of waiters */
 };
 
 /* Convert between a usb_hcd pointer and the corresponding uhci_hcd */
@@ -429,7 +448,7 @@
  *	Private per-URB data
  */
 struct urb_priv {
-	struct list_head urb_list;
+	struct list_head node;		/* Node in the QH's urbp list */
 
 	struct urb *urb;
 
@@ -437,15 +456,8 @@
 	struct list_head td_list;
 
 	unsigned fsbr : 1;		/* URB turned on FSBR */
-	unsigned fsbr_timeout : 1;	/* URB timed out on FSBR */
-	unsigned queued : 1;		/* QH was queued (not linked in) */
-	unsigned short_control_packet : 1;	/* If we get a short packet during */
-						/*  a control transfer, retrigger */
-						/*  the status phase */
-
-	unsigned long fsbrtime;		/* In jiffies */
-
-	struct list_head queue_list;
+	unsigned short_transfer : 1;	/* URB got a short transfer, no
+					 * need to rescan */
 };
 
 
diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c
index a71e48a..152971d 100644
--- a/drivers/usb/host/uhci-hub.c
+++ b/drivers/usb/host/uhci-hub.c
@@ -99,6 +99,21 @@
 	}
 }
 
+/* Wait for the UHCI controller in HP's iLO2 server management chip.
+ * It can take up to 250 us to finish a reset and set the CSC bit.
+ */
+static void wait_for_HP(unsigned long port_addr)
+{
+	int i;
+
+	for (i = 10; i < 250; i += 10) {
+		if (inw(port_addr) & USBPORTSC_CSC)
+			return;
+		udelay(10);
+	}
+	/* Log a warning? */
+}
+
 static void uhci_check_ports(struct uhci_hcd *uhci)
 {
 	unsigned int port;
@@ -113,6 +128,12 @@
 				CLR_RH_PORTSTAT(USBPORTSC_PR);
 				udelay(10);
 
+				/* HP's server management chip requires
+				 * a longer delay. */
+				if (to_pci_dev(uhci_dev(uhci))->vendor ==
+						PCI_VENDOR_ID_HP)
+					wait_for_HP(port_addr);
+
 				/* If the port was enabled before, turning
 				 * reset on caused a port enable change.
 				 * Turning reset off causes a port connect
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 7823980..a06d84c 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -13,13 +13,9 @@
  * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
  *               support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
  * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
- * (C) Copyright 2004 Alan Stern, stern@rowland.harvard.edu
+ * (C) Copyright 2004-2005 Alan Stern, stern@rowland.harvard.edu
  */
 
-static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb);
-static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb);
-static void uhci_remove_pending_urbps(struct uhci_hcd *uhci);
-static void uhci_free_pending_qhs(struct uhci_hcd *uhci);
 static void uhci_free_pending_tds(struct uhci_hcd *uhci);
 
 /*
@@ -30,7 +26,7 @@
  * games with the FSBR code to make sure we get the correct order in all
  * the cases. I don't think it's worth the effort
  */
-static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci)
+static void uhci_set_next_interrupt(struct uhci_hcd *uhci)
 {
 	if (uhci->is_stopped)
 		mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies);
@@ -42,12 +38,6 @@
 	uhci->term_td->status &= ~cpu_to_le32(TD_CTRL_IOC);
 }
 
-static inline void uhci_moveto_complete(struct uhci_hcd *uhci, 
-					struct urb_priv *urbp)
-{
-	list_move_tail(&urbp->urb_list, &uhci->complete_list);
-}
-
 static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci)
 {
 	dma_addr_t dma_handle;
@@ -58,10 +48,6 @@
 		return NULL;
 
 	td->dma_handle = dma_handle;
-
-	td->link = UHCI_PTR_TERM;
-	td->buffer = 0;
-
 	td->frame = -1;
 
 	INIT_LIST_HEAD(&td->list);
@@ -71,6 +57,18 @@
 	return td;
 }
 
+static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td)
+{
+	if (!list_empty(&td->list))
+		dev_warn(uhci_dev(uhci), "td %p still in list!\n", td);
+	if (!list_empty(&td->remove_list))
+		dev_warn(uhci_dev(uhci), "td %p still in remove_list!\n", td);
+	if (!list_empty(&td->fl_list))
+		dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td);
+
+	dma_pool_free(uhci->td_pool, td, td->dma_handle);
+}
+
 static inline void uhci_fill_td(struct uhci_td *td, u32 status,
 		u32 token, u32 buffer)
 {
@@ -82,7 +80,8 @@
 /*
  * We insert Isochronous URBs directly into the frame list at the beginning
  */
-static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td, unsigned framenum)
+static inline void uhci_insert_td_in_frame_list(struct uhci_hcd *uhci,
+		struct uhci_td *td, unsigned framenum)
 {
 	framenum &= (UHCI_NUMFRAMES - 1);
 
@@ -108,7 +107,7 @@
 	}
 }
 
-static inline void uhci_remove_td_frame_list(struct uhci_hcd *uhci,
+static inline void uhci_remove_td_from_frame_list(struct uhci_hcd *uhci,
 		struct uhci_td *td)
 {
 	/* If it's not inserted, don't remove it */
@@ -139,48 +138,21 @@
 	td->frame = -1;
 }
 
-static void unlink_isochronous_tds(struct uhci_hcd *uhci, struct urb *urb)
+/*
+ * Remove all the TDs for an Isochronous URB from the frame list
+ */
+static void uhci_unlink_isochronous_tds(struct uhci_hcd *uhci, struct urb *urb)
 {
 	struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
 	struct uhci_td *td;
 
 	list_for_each_entry(td, &urbp->td_list, list)
-		uhci_remove_td_frame_list(uhci, td);
+		uhci_remove_td_from_frame_list(uhci, td);
 	wmb();
 }
 
-/*
- * Inserts a td list into qh.
- */
-static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, __le32 breadth)
-{
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct uhci_td *td;
-	__le32 *plink;
-
-	/* Ordering isn't important here yet since the QH hasn't been */
-	/* inserted into the schedule yet */
-	plink = &qh->element;
-	list_for_each_entry(td, &urbp->td_list, list) {
-		*plink = cpu_to_le32(td->dma_handle) | breadth;
-		plink = &td->link;
-	}
-	*plink = UHCI_PTR_TERM;
-}
-
-static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td)
-{
-	if (!list_empty(&td->list))
-		dev_warn(uhci_dev(uhci), "td %p still in list!\n", td);
-	if (!list_empty(&td->remove_list))
-		dev_warn(uhci_dev(uhci), "td %p still in remove_list!\n", td);
-	if (!list_empty(&td->fl_list))
-		dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td);
-
-	dma_pool_free(uhci->td_pool, td, td->dma_handle);
-}
-
-static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci)
+static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci,
+		struct usb_device *udev, struct usb_host_endpoint *hep)
 {
 	dma_addr_t dma_handle;
 	struct uhci_qh *qh;
@@ -194,256 +166,217 @@
 	qh->element = UHCI_PTR_TERM;
 	qh->link = UHCI_PTR_TERM;
 
-	qh->urbp = NULL;
+	INIT_LIST_HEAD(&qh->queue);
+	INIT_LIST_HEAD(&qh->node);
 
-	INIT_LIST_HEAD(&qh->list);
-	INIT_LIST_HEAD(&qh->remove_list);
+	if (udev) {		/* Normal QH */
+		qh->dummy_td = uhci_alloc_td(uhci);
+		if (!qh->dummy_td) {
+			dma_pool_free(uhci->qh_pool, qh, dma_handle);
+			return NULL;
+		}
+		qh->state = QH_STATE_IDLE;
+		qh->hep = hep;
+		qh->udev = udev;
+		hep->hcpriv = qh;
 
+	} else {		/* Skeleton QH */
+		qh->state = QH_STATE_ACTIVE;
+		qh->udev = NULL;
+	}
 	return qh;
 }
 
 static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
 {
-	if (!list_empty(&qh->list))
+	WARN_ON(qh->state != QH_STATE_IDLE && qh->udev);
+	if (!list_empty(&qh->queue))
 		dev_warn(uhci_dev(uhci), "qh %p list not empty!\n", qh);
-	if (!list_empty(&qh->remove_list))
-		dev_warn(uhci_dev(uhci), "qh %p still in remove_list!\n", qh);
 
+	list_del(&qh->node);
+	if (qh->udev) {
+		qh->hep->hcpriv = NULL;
+		uhci_free_td(uhci, qh->dummy_td);
+	}
 	dma_pool_free(uhci->qh_pool, qh, qh->dma_handle);
 }
 
 /*
- * Append this urb's qh after the last qh in skelqh->list
- *
- * Note that urb_priv.queue_list doesn't have a separate queue head;
- * it's a ring with every element "live".
+ * When the currently executing URB is dequeued, save its current toggle value
  */
-static void uhci_insert_qh(struct uhci_hcd *uhci, struct uhci_qh *skelqh, struct urb *urb)
+static void uhci_save_toggle(struct uhci_qh *qh, struct urb *urb)
 {
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct urb_priv *turbp;
-	struct uhci_qh *lqh;
+	struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
+	struct uhci_td *td;
 
-	/* Grab the last QH */
-	lqh = list_entry(skelqh->list.prev, struct uhci_qh, list);
+	/* If the QH element pointer is UHCI_PTR_TERM then then currently
+	 * executing URB has already been unlinked, so this one isn't it. */
+	if (qh_element(qh) == UHCI_PTR_TERM ||
+				qh->queue.next != &urbp->node)
+		return;
+	qh->element = UHCI_PTR_TERM;
 
-	/* Point to the next skelqh */
-	urbp->qh->link = lqh->link;
-	wmb();				/* Ordering is important */
+	/* Only bulk and interrupt pipes have to worry about toggles */
+	if (!(usb_pipetype(urb->pipe) == PIPE_BULK ||
+			usb_pipetype(urb->pipe) == PIPE_INTERRUPT))
+		return;
 
-	/*
-	 * Patch QHs for previous endpoint's queued URBs?  HC goes
-	 * here next, not to the next skelqh it now points to.
-	 *
-	 *    lqh --> td ... --> qh ... --> td --> qh ... --> td
-	 *     |                 |                 |
-	 *     v                 v                 v
-	 *     +<----------------+-----------------+
-	 *     v
-	 *    newqh --> td ... --> td
-	 *     |
-	 *     v
-	 *    ...
-	 *
-	 * The HC could see (and use!) any of these as we write them.
-	 */
-	lqh->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH;
-	if (lqh->urbp) {
-		list_for_each_entry(turbp, &lqh->urbp->queue_list, queue_list)
-			turbp->qh->link = lqh->link;
+	/* Find the first active TD; that's the device's toggle state */
+	list_for_each_entry(td, &urbp->td_list, list) {
+		if (td_status(td) & TD_CTRL_ACTIVE) {
+			qh->needs_fixup = 1;
+			qh->initial_toggle = uhci_toggle(td_token(td));
+			return;
+		}
 	}
 
-	list_add_tail(&urbp->qh->list, &skelqh->list);
+	WARN_ON(1);
 }
 
 /*
- * Start removal of QH from schedule; it finishes next frame.
- * TDs should be unlinked before this is called.
+ * Fix up the data toggles for URBs in a queue, when one of them
+ * terminates early (short transfer, error, or dequeued).
  */
-static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
+static void uhci_fixup_toggles(struct uhci_qh *qh, int skip_first)
+{
+	struct urb_priv *urbp = NULL;
+	struct uhci_td *td;
+	unsigned int toggle = qh->initial_toggle;
+	unsigned int pipe;
+
+	/* Fixups for a short transfer start with the second URB in the
+	 * queue (the short URB is the first). */
+	if (skip_first)
+		urbp = list_entry(qh->queue.next, struct urb_priv, node);
+
+	/* When starting with the first URB, if the QH element pointer is
+	 * still valid then we know the URB's toggles are okay. */
+	else if (qh_element(qh) != UHCI_PTR_TERM)
+		toggle = 2;
+
+	/* Fix up the toggle for the URBs in the queue.  Normally this
+	 * loop won't run more than once: When an error or short transfer
+	 * occurs, the queue usually gets emptied. */
+	urbp = list_prepare_entry(urbp, &qh->queue, node);
+	list_for_each_entry_continue(urbp, &qh->queue, node) {
+
+		/* If the first TD has the right toggle value, we don't
+		 * need to change any toggles in this URB */
+		td = list_entry(urbp->td_list.next, struct uhci_td, list);
+		if (toggle > 1 || uhci_toggle(td_token(td)) == toggle) {
+			td = list_entry(urbp->td_list.next, struct uhci_td,
+					list);
+			toggle = uhci_toggle(td_token(td)) ^ 1;
+
+		/* Otherwise all the toggles in the URB have to be switched */
+		} else {
+			list_for_each_entry(td, &urbp->td_list, list) {
+				td->token ^= __constant_cpu_to_le32(
+							TD_TOKEN_TOGGLE);
+				toggle ^= 1;
+			}
+		}
+	}
+
+	wmb();
+	pipe = list_entry(qh->queue.next, struct urb_priv, node)->urb->pipe;
+	usb_settoggle(qh->udev, usb_pipeendpoint(pipe),
+			usb_pipeout(pipe), toggle);
+	qh->needs_fixup = 0;
+}
+
+/*
+ * Put a QH on the schedule in both hardware and software
+ */
+static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
 {
 	struct uhci_qh *pqh;
-	__le32 newlink;
 
-	if (!qh)
-		return;
+	WARN_ON(list_empty(&qh->queue));
 
-	/*
-	 * Only go through the hoops if it's actually linked in
-	 */
-	if (!list_empty(&qh->list)) {
+	/* Set the element pointer if it isn't set already.
+	 * This isn't needed for Isochronous queues, but it doesn't hurt. */
+	if (qh_element(qh) == UHCI_PTR_TERM) {
+		struct urb_priv *urbp = list_entry(qh->queue.next,
+				struct urb_priv, node);
+		struct uhci_td *td = list_entry(urbp->td_list.next,
+				struct uhci_td, list);
 
-		/* If our queue is nonempty, make the next URB the head */
-		if (!list_empty(&qh->urbp->queue_list)) {
-			struct urb_priv *nurbp;
-
-			nurbp = list_entry(qh->urbp->queue_list.next,
-					struct urb_priv, queue_list);
-			nurbp->queued = 0;
-			list_add(&nurbp->qh->list, &qh->list);
-			newlink = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH;
-		} else
-			newlink = qh->link;
-
-		/* Fix up the previous QH's queue to link to either
-		 * the new head of this queue or the start of the
-		 * next endpoint's queue. */
-		pqh = list_entry(qh->list.prev, struct uhci_qh, list);
-		pqh->link = newlink;
-		if (pqh->urbp) {
-			struct urb_priv *turbp;
-
-			list_for_each_entry(turbp, &pqh->urbp->queue_list,
-					queue_list)
-				turbp->qh->link = newlink;
-		}
-		wmb();
-
-		/* Leave qh->link in case the HC is on the QH now, it will */
-		/* continue the rest of the schedule */
-		qh->element = UHCI_PTR_TERM;
-
-		list_del_init(&qh->list);
+		qh->element = cpu_to_le32(td->dma_handle);
 	}
 
-	list_del_init(&qh->urbp->queue_list);
-	qh->urbp = NULL;
+	if (qh->state == QH_STATE_ACTIVE)
+		return;
+	qh->state = QH_STATE_ACTIVE;
+
+	/* Move the QH from its old list to the end of the appropriate
+	 * skeleton's list */
+	if (qh == uhci->next_qh)
+		uhci->next_qh = list_entry(qh->node.next, struct uhci_qh,
+				node);
+	list_move_tail(&qh->node, &qh->skel->node);
+
+	/* Link it into the schedule */
+	pqh = list_entry(qh->node.prev, struct uhci_qh, node);
+	qh->link = pqh->link;
+	wmb();
+	pqh->link = UHCI_PTR_QH | cpu_to_le32(qh->dma_handle);
+}
+
+/*
+ * Take a QH off the hardware schedule
+ */
+static void uhci_unlink_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+	struct uhci_qh *pqh;
+
+	if (qh->state == QH_STATE_UNLINKING)
+		return;
+	WARN_ON(qh->state != QH_STATE_ACTIVE || !qh->udev);
+	qh->state = QH_STATE_UNLINKING;
+
+	/* Unlink the QH from the schedule and record when we did it */
+	pqh = list_entry(qh->node.prev, struct uhci_qh, node);
+	pqh->link = qh->link;
+	mb();
 
 	uhci_get_current_frame_number(uhci);
-	if (uhci->frame_number + uhci->is_stopped != uhci->qh_remove_age) {
-		uhci_free_pending_qhs(uhci);
-		uhci->qh_remove_age = uhci->frame_number;
-	}
+	qh->unlink_frame = uhci->frame_number;
 
-	/* Check to see if the remove list is empty. Set the IOC bit */
-	/* to force an interrupt so we can remove the QH */
-	if (list_empty(&uhci->qh_remove_list))
+	/* Force an interrupt so we know when the QH is fully unlinked */
+	if (list_empty(&uhci->skel_unlink_qh->node))
 		uhci_set_next_interrupt(uhci);
 
-	list_add(&qh->remove_list, &uhci->qh_remove_list);
+	/* Move the QH from its old list to the end of the unlinking list */
+	if (qh == uhci->next_qh)
+		uhci->next_qh = list_entry(qh->node.next, struct uhci_qh,
+				node);
+	list_move_tail(&qh->node, &uhci->skel_unlink_qh->node);
 }
 
-static int uhci_fixup_toggle(struct urb *urb, unsigned int toggle)
+/*
+ * When we and the controller are through with a QH, it becomes IDLE.
+ * This happens when a QH has been off the schedule (on the unlinking
+ * list) for more than one frame, or when an error occurs while adding
+ * the first URB onto a new QH.
+ */
+static void uhci_make_qh_idle(struct uhci_hcd *uhci, struct uhci_qh *qh)
 {
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct uhci_td *td;
+	WARN_ON(qh->state == QH_STATE_ACTIVE);
 
-	list_for_each_entry(td, &urbp->td_list, list) {
-		if (toggle)
-			td->token |= cpu_to_le32(TD_TOKEN_TOGGLE);
-		else
-			td->token &= ~cpu_to_le32(TD_TOKEN_TOGGLE);
+	if (qh == uhci->next_qh)
+		uhci->next_qh = list_entry(qh->node.next, struct uhci_qh,
+				node);
+	list_move(&qh->node, &uhci->idle_qh_list);
+	qh->state = QH_STATE_IDLE;
 
-		toggle ^= 1;
-	}
-
-	return toggle;
+	/* If anyone is waiting for a QH to become idle, wake them up */
+	if (uhci->num_waiting)
+		wake_up_all(&uhci->waitqh);
 }
 
-/* This function will append one URB's QH to another URB's QH. This is for */
-/* queuing interrupt, control or bulk transfers */
-static void uhci_append_queued_urb(struct uhci_hcd *uhci, struct urb *eurb, struct urb *urb)
-{
-	struct urb_priv *eurbp, *urbp, *furbp, *lurbp;
-	struct uhci_td *lltd;
-
-	eurbp = eurb->hcpriv;
-	urbp = urb->hcpriv;
-
-	/* Find the first URB in the queue */
-	furbp = eurbp;
-	if (eurbp->queued) {
-		list_for_each_entry(furbp, &eurbp->queue_list, queue_list)
-			if (!furbp->queued)
-				break;
-	}
-
-	lurbp = list_entry(furbp->queue_list.prev, struct urb_priv, queue_list);
-
-	lltd = list_entry(lurbp->td_list.prev, struct uhci_td, list);
-
-	/* Control transfers always start with toggle 0 */
-	if (!usb_pipecontrol(urb->pipe))
-		usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-				usb_pipeout(urb->pipe),
-				uhci_fixup_toggle(urb,
-					uhci_toggle(td_token(lltd)) ^ 1));
-
-	/* All qhs in the queue need to link to the next queue */
-	urbp->qh->link = eurbp->qh->link;
-
-	wmb();			/* Make sure we flush everything */
-
-	lltd->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH;
-
-	list_add_tail(&urbp->queue_list, &furbp->queue_list);
-
-	urbp->queued = 1;
-}
-
-static void uhci_delete_queued_urb(struct uhci_hcd *uhci, struct urb *urb)
-{
-	struct urb_priv *urbp, *nurbp, *purbp, *turbp;
-	struct uhci_td *pltd;
-	unsigned int toggle;
-
-	urbp = urb->hcpriv;
-
-	if (list_empty(&urbp->queue_list))
-		return;
-
-	nurbp = list_entry(urbp->queue_list.next, struct urb_priv, queue_list);
-
-	/*
-	 * Fix up the toggle for the following URBs in the queue.
-	 * Only needed for bulk and interrupt: control and isochronous
-	 * endpoints don't propagate toggles between messages.
-	 */
-	if (usb_pipebulk(urb->pipe) || usb_pipeint(urb->pipe)) {
-		if (!urbp->queued)
-			/* We just set the toggle in uhci_unlink_generic */
-			toggle = usb_gettoggle(urb->dev,
-					usb_pipeendpoint(urb->pipe),
-					usb_pipeout(urb->pipe));
-		else {
-			/* If we're in the middle of the queue, grab the */
-			/* toggle from the TD previous to us */
-			purbp = list_entry(urbp->queue_list.prev,
-					struct urb_priv, queue_list);
-			pltd = list_entry(purbp->td_list.prev,
-					struct uhci_td, list);
-			toggle = uhci_toggle(td_token(pltd)) ^ 1;
-		}
-
-		list_for_each_entry(turbp, &urbp->queue_list, queue_list) {
-			if (!turbp->queued)
-				break;
-			toggle = uhci_fixup_toggle(turbp->urb, toggle);
-		}
-
-		usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-				usb_pipeout(urb->pipe), toggle);
-	}
-
-	if (urbp->queued) {
-		/* We're somewhere in the middle (or end).  The case where
-		 * we're at the head is handled in uhci_remove_qh(). */
-		purbp = list_entry(urbp->queue_list.prev, struct urb_priv,
-				queue_list);
-
-		pltd = list_entry(purbp->td_list.prev, struct uhci_td, list);
-		if (nurbp->queued)
-			pltd->link = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH;
-		else
-			/* The next URB happens to be the beginning, so */
-			/*  we're the last, end the chain */
-			pltd->link = UHCI_PTR_TERM;
-	}
-
-	/* urbp->queue_list is handled in uhci_remove_qh() */
-}
-
-static struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
+static inline struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci,
+		struct urb *urb)
 {
 	struct urb_priv *urbp;
 
@@ -453,16 +386,11 @@
 
 	memset((void *)urbp, 0, sizeof(*urbp));
 
-	urbp->fsbrtime = jiffies;
 	urbp->urb = urb;
-	
-	INIT_LIST_HEAD(&urbp->td_list);
-	INIT_LIST_HEAD(&urbp->queue_list);
-	INIT_LIST_HEAD(&urbp->urb_list);
-
-	list_add_tail(&urbp->urb_list, &uhci->urb_list);
-
 	urb->hcpriv = urbp;
+	
+	INIT_LIST_HEAD(&urbp->node);
+	INIT_LIST_HEAD(&urbp->td_list);
 
 	return urbp;
 }
@@ -482,18 +410,14 @@
 	list_del_init(&td->list);
 }
 
-static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
+static void uhci_free_urb_priv(struct uhci_hcd *uhci,
+		struct urb_priv *urbp)
 {
 	struct uhci_td *td, *tmp;
-	struct urb_priv *urbp;
 
-	urbp = (struct urb_priv *)urb->hcpriv;
-	if (!urbp)
-		return;
-
-	if (!list_empty(&urbp->urb_list))
-		dev_warn(uhci_dev(uhci), "urb %p still on uhci->urb_list "
-				"or uhci->remove_list!\n", urb);
+	if (!list_empty(&urbp->node))
+		dev_warn(uhci_dev(uhci), "urb %p still on QH's list!\n",
+				urbp->urb);
 
 	uhci_get_current_frame_number(uhci);
 	if (uhci->frame_number + uhci->is_stopped != uhci->td_remove_age) {
@@ -502,7 +426,7 @@
 	}
 
 	/* Check to see if the remove list is empty. Set the IOC bit */
-	/* to force an interrupt so we can remove the TDs*/
+	/* to force an interrupt so we can remove the TDs. */
 	if (list_empty(&uhci->td_remove_list))
 		uhci_set_next_interrupt(uhci);
 
@@ -511,7 +435,7 @@
 		list_add(&td->remove_list, &uhci->td_remove_list);
 	}
 
-	urb->hcpriv = NULL;
+	urbp->urb->hcpriv = NULL;
 	kmem_cache_free(uhci_up_cachep, urbp);
 }
 
@@ -570,34 +494,33 @@
 /*
  * Control transfers
  */
-static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb)
+static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
+		struct uhci_qh *qh)
 {
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 	struct uhci_td *td;
-	struct uhci_qh *qh, *skelqh;
 	unsigned long destination, status;
-	int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+	int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize);
 	int len = urb->transfer_buffer_length;
 	dma_addr_t data = urb->transfer_dma;
+	__le32 *plink;
 
 	/* The "pipe" thing contains the destination in bits 8--18 */
 	destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
 
-	/* 3 errors */
-	status = TD_CTRL_ACTIVE | uhci_maxerr(3);
+	/* 3 errors, dummy TD remains inactive */
+	status = uhci_maxerr(3);
 	if (urb->dev->speed == USB_SPEED_LOW)
 		status |= TD_CTRL_LS;
 
 	/*
 	 * Build the TD for the control request setup packet
 	 */
-	td = uhci_alloc_td(uhci);
-	if (!td)
-		return -ENOMEM;
-
+	td = qh->dummy_td;
 	uhci_add_td_to_urb(urb, td);
 	uhci_fill_td(td, status, destination | uhci_explen(8),
-		urb->setup_dma);
+			urb->setup_dma);
+	plink = &td->link;
+	status |= TD_CTRL_ACTIVE;
 
 	/*
 	 * If direction is "send", change the packet ID from SETUP (0x2D)
@@ -615,21 +538,20 @@
 	 * Build the DATA TDs
 	 */
 	while (len > 0) {
-		int pktsze = len;
-
-		if (pktsze > maxsze)
-			pktsze = maxsze;
+		int pktsze = min(len, maxsze);
 
 		td = uhci_alloc_td(uhci);
 		if (!td)
-			return -ENOMEM;
+			goto nomem;
+		*plink = cpu_to_le32(td->dma_handle);
 
 		/* Alternate Data0/1 (start with Data1) */
 		destination ^= TD_TOKEN_TOGGLE;
 	
 		uhci_add_td_to_urb(urb, td);
 		uhci_fill_td(td, status, destination | uhci_explen(pktsze),
-			data);
+				data);
+		plink = &td->link;
 
 		data += pktsze;
 		len -= pktsze;
@@ -640,7 +562,8 @@
 	 */
 	td = uhci_alloc_td(uhci);
 	if (!td)
-		return -ENOMEM;
+		goto nomem;
+	*plink = cpu_to_le32(td->dma_handle);
 
 	/*
 	 * It's IN if the pipe is an output pipe or we're not expecting
@@ -658,16 +581,21 @@
 
 	uhci_add_td_to_urb(urb, td);
 	uhci_fill_td(td, status | TD_CTRL_IOC,
-		destination | uhci_explen(0), 0);
+			destination | uhci_explen(0), 0);
+	plink = &td->link;
 
-	qh = uhci_alloc_qh(uhci);
-	if (!qh)
-		return -ENOMEM;
+	/*
+	 * Build the new dummy TD and activate the old one
+	 */
+	td = uhci_alloc_td(uhci);
+	if (!td)
+		goto nomem;
+	*plink = cpu_to_le32(td->dma_handle);
 
-	urbp->qh = qh;
-	qh->urbp = urbp;
-
-	uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH);
+	uhci_fill_td(td, 0, USB_PID_OUT | uhci_explen(0), 0);
+	wmb();
+	qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE);
+	qh->dummy_td = td;
 
 	/* Low-speed transfers get a different queue, and won't hog the bus.
 	 * Also, some devices enumerate better without FSBR; the easiest way
@@ -675,18 +603,17 @@
 	 * isn't in the CONFIGURED state. */
 	if (urb->dev->speed == USB_SPEED_LOW ||
 			urb->dev->state != USB_STATE_CONFIGURED)
-		skelqh = uhci->skel_ls_control_qh;
+		qh->skel = uhci->skel_ls_control_qh;
 	else {
-		skelqh = uhci->skel_fs_control_qh;
+		qh->skel = uhci->skel_fs_control_qh;
 		uhci_inc_fsbr(uhci, urb);
 	}
+	return 0;
 
-	if (eurb)
-		uhci_append_queued_urb(uhci, eurb, urb);
-	else
-		uhci_insert_qh(uhci, skelqh, urb);
-
-	return -EINPROGRESS;
+nomem:
+	/* Remove the dummy TD from the td_list so it doesn't get freed */
+	uhci_remove_td_from_urb(qh->dummy_td);
+	return -ENOMEM;
 }
 
 /*
@@ -703,7 +630,7 @@
 	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 	struct uhci_td *td;
 
-	urbp->short_control_packet = 1;
+	urbp->short_transfer = 1;
 
 	td = list_entry(urbp->td_list.prev, struct uhci_td, list);
 	urbp->qh->element = cpu_to_le32(td->dma_handle);
@@ -720,16 +647,14 @@
 	unsigned int status;
 	int ret = 0;
 
-	if (list_empty(&urbp->td_list))
-		return -EINVAL;
-
 	head = &urbp->td_list;
-
-	if (urbp->short_control_packet) {
+	if (urbp->short_transfer) {
 		tmp = head->prev;
 		goto status_stage;
 	}
 
+	urb->actual_length = 0;
+
 	tmp = head->next;
 	td = list_entry(tmp, struct uhci_td, list);
 
@@ -742,8 +667,6 @@
 	if (status)
 		goto td_error;
 
-	urb->actual_length = 0;
-
 	/* The rest of the TDs (but the last) are data */
 	tmp = tmp->next;
 	while (tmp != head && tmp->next != head) {
@@ -770,10 +693,7 @@
 				goto err;
 			}
 
-			if (uhci_packetid(td_token(td)) == USB_PID_IN)
-				return usb_control_retrigger_status(uhci, urb);
-			else
-				return 0;
+			return usb_control_retrigger_status(uhci, urb);
 		}
 	}
 
@@ -814,34 +734,40 @@
 		if (errbuf) {
 			/* Print the chain for debugging purposes */
 			uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
-
 			lprintk(errbuf);
 		}
 	}
 
+	/* Note that the queue has stopped */
+	urbp->qh->element = UHCI_PTR_TERM;
+	urbp->qh->is_stopped = 1;
 	return ret;
 }
 
 /*
  * Common submit for bulk and interrupt
  */
-static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb, struct uhci_qh *skelqh)
+static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
+		struct uhci_qh *qh)
 {
 	struct uhci_td *td;
-	struct uhci_qh *qh;
 	unsigned long destination, status;
-	int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+	int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize);
 	int len = urb->transfer_buffer_length;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 	dma_addr_t data = urb->transfer_dma;
+	__le32 *plink;
+	unsigned int toggle;
 
 	if (len < 0)
 		return -EINVAL;
 
 	/* The "pipe" thing contains the destination in bits 8--18 */
 	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
+	toggle = usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+			 usb_pipeout(urb->pipe));
 
-	status = uhci_maxerr(3) | TD_CTRL_ACTIVE;
+	/* 3 errors, dummy TD remains inactive */
+	status = uhci_maxerr(3);
 	if (urb->dev->speed == USB_SPEED_LOW)
 		status |= TD_CTRL_LS;
 	if (usb_pipein(urb->pipe))
@@ -850,30 +776,34 @@
 	/*
 	 * Build the DATA TDs
 	 */
+	plink = NULL;
+	td = qh->dummy_td;
 	do {	/* Allow zero length packets */
 		int pktsze = maxsze;
 
-		if (pktsze >= len) {
+		if (len <= pktsze) {		/* The last packet */
 			pktsze = len;
 			if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
 				status &= ~TD_CTRL_SPD;
 		}
 
-		td = uhci_alloc_td(uhci);
-		if (!td)
-			return -ENOMEM;
-
+		if (plink) {
+			td = uhci_alloc_td(uhci);
+			if (!td)
+				goto nomem;
+			*plink = cpu_to_le32(td->dma_handle);
+		}
 		uhci_add_td_to_urb(urb, td);
-		uhci_fill_td(td, status, destination | uhci_explen(pktsze) |
-			(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-			 usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
-			data);
+		uhci_fill_td(td, status,
+				destination | uhci_explen(pktsze) |
+					(toggle << TD_TOKEN_TOGGLE_SHIFT),
+				data);
+		plink = &td->link;
+		status |= TD_CTRL_ACTIVE;
 
 		data += pktsze;
 		len -= maxsze;
-
-		usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-			usb_pipeout(urb->pipe));
+		toggle ^= 1;
 	} while (len > 0);
 
 	/*
@@ -883,20 +813,22 @@
 	 * however, if transfer_length == 0, the zero packet was already
 	 * prepared above.
 	 */
-	if (usb_pipeout(urb->pipe) && (urb->transfer_flags & URB_ZERO_PACKET) &&
-	    !len && urb->transfer_buffer_length) {
+	if ((urb->transfer_flags & URB_ZERO_PACKET) &&
+			usb_pipeout(urb->pipe) && len == 0 &&
+			urb->transfer_buffer_length > 0) {
 		td = uhci_alloc_td(uhci);
 		if (!td)
-			return -ENOMEM;
+			goto nomem;
+		*plink = cpu_to_le32(td->dma_handle);
 
 		uhci_add_td_to_urb(urb, td);
-		uhci_fill_td(td, status, destination | uhci_explen(0) |
-			(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-			 usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
-			data);
+		uhci_fill_td(td, status,
+				destination | uhci_explen(0) |
+					(toggle << TD_TOKEN_TOGGLE_SHIFT),
+				data);
+		plink = &td->link;
 
-		usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-			usb_pipeout(urb->pipe));
+		toggle ^= 1;
 	}
 
 	/* Set the interrupt-on-completion flag on the last packet.
@@ -905,24 +837,29 @@
 	 * fast side but not enough to justify delaying an interrupt
 	 * more than 2 or 3 URBs, so we will ignore the URB_NO_INTERRUPT
 	 * flag setting. */
-	td->status |= cpu_to_le32(TD_CTRL_IOC);
+	td->status |= __constant_cpu_to_le32(TD_CTRL_IOC);
 
-	qh = uhci_alloc_qh(uhci);
-	if (!qh)
-		return -ENOMEM;
+	/*
+	 * Build the new dummy TD and activate the old one
+	 */
+	td = uhci_alloc_td(uhci);
+	if (!td)
+		goto nomem;
+	*plink = cpu_to_le32(td->dma_handle);
 
-	urbp->qh = qh;
-	qh->urbp = urbp;
+	uhci_fill_td(td, 0, USB_PID_OUT | uhci_explen(0), 0);
+	wmb();
+	qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE);
+	qh->dummy_td = td;
 
-	/* Always breadth first */
-	uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH);
+	usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+			usb_pipeout(urb->pipe), toggle);
+	return 0;
 
-	if (eurb)
-		uhci_append_queued_urb(uhci, eurb, urb);
-	else
-		uhci_insert_qh(uhci, skelqh, urb);
-
-	return -EINPROGRESS;
+nomem:
+	/* Remove the dummy TD from the td_list so it doesn't get freed */
+	uhci_remove_td_from_urb(qh->dummy_td);
+	return -ENOMEM;
 }
 
 /*
@@ -954,8 +891,27 @@
 			if (urb->transfer_flags & URB_SHORT_NOT_OK) {
 				ret = -EREMOTEIO;
 				goto err;
-			} else
-				return 0;
+			}
+
+			/*
+			 * This URB stopped short of its end.  We have to
+			 * fix up the toggles of the following URBs on the
+			 * queue and restart the queue.
+			 *
+			 * Do this only the first time we encounter the
+			 * short URB.
+			 */
+			if (!urbp->short_transfer) {
+				urbp->short_transfer = 1;
+				urbp->qh->initial_toggle =
+						uhci_toggle(td_token(td)) ^ 1;
+				uhci_fixup_toggles(urbp->qh, 1);
+
+				td = list_entry(urbp->td_list.prev,
+						struct uhci_td, list);
+				urbp->qh->element = td->link;
+			}
+			break;
 		}
 	}
 
@@ -964,31 +920,30 @@
 td_error:
 	ret = uhci_map_status(status, uhci_packetout(td_token(td)));
 
-err:
-	/* 
-	 * Enable this chunk of code if you want to see some more debugging.
-	 * But be careful, it has the tendancy to starve out khubd and prevent
-	 * disconnects from happening successfully if you have a slow debug
-	 * log interface (like a serial console.
-	 */
-#if 0
 	if ((debug == 1 && ret != -EPIPE) || debug > 1) {
 		/* Some debugging code */
 		dev_dbg(uhci_dev(uhci), "%s: failed with status %x\n",
 				__FUNCTION__, status);
 
-		if (errbuf) {
+		if (debug > 1 && errbuf) {
 			/* Print the chain for debugging purposes */
 			uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
-
 			lprintk(errbuf);
 		}
 	}
-#endif
+err:
+
+	/* Note that the queue has stopped and save the next toggle value */
+	urbp->qh->element = UHCI_PTR_TERM;
+	urbp->qh->is_stopped = 1;
+	urbp->qh->needs_fixup = 1;
+	urbp->qh->initial_toggle = uhci_toggle(td_token(td)) ^
+			(ret == -EREMOTEIO);
 	return ret;
 }
 
-static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb)
+static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb,
+		struct uhci_qh *qh)
 {
 	int ret;
 
@@ -996,95 +951,60 @@
 	if (urb->dev->speed == USB_SPEED_LOW)
 		return -EINVAL;
 
-	ret = uhci_submit_common(uhci, urb, eurb, uhci->skel_bulk_qh);
-	if (ret == -EINPROGRESS)
+	qh->skel = uhci->skel_bulk_qh;
+	ret = uhci_submit_common(uhci, urb, qh);
+	if (ret == 0)
 		uhci_inc_fsbr(uhci, urb);
-
 	return ret;
 }
 
-static inline int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb)
+static inline int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb,
+		struct uhci_qh *qh)
 {
-	/* USB 1.1 interrupt transfers only involve one packet per interval;
-	 * that's the uhci_submit_common() "breadth first" policy.  Drivers
-	 * can submit urbs of any length, but longer ones might need many
-	 * intervals to complete.
+	/* USB 1.1 interrupt transfers only involve one packet per interval.
+	 * Drivers can submit URBs of any length, but longer ones will need
+	 * multiple intervals to complete.
 	 */
-	return uhci_submit_common(uhci, urb, eurb, uhci->skelqh[__interval_to_skel(urb->interval)]);
+	qh->skel = uhci->skelqh[__interval_to_skel(urb->interval)];
+	return uhci_submit_common(uhci, urb, qh);
 }
 
 /*
  * Isochronous transfers
  */
-static int isochronous_find_limits(struct uhci_hcd *uhci, struct urb *urb, unsigned int *start, unsigned int *end)
+static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
+		struct uhci_qh *qh)
 {
-	struct urb *last_urb = NULL;
-	struct urb_priv *up;
-	int ret = 0;
-
-	list_for_each_entry(up, &uhci->urb_list, urb_list) {
-		struct urb *u = up->urb;
-
-		/* look for pending URBs with identical pipe handle */
-		if ((urb->pipe == u->pipe) && (urb->dev == u->dev) &&
-		    (u->status == -EINPROGRESS) && (u != urb)) {
-			if (!last_urb)
-				*start = u->start_frame;
-			last_urb = u;
-		}
-	}
-
-	if (last_urb) {
-		*end = (last_urb->start_frame + last_urb->number_of_packets *
-				last_urb->interval) & (UHCI_NUMFRAMES-1);
-		ret = 0;
-	} else
-		ret = -1;	/* no previous urb found */
-
-	return ret;
-}
-
-static int isochronous_find_start(struct uhci_hcd *uhci, struct urb *urb)
-{
-	int limits;
-	unsigned int start = 0, end = 0;
+	struct uhci_td *td = NULL;	/* Since urb->number_of_packets > 0 */
+	int i, frame;
+	unsigned long destination, status;
+	struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
 
 	if (urb->number_of_packets > 900)	/* 900? Why? */
 		return -EFBIG;
 
-	limits = isochronous_find_limits(uhci, urb, &start, &end);
-
-	if (urb->transfer_flags & URB_ISO_ASAP) {
-		if (limits) {
-			uhci_get_current_frame_number(uhci);
-			urb->start_frame = (uhci->frame_number + 10)
-					& (UHCI_NUMFRAMES - 1);
-		} else
-			urb->start_frame = end;
-	} else {
-		urb->start_frame &= (UHCI_NUMFRAMES - 1);
-		/* FIXME: Sanity check */
-	}
-
-	return 0;
-}
-
-/*
- * Isochronous transfers
- */
-static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb)
-{
-	struct uhci_td *td;
-	int i, ret, frame;
-	int status, destination;
-	struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
-
 	status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
 	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
 
-	ret = isochronous_find_start(uhci, urb);
-	if (ret)
-		return ret;
+	/* Figure out the starting frame number */
+	if (urb->transfer_flags & URB_ISO_ASAP) {
+		if (list_empty(&qh->queue)) {
+			uhci_get_current_frame_number(uhci);
+			urb->start_frame = (uhci->frame_number + 10);
+
+		} else {		/* Go right after the last one */
+			struct urb *last_urb;
+
+			last_urb = list_entry(qh->queue.prev,
+					struct urb_priv, node)->urb;
+			urb->start_frame = (last_urb->start_frame +
+					last_urb->number_of_packets *
+					last_urb->interval);
+		}
+	} else {
+		/* FIXME: Sanity check */
+	}
+	urb->start_frame &= (UHCI_NUMFRAMES - 1);
 
 	for (i = 0; i < urb->number_of_packets; i++) {
 		td = uhci_alloc_td(uhci);
@@ -1092,20 +1012,25 @@
 			return -ENOMEM;
 
 		uhci_add_td_to_urb(urb, td);
-		uhci_fill_td(td, status, destination | uhci_explen(urb->iso_frame_desc[i].length),
-			urb->transfer_dma + urb->iso_frame_desc[i].offset);
-
-		if (i + 1 >= urb->number_of_packets)
-			td->status |= cpu_to_le32(TD_CTRL_IOC);
+		uhci_fill_td(td, status, destination |
+				uhci_explen(urb->iso_frame_desc[i].length),
+				urb->transfer_dma +
+					urb->iso_frame_desc[i].offset);
 	}
 
+	/* Set the interrupt-on-completion flag on the last packet. */
+	td->status |= __constant_cpu_to_le32(TD_CTRL_IOC);
+
+	qh->skel = uhci->skel_iso_qh;
+
+	/* Add the TDs to the frame list */
 	frame = urb->start_frame;
 	list_for_each_entry(td, &urbp->td_list, list) {
-		uhci_insert_td_frame_list(uhci, td, frame);
+		uhci_insert_td_in_frame_list(uhci, td, frame);
 		frame += urb->interval;
 	}
 
-	return -EINPROGRESS;
+	return 0;
 }
 
 static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
@@ -1139,80 +1064,67 @@
 
 		i++;
 	}
-	unlink_isochronous_tds(uhci, urb);
 
 	return ret;
 }
 
-static struct urb *uhci_find_urb_ep(struct uhci_hcd *uhci, struct urb *urb)
-{
-	struct urb_priv *up;
-
-	/* We don't match Isoc transfers since they are special */
-	if (usb_pipeisoc(urb->pipe))
-		return NULL;
-
-	list_for_each_entry(up, &uhci->urb_list, urb_list) {
-		struct urb *u = up->urb;
-
-		if (u->dev == urb->dev && u->status == -EINPROGRESS) {
-			/* For control, ignore the direction */
-			if (usb_pipecontrol(urb->pipe) &&
-			    (u->pipe & ~USB_DIR_IN) == (urb->pipe & ~USB_DIR_IN))
-				return u;
-			else if (u->pipe == urb->pipe)
-				return u;
-		}
-	}
-
-	return NULL;
-}
-
 static int uhci_urb_enqueue(struct usb_hcd *hcd,
-		struct usb_host_endpoint *ep,
+		struct usb_host_endpoint *hep,
 		struct urb *urb, gfp_t mem_flags)
 {
 	int ret;
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 	unsigned long flags;
-	struct urb *eurb;
+	struct urb_priv *urbp;
+	struct uhci_qh *qh;
 	int bustime;
 
 	spin_lock_irqsave(&uhci->lock, flags);
 
 	ret = urb->status;
 	if (ret != -EINPROGRESS)		/* URB already unlinked! */
-		goto out;
+		goto done;
 
-	eurb = uhci_find_urb_ep(uhci, urb);
+	ret = -ENOMEM;
+	urbp = uhci_alloc_urb_priv(uhci, urb);
+	if (!urbp)
+		goto done;
 
-	if (!uhci_alloc_urb_priv(uhci, urb)) {
-		ret = -ENOMEM;
-		goto out;
+	if (hep->hcpriv)
+		qh = (struct uhci_qh *) hep->hcpriv;
+	else {
+		qh = uhci_alloc_qh(uhci, urb->dev, hep);
+		if (!qh)
+			goto err_no_qh;
 	}
+	urbp->qh = qh;
 
 	switch (usb_pipetype(urb->pipe)) {
 	case PIPE_CONTROL:
-		ret = uhci_submit_control(uhci, urb, eurb);
+		ret = uhci_submit_control(uhci, urb, qh);
+		break;
+	case PIPE_BULK:
+		ret = uhci_submit_bulk(uhci, urb, qh);
 		break;
 	case PIPE_INTERRUPT:
-		if (!eurb) {
+		if (list_empty(&qh->queue)) {
 			bustime = usb_check_bandwidth(urb->dev, urb);
 			if (bustime < 0)
 				ret = bustime;
 			else {
-				ret = uhci_submit_interrupt(uhci, urb, eurb);
-				if (ret == -EINPROGRESS)
+				ret = uhci_submit_interrupt(uhci, urb, qh);
+				if (ret == 0)
 					usb_claim_bandwidth(urb->dev, urb, bustime, 0);
 			}
 		} else {	/* inherit from parent */
-			urb->bandwidth = eurb->bandwidth;
-			ret = uhci_submit_interrupt(uhci, urb, eurb);
+			struct urb_priv *eurbp;
+
+			eurbp = list_entry(qh->queue.prev, struct urb_priv,
+					node);
+			urb->bandwidth = eurbp->urb->bandwidth;
+			ret = uhci_submit_interrupt(uhci, urb, qh);
 		}
 		break;
-	case PIPE_BULK:
-		ret = uhci_submit_bulk(uhci, urb, eurb);
-		break;
 	case PIPE_ISOCHRONOUS:
 		bustime = usb_check_bandwidth(urb->dev, urb);
 		if (bustime < 0) {
@@ -1220,146 +1132,37 @@
 			break;
 		}
 
-		ret = uhci_submit_isochronous(uhci, urb);
-		if (ret == -EINPROGRESS)
+		ret = uhci_submit_isochronous(uhci, urb, qh);
+		if (ret == 0)
 			usb_claim_bandwidth(urb->dev, urb, bustime, 1);
 		break;
 	}
+	if (ret != 0)
+		goto err_submit_failed;
 
-	if (ret != -EINPROGRESS) {
-		/* Submit failed, so delete it from the urb_list */
-		struct urb_priv *urbp = urb->hcpriv;
+	/* Add this URB to the QH */
+	urbp->qh = qh;
+	list_add_tail(&urbp->node, &qh->queue);
 
-		list_del_init(&urbp->urb_list);
-		uhci_destroy_urb_priv(uhci, urb);
-	} else
-		ret = 0;
+	/* If the new URB is the first and only one on this QH then either
+	 * the QH is new and idle or else it's unlinked and waiting to
+	 * become idle, so we can activate it right away. */
+	if (qh->queue.next == &urbp->node)
+		uhci_activate_qh(uhci, qh);
+	goto done;
 
-out:
+err_submit_failed:
+	if (qh->state == QH_STATE_IDLE)
+		uhci_make_qh_idle(uhci, qh);	/* Reclaim unused QH */
+
+err_no_qh:
+	uhci_free_urb_priv(uhci, urbp);
+
+done:
 	spin_unlock_irqrestore(&uhci->lock, flags);
 	return ret;
 }
 
-/*
- * Return the result of a transfer
- */
-static void uhci_transfer_result(struct uhci_hcd *uhci, struct urb *urb)
-{
-	int ret = -EINPROGRESS;
-	struct urb_priv *urbp;
-
-	spin_lock(&urb->lock);
-
-	urbp = (struct urb_priv *)urb->hcpriv;
-
-	if (urb->status != -EINPROGRESS)	/* URB already dequeued */
-		goto out;
-
-	switch (usb_pipetype(urb->pipe)) {
-	case PIPE_CONTROL:
-		ret = uhci_result_control(uhci, urb);
-		break;
-	case PIPE_BULK:
-	case PIPE_INTERRUPT:
-		ret = uhci_result_common(uhci, urb);
-		break;
-	case PIPE_ISOCHRONOUS:
-		ret = uhci_result_isochronous(uhci, urb);
-		break;
-	}
-
-	if (ret == -EINPROGRESS)
-		goto out;
-	urb->status = ret;
-
-	switch (usb_pipetype(urb->pipe)) {
-	case PIPE_CONTROL:
-	case PIPE_BULK:
-	case PIPE_ISOCHRONOUS:
-		/* Release bandwidth for Interrupt or Isoc. transfers */
-		if (urb->bandwidth)
-			usb_release_bandwidth(urb->dev, urb, 1);
-		uhci_unlink_generic(uhci, urb);
-		break;
-	case PIPE_INTERRUPT:
-		/* Release bandwidth for Interrupt or Isoc. transfers */
-		/* Make sure we don't release if we have a queued URB */
-		if (list_empty(&urbp->queue_list) && urb->bandwidth)
-			usb_release_bandwidth(urb->dev, urb, 0);
-		else
-			/* bandwidth was passed on to queued URB, */
-			/* so don't let usb_unlink_urb() release it */
-			urb->bandwidth = 0;
-		uhci_unlink_generic(uhci, urb);
-		break;
-	default:
-		dev_info(uhci_dev(uhci), "%s: unknown pipe type %d "
-				"for urb %p\n",
-				__FUNCTION__, usb_pipetype(urb->pipe), urb);
-	}
-
-	/* Move it from uhci->urb_list to uhci->complete_list */
-	uhci_moveto_complete(uhci, urbp);
-
-out:
-	spin_unlock(&urb->lock);
-}
-
-static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb)
-{
-	struct list_head *head;
-	struct uhci_td *td;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	int prevactive = 0;
-
-	uhci_dec_fsbr(uhci, urb);	/* Safe since it checks */
-
-	/*
-	 * Now we need to find out what the last successful toggle was
-	 * so we can update the local data toggle for the next transfer
-	 *
-	 * There are 2 ways the last successful completed TD is found:
-	 *
-	 * 1) The TD is NOT active and the actual length < expected length
-	 * 2) The TD is NOT active and it's the last TD in the chain
-	 *
-	 * and a third way the first uncompleted TD is found:
-	 *
-	 * 3) The TD is active and the previous TD is NOT active
-	 *
-	 * Control and Isochronous ignore the toggle, so this is safe
-	 * for all types
-	 *
-	 * FIXME: The toggle fixups won't be 100% reliable until we
-	 * change over to using a single queue for each endpoint and
-	 * stop the queue before unlinking.
-	 */
-	head = &urbp->td_list;
-	list_for_each_entry(td, head, list) {
-		unsigned int ctrlstat = td_status(td);
-
-		if (!(ctrlstat & TD_CTRL_ACTIVE) &&
-				(uhci_actual_length(ctrlstat) <
-				 uhci_expected_length(td_token(td)) ||
-				td->list.next == head))
-			usb_settoggle(urb->dev, uhci_endpoint(td_token(td)),
-				uhci_packetout(td_token(td)),
-				uhci_toggle(td_token(td)) ^ 1);
-		else if ((ctrlstat & TD_CTRL_ACTIVE) && !prevactive)
-			usb_settoggle(urb->dev, uhci_endpoint(td_token(td)),
-				uhci_packetout(td_token(td)),
-				uhci_toggle(td_token(td)));
-
-		prevactive = ctrlstat & TD_CTRL_ACTIVE;
-	}
-
-	uhci_delete_queued_urb(uhci, urb);
-
-	/* The interrupt loop will reclaim the QHs */
-	uhci_remove_qh(uhci, urbp->qh);
-	urbp->qh = NULL;
-}
-
 static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
 {
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
@@ -1370,71 +1173,167 @@
 	urbp = urb->hcpriv;
 	if (!urbp)			/* URB was never linked! */
 		goto done;
-	list_del_init(&urbp->urb_list);
 
+	/* Remove Isochronous TDs from the frame list ASAP */
 	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
-		unlink_isochronous_tds(uhci, urb);
-	uhci_unlink_generic(uhci, urb);
-
-	uhci_get_current_frame_number(uhci);
-	if (uhci->frame_number + uhci->is_stopped != uhci->urb_remove_age) {
-		uhci_remove_pending_urbps(uhci);
-		uhci->urb_remove_age = uhci->frame_number;
-	}
-
-	/* If we're the first, set the next interrupt bit */
-	if (list_empty(&uhci->urb_remove_list))
-		uhci_set_next_interrupt(uhci);
-	list_add_tail(&urbp->urb_list, &uhci->urb_remove_list);
+		uhci_unlink_isochronous_tds(uhci, urb);
+	uhci_unlink_qh(uhci, urbp->qh);
 
 done:
 	spin_unlock_irqrestore(&uhci->lock, flags);
 	return 0;
 }
 
-static int uhci_fsbr_timeout(struct uhci_hcd *uhci, struct urb *urb)
+/*
+ * Finish unlinking an URB and give it back
+ */
+static void uhci_giveback_urb(struct uhci_hcd *uhci, struct uhci_qh *qh,
+		struct urb *urb, struct pt_regs *regs)
+__releases(uhci->lock)
+__acquires(uhci->lock)
 {
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct list_head *head;
-	struct uhci_td *td;
-	int count = 0;
+	struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
 
-	uhci_dec_fsbr(uhci, urb);
+	/* Isochronous TDs get unlinked directly from the frame list */
+	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
+		uhci_unlink_isochronous_tds(uhci, urb);
 
-	urbp->fsbr_timeout = 1;
+	/* If the URB isn't first on its queue, adjust the link pointer
+	 * of the last TD in the previous URB. */
+	else if (qh->queue.next != &urbp->node) {
+		struct urb_priv *purbp;
+		struct uhci_td *ptd, *ltd;
 
-	/*
-	 * Ideally we would want to fix qh->element as well, but it's
-	 * read/write by the HC, so that can introduce a race. It's not
-	 * really worth the hassle
-	 */
-
-	head = &urbp->td_list;
-	list_for_each_entry(td, head, list) {
-		/*
-		 * Make sure we don't do the last one (since it'll have the
-		 * TERM bit set) as well as we skip every so many TDs to
-		 * make sure it doesn't hog the bandwidth
-		 */
-		if (td->list.next != head && (count % DEPTH_INTERVAL) ==
-				(DEPTH_INTERVAL - 1))
-			td->link |= UHCI_PTR_DEPTH;
-
-		count++;
+		purbp = list_entry(urbp->node.prev, struct urb_priv, node);
+		ptd = list_entry(purbp->td_list.prev, struct uhci_td,
+				list);
+		ltd = list_entry(urbp->td_list.prev, struct uhci_td,
+				list);
+		ptd->link = ltd->link;
 	}
 
-	return 0;
+	/* Take the URB off the QH's queue.  If the queue is now empty,
+	 * this is a perfect time for a toggle fixup. */
+	list_del_init(&urbp->node);
+	if (list_empty(&qh->queue) && qh->needs_fixup) {
+		usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+				usb_pipeout(urb->pipe), qh->initial_toggle);
+		qh->needs_fixup = 0;
+	}
+
+	uhci_dec_fsbr(uhci, urb);	/* Safe since it checks */
+	uhci_free_urb_priv(uhci, urbp);
+
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_ISOCHRONOUS:
+		/* Release bandwidth for Interrupt or Isoc. transfers */
+		if (urb->bandwidth)
+			usb_release_bandwidth(urb->dev, urb, 1);
+		break;
+	case PIPE_INTERRUPT:
+		/* Release bandwidth for Interrupt or Isoc. transfers */
+		/* Make sure we don't release if we have a queued URB */
+		if (list_empty(&qh->queue) && urb->bandwidth)
+			usb_release_bandwidth(urb->dev, urb, 0);
+		else
+			/* bandwidth was passed on to queued URB, */
+			/* so don't let usb_unlink_urb() release it */
+			urb->bandwidth = 0;
+		break;
+	}
+
+	spin_unlock(&uhci->lock);
+	usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb, regs);
+	spin_lock(&uhci->lock);
+
+	/* If the queue is now empty, we can unlink the QH and give up its
+	 * reserved bandwidth. */
+	if (list_empty(&qh->queue)) {
+		uhci_unlink_qh(uhci, qh);
+
+		/* Bandwidth stuff not yet implemented */
+	}
 }
 
-static void uhci_free_pending_qhs(struct uhci_hcd *uhci)
+/*
+ * Scan the URBs in a QH's queue
+ */
+#define QH_FINISHED_UNLINKING(qh)			\
+		(qh->state == QH_STATE_UNLINKING &&	\
+		uhci->frame_number + uhci->is_stopped != qh->unlink_frame)
+
+static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh,
+		struct pt_regs *regs)
 {
-	struct uhci_qh *qh, *tmp;
+	struct urb_priv *urbp;
+	struct urb *urb;
+	int status;
 
-	list_for_each_entry_safe(qh, tmp, &uhci->qh_remove_list, remove_list) {
-		list_del_init(&qh->remove_list);
+	while (!list_empty(&qh->queue)) {
+		urbp = list_entry(qh->queue.next, struct urb_priv, node);
+		urb = urbp->urb;
 
-		uhci_free_qh(uhci, qh);
+		switch (usb_pipetype(urb->pipe)) {
+		case PIPE_CONTROL:
+			status = uhci_result_control(uhci, urb);
+			break;
+		case PIPE_ISOCHRONOUS:
+			status = uhci_result_isochronous(uhci, urb);
+			break;
+		default:	/* PIPE_BULK or PIPE_INTERRUPT */
+			status = uhci_result_common(uhci, urb);
+			break;
+		}
+		if (status == -EINPROGRESS)
+			break;
+
+		spin_lock(&urb->lock);
+		if (urb->status == -EINPROGRESS)	/* Not dequeued */
+			urb->status = status;
+		else
+			status = -ECONNRESET;
+		spin_unlock(&urb->lock);
+
+		/* Dequeued but completed URBs can't be given back unless
+		 * the QH is stopped or has finished unlinking. */
+		if (status == -ECONNRESET &&
+				!(qh->is_stopped || QH_FINISHED_UNLINKING(qh)))
+			return;
+
+		uhci_giveback_urb(uhci, qh, urb, regs);
+		if (qh->is_stopped)
+			break;
 	}
+
+	/* If the QH is neither stopped nor finished unlinking (normal case),
+	 * our work here is done. */
+ restart:
+	if (!(qh->is_stopped || QH_FINISHED_UNLINKING(qh)))
+		return;
+
+	/* Otherwise give back each of the dequeued URBs */
+	list_for_each_entry(urbp, &qh->queue, node) {
+		urb = urbp->urb;
+		if (urb->status != -EINPROGRESS) {
+			uhci_save_toggle(qh, urb);
+			uhci_giveback_urb(uhci, qh, urb, regs);
+			goto restart;
+		}
+	}
+	qh->is_stopped = 0;
+
+	/* There are no more dequeued URBs.  If there are still URBs on the
+	 * queue, the QH can now be re-activated. */
+	if (!list_empty(&qh->queue)) {
+		if (qh->needs_fixup)
+			uhci_fixup_toggles(qh, 0);
+		uhci_activate_qh(uhci, qh);
+	}
+
+	/* The queue is empty.  The QH can become idle if it is fully
+	 * unlinked. */
+	else if (QH_FINISHED_UNLINKING(qh))
+		uhci_make_qh_idle(uhci, qh);
 }
 
 static void uhci_free_pending_tds(struct uhci_hcd *uhci)
@@ -1448,43 +1347,13 @@
 	}
 }
 
-static void
-uhci_finish_urb(struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs)
-__releases(uhci->lock)
-__acquires(uhci->lock)
-{
-	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
-
-	uhci_destroy_urb_priv(uhci, urb);
-
-	spin_unlock(&uhci->lock);
-	usb_hcd_giveback_urb(hcd, urb, regs);
-	spin_lock(&uhci->lock);
-}
-
-static void uhci_finish_completion(struct uhci_hcd *uhci, struct pt_regs *regs)
-{
-	struct urb_priv *urbp, *tmp;
-
-	list_for_each_entry_safe(urbp, tmp, &uhci->complete_list, urb_list) {
-		struct urb *urb = urbp->urb;
-
-		list_del_init(&urbp->urb_list);
-		uhci_finish_urb(uhci_to_hcd(uhci), urb, regs);
-	}
-}
-
-static void uhci_remove_pending_urbps(struct uhci_hcd *uhci)
-{
-
-	/* Splice the urb_remove_list onto the end of the complete_list */
-	list_splice_init(&uhci->urb_remove_list, uhci->complete_list.prev);
-}
-
-/* Process events in the schedule, but only in one thread at a time */
+/*
+ * Process events in the schedule, but only in one thread at a time
+ */
 static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs)
 {
-	struct urb_priv *urbp, *tmp;
+	int i;
+	struct uhci_qh *qh;
 
 	/* Don't allow re-entrant calls */
 	if (uhci->scan_in_progress) {
@@ -1498,60 +1367,39 @@
 	uhci_clear_next_interrupt(uhci);
 	uhci_get_current_frame_number(uhci);
 
-	if (uhci->frame_number + uhci->is_stopped != uhci->qh_remove_age)
-		uhci_free_pending_qhs(uhci);
 	if (uhci->frame_number + uhci->is_stopped != uhci->td_remove_age)
 		uhci_free_pending_tds(uhci);
-	if (uhci->frame_number + uhci->is_stopped != uhci->urb_remove_age)
-		uhci_remove_pending_urbps(uhci);
 
-	/* Walk the list of pending URBs to see which ones completed
-	 * (must be _safe because uhci_transfer_result() dequeues URBs) */
-	list_for_each_entry_safe(urbp, tmp, &uhci->urb_list, urb_list) {
-		struct urb *urb = urbp->urb;
-
-		/* Checks the status and does all of the magic necessary */
-		uhci_transfer_result(uhci, urb);
-	}
-	uhci_finish_completion(uhci, regs);
-
-	/* If the controller is stopped, we can finish these off right now */
-	if (uhci->is_stopped) {
-		uhci_free_pending_qhs(uhci);
-		uhci_free_pending_tds(uhci);
-		uhci_remove_pending_urbps(uhci);
+	/* Go through all the QH queues and process the URBs in each one */
+	for (i = 0; i < UHCI_NUM_SKELQH - 1; ++i) {
+		uhci->next_qh = list_entry(uhci->skelqh[i]->node.next,
+				struct uhci_qh, node);
+		while ((qh = uhci->next_qh) != uhci->skelqh[i]) {
+			uhci->next_qh = list_entry(qh->node.next,
+					struct uhci_qh, node);
+			uhci_scan_qh(uhci, qh, regs);
+		}
 	}
 
 	if (uhci->need_rescan)
 		goto rescan;
 	uhci->scan_in_progress = 0;
 
-	if (list_empty(&uhci->urb_remove_list) &&
-	    list_empty(&uhci->td_remove_list) &&
-	    list_empty(&uhci->qh_remove_list))
+	/* If the controller is stopped, we can finish these off right now */
+	if (uhci->is_stopped)
+		uhci_free_pending_tds(uhci);
+
+	if (list_empty(&uhci->td_remove_list) &&
+			list_empty(&uhci->skel_unlink_qh->node))
 		uhci_clear_next_interrupt(uhci);
 	else
 		uhci_set_next_interrupt(uhci);
-
-	/* Wake up anyone waiting for an URB to complete */
-	wake_up_all(&uhci->waitqh);
 }
 
 static void check_fsbr(struct uhci_hcd *uhci)
 {
-	struct urb_priv *up;
-
-	list_for_each_entry(up, &uhci->urb_list, urb_list) {
-		struct urb *u = up->urb;
-
-		spin_lock(&u->lock);
-
-		/* Check if the FSBR timed out */
-		if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT))
-			uhci_fsbr_timeout(uhci, u);
-
-		spin_unlock(&u->lock);
-	}
+	/* For now, don't scan URBs for FSBR timeouts.
+	 * Add it back in later... */
 
 	/* Really disable FSBR */
 	if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) {
diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
index 0498711..08daf40 100644
--- a/drivers/usb/image/mdc800.c
+++ b/drivers/usb/image/mdc800.c
@@ -96,6 +96,7 @@
 #include <linux/module.h>
 #include <linux/smp_lock.h>
 #include <linux/wait.h>
+#include <linux/mutex.h>
 
 #include <linux/usb.h>
 #include <linux/fs.h>
@@ -169,7 +170,7 @@
 	int			out_count;	// Bytes in the buffer
 
 	int			open;		// Camera device open ?
-	struct semaphore	io_lock;	// IO -lock
+	struct mutex		io_lock;	// IO -lock
 
 	char 			in [8];		// Command Input Buffer
 	int  			in_count;
@@ -497,7 +498,7 @@
 
 	info ("Found Mustek MDC800 on USB.");
 
-	down (&mdc800->io_lock);
+	mutex_lock(&mdc800->io_lock);
 
 	retval = usb_register_dev(intf, &mdc800_class);
 	if (retval) {
@@ -542,7 +543,7 @@
 
 	mdc800->state=READY;
 
-	up (&mdc800->io_lock);
+	mutex_unlock(&mdc800->io_lock);
 	
 	usb_set_intfdata(intf, mdc800);
 	return 0;
@@ -620,7 +621,7 @@
 	int retval=0;
 	int errn=0;
 
-	down (&mdc800->io_lock);
+	mutex_lock(&mdc800->io_lock);
 	
 	if (mdc800->state == NOT_CONNECTED)
 	{
@@ -656,7 +657,7 @@
 	dbg ("Mustek MDC800 device opened.");
 
 error_out:
-	up (&mdc800->io_lock);
+	mutex_unlock(&mdc800->io_lock);
 	return errn;
 }
 
@@ -669,7 +670,7 @@
 	int retval=0;
 	dbg ("Mustek MDC800 device closed.");
 
-	down (&mdc800->io_lock);
+	mutex_lock(&mdc800->io_lock);
 	if (mdc800->open && (mdc800->state != NOT_CONNECTED))
 	{
 		usb_kill_urb(mdc800->irq_urb);
@@ -682,7 +683,7 @@
 		retval=-EIO;
 	}
 
-	up(&mdc800->io_lock);
+	mutex_unlock(&mdc800->io_lock);
 	return retval;
 }
 
@@ -695,21 +696,21 @@
 	size_t left=len, sts=len; /* single transfer size */
 	char __user *ptr = buf;
 
-	down (&mdc800->io_lock);
+	mutex_lock(&mdc800->io_lock);
 	if (mdc800->state == NOT_CONNECTED)
 	{
-		up (&mdc800->io_lock);
+		mutex_unlock(&mdc800->io_lock);
 		return -EBUSY;
 	}
 	if (mdc800->state == WORKING)
 	{
 		warn ("Illegal State \"working\" reached during read ?!");
-		up (&mdc800->io_lock);
+		mutex_unlock(&mdc800->io_lock);
 		return -EBUSY;
 	}
 	if (!mdc800->open)
 	{
-		up (&mdc800->io_lock);
+		mutex_unlock(&mdc800->io_lock);
 		return -EBUSY;
 	}
 
@@ -717,7 +718,7 @@
 	{
 		if (signal_pending (current)) 
 		{
-			up (&mdc800->io_lock);
+			mutex_unlock(&mdc800->io_lock);
 			return -EINTR;
 		}
 
@@ -736,7 +737,7 @@
 				if (usb_submit_urb (mdc800->download_urb, GFP_KERNEL))
 				{
 					err ("Can't submit download urb (status=%i)",mdc800->download_urb->status);
-					up (&mdc800->io_lock);
+					mutex_unlock(&mdc800->io_lock);
 					return len-left;
 				}
 				wait_event_timeout(mdc800->download_wait, mdc800->downloaded,
@@ -745,14 +746,14 @@
 				if (mdc800->download_urb->status != 0)
 				{
 					err ("request download-bytes fails (status=%i)",mdc800->download_urb->status);
-					up (&mdc800->io_lock);
+					mutex_unlock(&mdc800->io_lock);
 					return len-left;
 				}
 			}
 			else
 			{
 				/* No more bytes -> that's an error*/
-				up (&mdc800->io_lock);
+				mutex_unlock(&mdc800->io_lock);
 				return -EIO;
 			}
 		}
@@ -761,7 +762,7 @@
 			/* Copy Bytes */
 			if (copy_to_user(ptr, &mdc800->out [mdc800->out_ptr],
 						sts)) {
-				up(&mdc800->io_lock);
+				mutex_unlock(&mdc800->io_lock);
 				return -EFAULT;
 			}
 			ptr+=sts;
@@ -770,7 +771,7 @@
 		}
 	}
 
-	up (&mdc800->io_lock);
+	mutex_unlock(&mdc800->io_lock);
 	return len-left;
 }
 
@@ -785,15 +786,15 @@
 {
 	size_t i=0;
 
-	down (&mdc800->io_lock);
+	mutex_lock(&mdc800->io_lock);
 	if (mdc800->state != READY)
 	{
-		up (&mdc800->io_lock);
+		mutex_unlock(&mdc800->io_lock);
 		return -EBUSY;
 	}
 	if (!mdc800->open )
 	{
-		up (&mdc800->io_lock);
+		mutex_unlock(&mdc800->io_lock);
 		return -EBUSY;
 	}
 
@@ -802,13 +803,13 @@
 		unsigned char c;
 		if (signal_pending (current)) 
 		{
-			up (&mdc800->io_lock);
+			mutex_unlock(&mdc800->io_lock);
 			return -EINTR;
 		}
 		
 		if(get_user(c, buf+i))
 		{
-			up(&mdc800->io_lock);
+			mutex_unlock(&mdc800->io_lock);
 			return -EFAULT;
 		}
 
@@ -829,7 +830,7 @@
 		}
 		else
 		{
-			up (&mdc800->io_lock);
+			mutex_unlock(&mdc800->io_lock);
 			return -EIO;
 		}
 
@@ -841,7 +842,7 @@
 			if (mdc800_usb_waitForIRQ (0,TO_GET_READY))
 			{
 				err ("Camera didn't get ready.\n");
-				up (&mdc800->io_lock);
+				mutex_unlock(&mdc800->io_lock);
 				return -EIO;
 			}
 
@@ -853,7 +854,7 @@
 			if (usb_submit_urb (mdc800->write_urb, GFP_KERNEL))
 			{
 				err ("submitting write urb fails (status=%i)", mdc800->write_urb->status);
-				up (&mdc800->io_lock);
+				mutex_unlock(&mdc800->io_lock);
 				return -EIO;
 			}
 			wait_event_timeout(mdc800->write_wait, mdc800->written, TO_WRITE_GET_READY*HZ/1000);
@@ -861,7 +862,7 @@
 			if (mdc800->state == WORKING)
 			{
 				usb_kill_urb(mdc800->write_urb);
-				up (&mdc800->io_lock);
+				mutex_unlock(&mdc800->io_lock);
 				return -EIO;
 			}
 
@@ -873,7 +874,7 @@
 					{
 						err ("call 0x07 before 0x05,0x3e");
 						mdc800->state=READY;
-						up (&mdc800->io_lock);
+						mutex_unlock(&mdc800->io_lock);
 						return -EIO;
 					}
 					mdc800->pic_len=-1;
@@ -892,7 +893,7 @@
 						if (mdc800_usb_waitForIRQ (1,TO_READ_FROM_IRQ))
 						{
 							err ("requesting answer from irq fails");
-							up (&mdc800->io_lock);
+							mutex_unlock(&mdc800->io_lock);
 							return -EIO;
 						}
 
@@ -920,7 +921,7 @@
 						if (mdc800_usb_waitForIRQ (0,TO_DEFAULT_COMMAND))
 						{
 							err ("Command Timeout.");
-							up (&mdc800->io_lock);
+							mutex_unlock(&mdc800->io_lock);
 							return -EIO;
 						}
 					}
@@ -930,7 +931,7 @@
 		}
 		i++;
 	}
-	up (&mdc800->io_lock);
+	mutex_unlock(&mdc800->io_lock);
 	return i;
 }
 
@@ -978,15 +979,13 @@
 {
 	int retval = -ENODEV;
 	/* Allocate Memory */
-	mdc800=kmalloc (sizeof (struct mdc800_data), GFP_KERNEL);
+	mdc800=kzalloc (sizeof (struct mdc800_data), GFP_KERNEL);
 	if (!mdc800)
 		goto cleanup_on_fail;
 
-	memset(mdc800, 0, sizeof(struct mdc800_data));
 	mdc800->dev = NULL;
-	mdc800->open=0;
 	mdc800->state=NOT_CONNECTED;
-	init_MUTEX (&mdc800->io_lock);
+	mutex_init (&mdc800->io_lock);
 
 	init_waitqueue_head (&mdc800->irq_wait);
 	init_waitqueue_head (&mdc800->write_wait);
diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c
index f7bdc50..99f986c 100644
--- a/drivers/usb/input/ati_remote.c
+++ b/drivers/usb/input/ati_remote.c
@@ -159,8 +159,6 @@
  */
 #define FILTER_TIME (HZ / 20)
 
-static DECLARE_MUTEX(disconnect_sem);
-
 struct ati_remote {
 	struct input_dev *idev;
 	struct usb_device *udev;
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
index 07a012f..58b59f6 100644
--- a/drivers/usb/input/hid-core.c
+++ b/drivers/usb/input/hid-core.c
@@ -66,9 +66,8 @@
 	if (report_enum->report_id_hash[id])
 		return report_enum->report_id_hash[id];
 
-	if (!(report = kmalloc(sizeof(struct hid_report), GFP_KERNEL)))
+	if (!(report = kzalloc(sizeof(struct hid_report), GFP_KERNEL)))
 		return NULL;
-	memset(report, 0, sizeof(struct hid_report));
 
 	if (id != 0)
 		report_enum->numbered = 1;
@@ -97,12 +96,9 @@
 		return NULL;
 	}
 
-	if (!(field = kmalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
+	if (!(field = kzalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
 		+ values * sizeof(unsigned), GFP_KERNEL))) return NULL;
 
-	memset(field, 0, sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
-		+ values * sizeof(unsigned));
-
 	field->index = report->maxfield++;
 	report->field[field->index] = field;
 	field->usage = (struct hid_usage *)(field + 1);
@@ -651,17 +647,14 @@
 		hid_parser_reserved
 	};
 
-	if (!(device = kmalloc(sizeof(struct hid_device), GFP_KERNEL)))
+	if (!(device = kzalloc(sizeof(struct hid_device), GFP_KERNEL)))
 		return NULL;
-	memset(device, 0, sizeof(struct hid_device));
 
-	if (!(device->collection = kmalloc(sizeof(struct hid_collection) *
+	if (!(device->collection = kzalloc(sizeof(struct hid_collection) *
 				   HID_DEFAULT_NUM_COLLECTIONS, GFP_KERNEL))) {
 		kfree(device);
 		return NULL;
 	}
-	memset(device->collection, 0, sizeof(struct hid_collection) *
-		HID_DEFAULT_NUM_COLLECTIONS);
 	device->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
 
 	for (i = 0; i < HID_REPORT_TYPES; i++)
@@ -675,13 +668,12 @@
 	memcpy(device->rdesc, start, size);
 	device->rsize = size;
 
-	if (!(parser = kmalloc(sizeof(struct hid_parser), GFP_KERNEL))) {
+	if (!(parser = kzalloc(sizeof(struct hid_parser), GFP_KERNEL))) {
 		kfree(device->rdesc);
 		kfree(device->collection);
 		kfree(device);
 		return NULL;
 	}
-	memset(parser, 0, sizeof(struct hid_parser));
 	parser->device = device;
 
 	end = start + size;
@@ -911,6 +903,99 @@
 }
 
 /*
+ * Input submission and I/O error handler.
+ */
+
+static void hid_io_error(struct hid_device *hid);
+
+/* Start up the input URB */
+static int hid_start_in(struct hid_device *hid)
+{
+	unsigned long flags;
+	int rc = 0;
+
+	spin_lock_irqsave(&hid->inlock, flags);
+	if (hid->open > 0 && !test_bit(HID_SUSPENDED, &hid->iofl) &&
+			!test_and_set_bit(HID_IN_RUNNING, &hid->iofl)) {
+		rc = usb_submit_urb(hid->urbin, GFP_ATOMIC);
+		if (rc != 0)
+			clear_bit(HID_IN_RUNNING, &hid->iofl);
+	}
+	spin_unlock_irqrestore(&hid->inlock, flags);
+	return rc;
+}
+
+/* I/O retry timer routine */
+static void hid_retry_timeout(unsigned long _hid)
+{
+	struct hid_device *hid = (struct hid_device *) _hid;
+
+	dev_dbg(&hid->intf->dev, "retrying intr urb\n");
+	if (hid_start_in(hid))
+		hid_io_error(hid);
+}
+
+/* Workqueue routine to reset the device */
+static void hid_reset(void *_hid)
+{
+	struct hid_device *hid = (struct hid_device *) _hid;
+	int rc_lock, rc;
+
+	dev_dbg(&hid->intf->dev, "resetting device\n");
+	rc = rc_lock = usb_lock_device_for_reset(hid->dev, hid->intf);
+	if (rc_lock >= 0) {
+		rc = usb_reset_device(hid->dev);
+		if (rc_lock)
+			usb_unlock_device(hid->dev);
+	}
+	clear_bit(HID_RESET_PENDING, &hid->iofl);
+
+	if (rc == 0) {
+		hid->retry_delay = 0;
+		if (hid_start_in(hid))
+			hid_io_error(hid);
+	} else if (!(rc == -ENODEV || rc == -EHOSTUNREACH || rc == -EINTR))
+		err("can't reset device, %s-%s/input%d, status %d",
+				hid->dev->bus->bus_name,
+				hid->dev->devpath,
+				hid->ifnum, rc);
+}
+
+/* Main I/O error handler */
+static void hid_io_error(struct hid_device *hid)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&hid->inlock, flags);
+
+	/* Stop when disconnected */
+	if (usb_get_intfdata(hid->intf) == NULL)
+		goto done;
+
+	/* When an error occurs, retry at increasing intervals */
+	if (hid->retry_delay == 0) {
+		hid->retry_delay = 13;	/* Then 26, 52, 104, 104, ... */
+		hid->stop_retry = jiffies + msecs_to_jiffies(1000);
+	} else if (hid->retry_delay < 100)
+		hid->retry_delay *= 2;
+
+	if (time_after(jiffies, hid->stop_retry)) {
+
+		/* Retries failed, so do a port reset */
+		if (!test_and_set_bit(HID_RESET_PENDING, &hid->iofl)) {
+			if (schedule_work(&hid->reset_work))
+				goto done;
+			clear_bit(HID_RESET_PENDING, &hid->iofl);
+		}
+	}
+
+	mod_timer(&hid->io_retry,
+			jiffies + msecs_to_jiffies(hid->retry_delay));
+done:
+	spin_unlock_irqrestore(&hid->inlock, flags);
+}
+
+/*
  * Input interrupt completion handler.
  */
 
@@ -921,25 +1006,35 @@
 
 	switch (urb->status) {
 		case 0:			/* success */
+			hid->retry_delay = 0;
 			hid_input_report(HID_INPUT_REPORT, urb, 1, regs);
 			break;
 		case -ECONNRESET:	/* unlink */
 		case -ENOENT:
-		case -EPERM:
 		case -ESHUTDOWN:	/* unplug */
-		case -EILSEQ:		/* unplug timeout on uhci */
+			clear_bit(HID_IN_RUNNING, &hid->iofl);
 			return;
+		case -EILSEQ:		/* protocol error or unplug */
+		case -EPROTO:		/* protocol error or unplug */
 		case -ETIMEDOUT:	/* NAK */
-			break;
+			clear_bit(HID_IN_RUNNING, &hid->iofl);
+			hid_io_error(hid);
+			return;
 		default:		/* error */
 			warn("input irq status %d received", urb->status);
 	}
 
 	status = usb_submit_urb(urb, SLAB_ATOMIC);
-	if (status)
-		err("can't resubmit intr, %s-%s/input%d, status %d",
-				hid->dev->bus->bus_name, hid->dev->devpath,
-				hid->ifnum, status);
+	if (status) {
+		clear_bit(HID_IN_RUNNING, &hid->iofl);
+		if (status != -EPERM) {
+			err("can't resubmit intr, %s-%s/input%d, status %d",
+					hid->dev->bus->bus_name,
+					hid->dev->devpath,
+					hid->ifnum, status);
+			hid_io_error(hid);
+		}
+	}
 }
 
 /*
@@ -1101,8 +1196,9 @@
 		case 0:			/* success */
 			break;
 		case -ESHUTDOWN:	/* unplug */
-		case -EILSEQ:		/* unplug timeout on uhci */
 			unplug = 1;
+		case -EILSEQ:		/* protocol error or unplug */
+		case -EPROTO:		/* protocol error or unplug */
 		case -ECONNRESET:	/* unlink */
 		case -ENOENT:
 			break;
@@ -1149,8 +1245,9 @@
 				hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, 0, regs);
 			break;
 		case -ESHUTDOWN:	/* unplug */
-		case -EILSEQ:		/* unplug timectrl on uhci */
 			unplug = 1;
+		case -EILSEQ:		/* protocol error or unplug */
+		case -EPROTO:		/* protocol error or unplug */
 		case -ECONNRESET:	/* unlink */
 		case -ENOENT:
 		case -EPIPE:		/* report not available */
@@ -1263,14 +1360,9 @@
 
 int hid_open(struct hid_device *hid)
 {
-	if (hid->open++)
-		return 0;
-
-	hid->urbin->dev = hid->dev;
-
-	if (usb_submit_urb(hid->urbin, GFP_KERNEL))
-		return -EIO;
-
+	++hid->open;
+	if (hid_start_in(hid))
+		hid_io_error(hid);
 	return 0;
 }
 
@@ -1460,6 +1552,9 @@
 #define USB_VENDOR_ID_HP		0x03f0
 #define USB_DEVICE_ID_HP_USBHUB_KB	0x020c
 
+#define USB_VENDOR_ID_CREATIVELABS	0x062a
+#define USB_DEVICE_ID_CREATIVELABS_SILVERCREST	0x0201
+
 /*
  * Alphabetically sorted blacklist by quirk type.
  */
@@ -1576,6 +1671,7 @@
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_KEYBOARD, HID_QUIRK_NOGET},
 	{ USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_USBHUB_KB, HID_QUIRK_NOGET},
+	{ USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVELABS_SILVERCREST, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_HP, USB_DEVICE_ID_HP_USBHUB_KB, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
@@ -1795,6 +1891,10 @@
 
 	init_waitqueue_head(&hid->wait);
 
+	INIT_WORK(&hid->reset_work, hid_reset, hid);
+	setup_timer(&hid->io_retry, hid_retry_timeout, (unsigned long) hid);
+
+	spin_lock_init(&hid->inlock);
 	spin_lock_init(&hid->outlock);
 	spin_lock_init(&hid->ctrllock);
 
@@ -1863,11 +1963,16 @@
 	if (!hid)
 		return;
 
+	spin_lock_irq(&hid->inlock);	/* Sync with error handler */
 	usb_set_intfdata(intf, NULL);
+	spin_unlock_irq(&hid->inlock);
 	usb_kill_urb(hid->urbin);
 	usb_kill_urb(hid->urbout);
 	usb_kill_urb(hid->urbctrl);
 
+	del_timer_sync(&hid->io_retry);
+	flush_scheduled_work();
+
 	if (hid->claimed & HID_CLAIMED_INPUT)
 		hidinput_disconnect(hid);
 	if (hid->claimed & HID_CLAIMED_HIDDEV)
@@ -1942,6 +2047,10 @@
 {
 	struct hid_device *hid = usb_get_intfdata (intf);
 
+	spin_lock_irq(&hid->inlock);	/* Sync with error handler */
+	set_bit(HID_SUSPENDED, &hid->iofl);
+	spin_unlock_irq(&hid->inlock);
+	del_timer(&hid->io_retry);
 	usb_kill_urb(hid->urbin);
 	dev_dbg(&intf->dev, "suspend\n");
 	return 0;
@@ -1952,10 +2061,8 @@
 	struct hid_device *hid = usb_get_intfdata (intf);
 	int status;
 
-	if (hid->open)
-		status = usb_submit_urb(hid->urbin, GFP_NOIO);
-	else
-		status = 0;
+	clear_bit(HID_SUSPENDED, &hid->iofl);
+	status = hid_start_in(hid);
 	dev_dbg(&intf->dev, "resume status %d\n", status);
 	return status;
 }
diff --git a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c
index f82c9c9..f07d443 100644
--- a/drivers/usb/input/hid-lgff.c
+++ b/drivers/usb/input/hid-lgff.c
@@ -154,10 +154,9 @@
 		return -1;
 	}
 
-	private = kmalloc(sizeof(struct lgff_device), GFP_KERNEL);
+	private = kzalloc(sizeof(struct lgff_device), GFP_KERNEL);
 	if (!private)
 		return -1;
-	memset(private, 0, sizeof(struct lgff_device));
 	hid->ff_private = private;
 
 	/* Input init */
@@ -228,13 +227,12 @@
 	}
 	*ret->field[0] = *report->field[0];
 
-	ret->field[0]->value = kmalloc(sizeof(s32[8]), GFP_KERNEL);
+	ret->field[0]->value = kzalloc(sizeof(s32[8]), GFP_KERNEL);
 	if (!ret->field[0]->value) {
 		kfree(ret->field[0]);
 		kfree(ret);
 		return NULL;
 	}
-	memset(ret->field[0]->value, 0, sizeof(s32[8]));
 
 	return ret;
 }
diff --git a/drivers/usb/input/hid-tmff.c b/drivers/usb/input/hid-tmff.c
index 023fd5a..534425c 100644
--- a/drivers/usb/input/hid-tmff.c
+++ b/drivers/usb/input/hid-tmff.c
@@ -113,11 +113,10 @@
 	struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
 	struct input_dev *input_dev = hidinput->input;
 
-	private = kmalloc(sizeof(struct tmff_device), GFP_KERNEL);
+	private = kzalloc(sizeof(struct tmff_device), GFP_KERNEL);
 	if (!private)
 		return -ENOMEM;
 
-	memset(private, 0, sizeof(struct tmff_device));
 	hid->ff_private = private;
 
 	/* Find the report to use */
diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h
index 8b0d434..4e1b784 100644
--- a/drivers/usb/input/hid.h
+++ b/drivers/usb/input/hid.h
@@ -31,6 +31,8 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
 
 /*
  * USB HID (Human Interface Device) interface class code
@@ -370,6 +372,9 @@
 
 #define HID_CTRL_RUNNING	1
 #define HID_OUT_RUNNING		2
+#define HID_IN_RUNNING		3
+#define HID_RESET_PENDING	4
+#define HID_SUSPENDED		5
 
 struct hid_input {
 	struct list_head list;
@@ -393,12 +398,17 @@
 	int ifnum;							/* USB interface number */
 
 	unsigned long iofl;						/* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
+	struct timer_list io_retry;					/* Retry timer */
+	unsigned long stop_retry;					/* Time to give up, in jiffies */
+	unsigned int retry_delay;					/* Delay length in ms */
+	struct work_struct reset_work;					/* Task context for resets */
 
 	unsigned int bufsize;						/* URB buffer size */
 
 	struct urb *urbin;						/* Input URB */
 	char *inbuf;							/* Input buffer */
 	dma_addr_t inbuf_dma;						/* Input buffer dma */
+	spinlock_t inlock;						/* Input fifo spinlock */
 
 	struct urb *urbctrl;						/* Control URB */
 	struct usb_ctrlrequest *cr;					/* Control request struct */
diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c
index 925f5ab..6dd6666 100644
--- a/drivers/usb/input/hiddev.c
+++ b/drivers/usb/input/hiddev.c
@@ -257,9 +257,8 @@
 	if (i >= HIDDEV_MINORS || !hiddev_table[i])
 		return -ENODEV;
 
-	if (!(list = kmalloc(sizeof(struct hiddev_list), GFP_KERNEL)))
+	if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL)))
 		return -ENOMEM;
-	memset(list, 0, sizeof(struct hiddev_list));
 
 	list->hiddev = hiddev_table[i];
 	list->next = hiddev_table[i]->list;
@@ -754,9 +753,8 @@
 	if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDDEV) == 0)
 		return -1;
 
-	if (!(hiddev = kmalloc(sizeof(struct hiddev), GFP_KERNEL)))
+	if (!(hiddev = kzalloc(sizeof(struct hiddev), GFP_KERNEL)))
 		return -1;
-	memset(hiddev, 0, sizeof(struct hiddev));
 
 	retval = usb_register_dev(hid->intf, &hiddev_class);
 	if (retval) {
diff --git a/drivers/usb/media/Kconfig b/drivers/usb/media/Kconfig
index 0d3d2cc..189d40f 100644
--- a/drivers/usb/media/Kconfig
+++ b/drivers/usb/media/Kconfig
@@ -191,6 +191,21 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called w9968cf.
 
+config USB_ZC0301
+	tristate "USB ZC0301 Image Processor and Control Chip support"
+	depends on USB && VIDEO_DEV
+	---help---
+	  Say Y here if you want support for cameras based on the ZC0301
+	  Image Processor and Control Chip.
+
+	  See <file:Documentation/usb/zc0301.txt> for more informations.
+
+	  This driver uses the Video For Linux API. You must say Y or M to
+	  "Video For Linux" to use this driver.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called zc0301.
+
 config USB_PWC
 	tristate "USB Philips Cameras"
 	depends on USB && VIDEO_DEV
diff --git a/drivers/usb/media/Makefile b/drivers/usb/media/Makefile
index 3957aa1..50e89a3 100644
--- a/drivers/usb/media/Makefile
+++ b/drivers/usb/media/Makefile
@@ -2,8 +2,12 @@
 # Makefile for USB Media drivers
 #
 
-sn9c102-objs	:= sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o sn9c102_ov7630.o sn9c102_pas106b.o sn9c102_pas202bcb.o sn9c102_tas5110c1b.o sn9c102_tas5130d1b.o
+sn9c102-objs	:= sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o \
+		   sn9c102_ov7630.o sn9c102_pas106b.o sn9c102_pas202bca.o \
+		   sn9c102_pas202bcb.o sn9c102_tas5110c1b.o \
+		   sn9c102_tas5130d1b.o
 et61x251-objs	:= et61x251_core.o et61x251_tas5130d1b.o
+zc0301-objs	:= zc0301_core.o zc0301_pas202bcb.o
 
 obj-$(CONFIG_USB_DABUSB)	+= dabusb.o
 obj-$(CONFIG_USB_DSBR)		+= dsbr100.o
@@ -16,4 +20,5 @@
 obj-$(CONFIG_USB_STV680)	+= stv680.o
 obj-$(CONFIG_USB_VICAM)		+= vicam.o usbvideo.o
 obj-$(CONFIG_USB_W9968CF)	+= w9968cf.o
+obj-$(CONFIG_USB_ZC0301)	+= zc0301.o
 obj-$(CONFIG_USB_PWC)           += pwc/
diff --git a/drivers/usb/media/dabusb.c b/drivers/usb/media/dabusb.c
index 18d8eaf..1774ab7 100644
--- a/drivers/usb/media/dabusb.c
+++ b/drivers/usb/media/dabusb.c
@@ -38,6 +38,7 @@
 #include <linux/delay.h>
 #include <linux/usb.h>
 #include <linux/smp_lock.h>
+#include <linux/mutex.h>
 
 #include "dabusb.h"
 #include "dabfirmware.h"
@@ -217,12 +218,11 @@
 		 pipesize, packets, transfer_buffer_length);
 
 	while (buffers < (s->total_buffer_size << 10)) {
-		b = (pbuff_t) kmalloc (sizeof (buff_t), GFP_KERNEL);
+		b = (pbuff_t) kzalloc (sizeof (buff_t), GFP_KERNEL);
 		if (!b) {
-			err("kmalloc(sizeof(buff_t))==NULL");
+			err("kzalloc(sizeof(buff_t))==NULL");
 			goto err;
 		}
-		memset (b, 0, sizeof (buff_t));
 		b->s = s;
 		b->purb = usb_alloc_urb(packets, GFP_KERNEL);
 		if (!b->purb) {
@@ -571,7 +571,7 @@
 			s->readptr = 0;
 		}
 	}
-      err:			//up(&s->mutex);
+      err:			//mutex_unlock(&s->mutex);
 	return ret;
 }
 
@@ -586,10 +586,10 @@
 	s = &dabusb[devnum - DABUSB_MINOR];
 
 	dbg("dabusb_open");
-	down (&s->mutex);
+	mutex_lock(&s->mutex);
 
 	while (!s->usbdev || s->opened) {
-		up (&s->mutex);
+		mutex_unlock(&s->mutex);
 
 		if (file->f_flags & O_NONBLOCK) {
 			return -EBUSY;
@@ -599,15 +599,15 @@
 		if (signal_pending (current)) {
 			return -EAGAIN;
 		}
-		down (&s->mutex);
+		mutex_lock(&s->mutex);
 	}
 	if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) {
-		up(&s->mutex);
+		mutex_unlock(&s->mutex);
 		err("set_interface failed");
 		return -EINVAL;
 	}
 	s->opened = 1;
-	up (&s->mutex);
+	mutex_unlock(&s->mutex);
 
 	file->f_pos = 0;
 	file->private_data = s;
@@ -621,10 +621,10 @@
 
 	dbg("dabusb_release");
 
-	down (&s->mutex);
+	mutex_lock(&s->mutex);
 	dabusb_stop (s);
 	dabusb_free_buffers (s);
-	up (&s->mutex);
+	mutex_unlock(&s->mutex);
 
 	if (!s->remove_pending) {
 		if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0)
@@ -649,10 +649,10 @@
 	if (s->remove_pending)
 		return -EIO;
 
-	down (&s->mutex);
+	mutex_lock(&s->mutex);
 
 	if (!s->usbdev) {
-		up (&s->mutex);
+		mutex_unlock(&s->mutex);
 		return -EIO;
 	}
 
@@ -692,7 +692,7 @@
 		ret = -ENOIOCTLCMD;
 		break;
 	}
-	up (&s->mutex);
+	mutex_unlock(&s->mutex);
 	return ret;
 }
 
@@ -738,7 +738,7 @@
 
 	s = &dabusb[intf->minor];
 
-	down (&s->mutex);
+	mutex_lock(&s->mutex);
 	s->remove_pending = 0;
 	s->usbdev = usbdev;
 	s->devnum = intf->minor;
@@ -761,7 +761,7 @@
 	}
 	dbg("bound to interface: %d", intf->altsetting->desc.bInterfaceNumber);
 	usb_set_intfdata (intf, s);
-	up (&s->mutex);
+	mutex_unlock(&s->mutex);
 
 	retval = usb_register_dev(intf, &dabusb_class);
 	if (retval) {
@@ -772,7 +772,7 @@
 	return 0;
 
       reject:
-	up (&s->mutex);
+	mutex_unlock(&s->mutex);
 	s->usbdev = NULL;
 	return -ENODEV;
 }
@@ -829,7 +829,7 @@
 	for (u = 0; u < NRDABUSB; u++) {
 		pdabusb_t s = &dabusb[u];
 		memset (s, 0, sizeof (dabusb_t));
-		init_MUTEX (&s->mutex);
+		mutex_init (&s->mutex);
 		s->usbdev = NULL;
 		s->total_buffer_size = buffers;
 		init_waitqueue_head (&s->wait);
diff --git a/drivers/usb/media/dabusb.h b/drivers/usb/media/dabusb.h
index 10b666e..96b03e4 100644
--- a/drivers/usb/media/dabusb.h
+++ b/drivers/usb/media/dabusb.h
@@ -18,7 +18,7 @@
 
 typedef struct
 {
-	struct semaphore mutex;
+	struct mutex mutex;
 	struct usb_device *usbdev;
 	wait_queue_head_t wait;
 	wait_queue_head_t remove_ok;
diff --git a/drivers/usb/media/et61x251.h b/drivers/usb/media/et61x251.h
index 652238f..eee8afc 100644
--- a/drivers/usb/media/et61x251.h
+++ b/drivers/usb/media/et61x251.h
@@ -33,7 +33,9 @@
 #include <linux/types.h>
 #include <linux/param.h>
 #include <linux/rwsem.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
 
 #include "et61x251_sensor.h"
 
@@ -51,6 +53,7 @@
 #define ET61X251_ALTERNATE_SETTING   13
 #define ET61X251_URB_TIMEOUT         msecs_to_jiffies(2 * ET61X251_ISO_PACKETS)
 #define ET61X251_CTRL_TIMEOUT        100
+#define ET61X251_FRAME_TIMEOUT       2
 
 /*****************************************************************************/
 
@@ -127,15 +130,16 @@
 
 struct et61x251_module_param {
 	u8 force_munmap;
+	u16 frame_timeout;
 };
 
-static DECLARE_MUTEX(et61x251_sysfs_lock);
+static DEFINE_MUTEX(et61x251_sysfs_lock);
 static DECLARE_RWSEM(et61x251_disconnect);
 
 struct et61x251_device {
 	struct video_device* v4ldev;
 
-	struct et61x251_sensor* sensor;
+	struct et61x251_sensor sensor;
 
 	struct usb_device* usbdev;
 	struct urb* urb[ET61X251_URBS];
@@ -157,19 +161,28 @@
 	enum et61x251_dev_state state;
 	u8 users;
 
-	struct semaphore dev_sem, fileop_sem;
+	struct mutex dev_mutex, fileop_mutex;
 	spinlock_t queue_lock;
 	wait_queue_head_t open, wait_frame, wait_stream;
 };
 
 /*****************************************************************************/
 
+struct et61x251_device*
+et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id)
+{
+	if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id))
+		return cam;
+
+	return NULL;
+}
+
+
 void
 et61x251_attach_sensor(struct et61x251_device* cam,
                        struct et61x251_sensor* sensor)
 {
-	cam->sensor = sensor;
-	cam->sensor->usbdev = cam->usbdev;
+	memcpy(&cam->sensor, sensor, sizeof(struct et61x251_sensor));
 }
 
 /*****************************************************************************/
@@ -212,7 +225,8 @@
 
 #undef PDBG
 #define PDBG(fmt, args...)                                                    \
-dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args)
+dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",                              \
+         __FUNCTION__, __LINE__ , ## args)
 
 #undef PDBGG
 #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
diff --git a/drivers/usb/media/et61x251_core.c b/drivers/usb/media/et61x251_core.c
index 2c0171a..7cc01b8 100644
--- a/drivers/usb/media/et61x251_core.c
+++ b/drivers/usb/media/et61x251_core.c
@@ -25,11 +25,9 @@
 #include <linux/moduleparam.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
-#include <linux/string.h>
 #include <linux/device.h>
 #include <linux/fs.h>
 #include <linux/delay.h>
-#include <linux/stddef.h>
 #include <linux/compiler.h>
 #include <linux/ioctl.h>
 #include <linux/poll.h>
@@ -50,8 +48,8 @@
 #define ET61X251_MODULE_AUTHOR  "(C) 2006 Luca Risolia"
 #define ET61X251_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"
 #define ET61X251_MODULE_LICENSE "GPL"
-#define ET61X251_MODULE_VERSION "1:1.01"
-#define ET61X251_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 1)
+#define ET61X251_MODULE_VERSION "1:1.02"
+#define ET61X251_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 2)
 
 /*****************************************************************************/
 
@@ -90,6 +88,16 @@
                  "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
                  "\n");
 
+static unsigned int frame_timeout[] = {[0 ... ET61X251_MAX_DEVICES-1] =
+                                       ET61X251_FRAME_TIMEOUT};
+module_param_array(frame_timeout, uint, NULL, 0644);
+MODULE_PARM_DESC(frame_timeout,
+                 "\n<n[,...]> Timeout for a video frame in seconds."
+                 "\nThis parameter is specific for each detected camera."
+                 "\nDefault value is "
+                 __MODULE_STRING(ET61X251_FRAME_TIMEOUT)"."
+                 "\n");
+
 #ifdef ET61X251_DEBUG
 static unsigned short debug = ET61X251_DEBUG_LEVEL;
 module_param(debug, ushort, 0644);
@@ -111,8 +119,8 @@
 et61x251_request_buffers(struct et61x251_device* cam, u32 count,
                          enum et61x251_io_method io)
 {
-	struct v4l2_pix_format* p = &(cam->sensor->pix_format);
-	struct v4l2_rect* r = &(cam->sensor->cropcap.bounds);
+	struct v4l2_pix_format* p = &(cam->sensor.pix_format);
+	struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
 	const size_t imagesize = cam->module_param.force_munmap ||
 	                         io == IO_READ ?
 	                         (p->width * p->height * p->priv) / 8 :
@@ -268,8 +276,8 @@
 	int err = 0, res;
 
 	data[0] = address;
-	data[1] = cam->sensor->i2c_slave_id;
-	data[2] = cam->sensor->rsta | 0x10;
+	data[1] = cam->sensor.i2c_slave_id;
+	data[2] = cam->sensor.rsta | 0x10;
 	data[3] = !(et61x251_read_reg(cam, 0x8b) & 0x02);
 	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
 	                      0, 0x88, data, 4, ET61X251_CTRL_TIMEOUT);
@@ -301,8 +309,8 @@
 	int err = 0, res;
 
 	data[0] = address;
-	data[1] = cam->sensor->i2c_slave_id;
-	data[2] = cam->sensor->rsta | 0x12;
+	data[1] = cam->sensor.i2c_slave_id;
+	data[2] = cam->sensor.rsta | 0x12;
 	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
 	                      0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT);
 	if (res < 0)
@@ -334,9 +342,6 @@
 	u8* data = cam->control_buffer;
 	int err = 0, res;
 
-	if (!cam->sensor)
-		return -1;
-
 	data[0] = data2;
 	data[1] = data3;
 	data[2] = data4;
@@ -350,8 +355,8 @@
 		err += res;
 
 	data[0] = address;
-	data[1] = cam->sensor->i2c_slave_id;
-	data[2] = cam->sensor->rsta | 0x02 | (n << 4);
+	data[1] = cam->sensor.i2c_slave_id;
+	data[2] = cam->sensor.rsta | 0x02 | (n << 4);
 	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
 	                      0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT);
 	if (res < 0)
@@ -364,11 +369,11 @@
 	if (res < 0)
 		err += res;
 
-	err += et61x251_i2c_wait(cam, cam->sensor);
+	err += et61x251_i2c_wait(cam, &cam->sensor);
 
 	if (err)
 		DBG(3, "I2C raw write failed for %s image sensor",
-		    cam->sensor->name);
+		    cam->sensor.name);
 
 	PDBGG("I2C raw write: %u bytes, address = 0x%02X, data1 = 0x%02X, "
 	      "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X,"
@@ -382,19 +387,13 @@
 
 int et61x251_i2c_read(struct et61x251_device* cam, u8 address)
 {
-	if (!cam->sensor)
-		return -1;
-
-	return et61x251_i2c_try_read(cam, cam->sensor, address);
+	return et61x251_i2c_try_read(cam, &cam->sensor, address);
 }
 
 
 int et61x251_i2c_write(struct et61x251_device* cam, u8 address, u8 value)
 {
-	if (!cam->sensor)
-		return -1;
-
-	return et61x251_i2c_try_write(cam, cam->sensor, address, value);
+	return et61x251_i2c_try_write(cam, &cam->sensor, address, value);
 }
 
 /*****************************************************************************/
@@ -417,7 +416,7 @@
 		if ((*f))
 			(*f)->state = F_QUEUED;
 		DBG(3, "Stream interrupted");
-		wake_up_interruptible(&cam->wait_stream);
+		wake_up(&cam->wait_stream);
 	}
 
 	if (cam->state & DEV_DISCONNECTED)
@@ -435,9 +434,9 @@
 		(*f) = list_entry(cam->inqueue.next, struct et61x251_frame_t,
 		                  frame);
 
-	imagesize = (cam->sensor->pix_format.width *
-	             cam->sensor->pix_format.height *
-	             cam->sensor->pix_format.priv) / 8;
+	imagesize = (cam->sensor.pix_format.width *
+	             cam->sensor.pix_format.height *
+	             cam->sensor.pix_format.priv) / 8;
 
 	for (i = 0; i < urb->number_of_packets; i++) {
 		unsigned int len, status;
@@ -476,7 +475,7 @@
 
 		if ((*f)->state == F_GRABBING) {
 			if (sof && (*f)->buf.bytesused) {
-				if (cam->sensor->pix_format.pixelformat ==
+				if (cam->sensor.pix_format.pixelformat ==
 				                         V4L2_PIX_FMT_ET61X251)
 					goto end_of_frame;
 				else {
@@ -521,7 +520,7 @@
 					goto resubmit_urb;
 
 				if (sof &&
-				    cam->sensor->pix_format.pixelformat ==
+				    cam->sensor.pix_format.pixelformat ==
 				                         V4L2_PIX_FMT_ET61X251)
 					goto start_of_frame;
 			}
@@ -650,21 +649,21 @@
 
 static int et61x251_stream_interrupt(struct et61x251_device* cam)
 {
-	int err = 0;
+	long timeout;
 
 	cam->stream = STREAM_INTERRUPT;
-	err = wait_event_timeout(cam->wait_stream,
-	                         (cam->stream == STREAM_OFF) ||
-	                         (cam->state & DEV_DISCONNECTED),
-	                         ET61X251_URB_TIMEOUT);
+	timeout = wait_event_timeout(cam->wait_stream,
+	                             (cam->stream == STREAM_OFF) ||
+	                             (cam->state & DEV_DISCONNECTED),
+	                             ET61X251_URB_TIMEOUT);
 	if (cam->state & DEV_DISCONNECTED)
 		return -ENODEV;
-	else if (err) {
+	else if (cam->stream != STREAM_OFF) {
 		cam->state |= DEV_MISCONFIGURED;
 		DBG(1, "URB timeout reached. The camera is misconfigured. To "
 		       "use it, close and open /dev/video%d again.",
 		    cam->v4ldev->minor);
-		return err;
+		return -EIO;
 	}
 
 	return 0;
@@ -709,18 +708,18 @@
 	struct et61x251_device* cam;
 	ssize_t count;
 
-	if (down_interruptible(&et61x251_sysfs_lock))
+	if (mutex_lock_interruptible(&et61x251_sysfs_lock))
 		return -ERESTARTSYS;
 
 	cam = video_get_drvdata(to_video_device(cd));
 	if (!cam) {
-		up(&et61x251_sysfs_lock);
+		mutex_unlock(&et61x251_sysfs_lock);
 		return -ENODEV;
 	}
 
 	count = sprintf(buf, "%u\n", cam->sysfs.reg);
 
-	up(&et61x251_sysfs_lock);
+	mutex_unlock(&et61x251_sysfs_lock);
 
 	return count;
 }
@@ -733,18 +732,18 @@
 	u8 index;
 	ssize_t count;
 
-	if (down_interruptible(&et61x251_sysfs_lock))
+	if (mutex_lock_interruptible(&et61x251_sysfs_lock))
 		return -ERESTARTSYS;
 
 	cam = video_get_drvdata(to_video_device(cd));
 	if (!cam) {
-		up(&et61x251_sysfs_lock);
+		mutex_unlock(&et61x251_sysfs_lock);
 		return -ENODEV;
 	}
 
 	index = et61x251_strtou8(buf, len, &count);
 	if (index > 0x8e || !count) {
-		up(&et61x251_sysfs_lock);
+		mutex_unlock(&et61x251_sysfs_lock);
 		return -EINVAL;
 	}
 
@@ -753,7 +752,7 @@
 	DBG(2, "Moved ET61X[12]51 register index to 0x%02X", cam->sysfs.reg);
 	DBG(3, "Written bytes: %zd", count);
 
-	up(&et61x251_sysfs_lock);
+	mutex_unlock(&et61x251_sysfs_lock);
 
 	return count;
 }
@@ -765,17 +764,17 @@
 	ssize_t count;
 	int val;
 
-	if (down_interruptible(&et61x251_sysfs_lock))
+	if (mutex_lock_interruptible(&et61x251_sysfs_lock))
 		return -ERESTARTSYS;
 
 	cam = video_get_drvdata(to_video_device(cd));
 	if (!cam) {
-		up(&et61x251_sysfs_lock);
+		mutex_unlock(&et61x251_sysfs_lock);
 		return -ENODEV;
 	}
 
 	if ((val = et61x251_read_reg(cam, cam->sysfs.reg)) < 0) {
-		up(&et61x251_sysfs_lock);
+		mutex_unlock(&et61x251_sysfs_lock);
 		return -EIO;
 	}
 
@@ -783,7 +782,7 @@
 
 	DBG(3, "Read bytes: %zd", count);
 
-	up(&et61x251_sysfs_lock);
+	mutex_unlock(&et61x251_sysfs_lock);
 
 	return count;
 }
@@ -797,24 +796,24 @@
 	ssize_t count;
 	int err;
 
-	if (down_interruptible(&et61x251_sysfs_lock))
+	if (mutex_lock_interruptible(&et61x251_sysfs_lock))
 		return -ERESTARTSYS;
 
 	cam = video_get_drvdata(to_video_device(cd));
 	if (!cam) {
-		up(&et61x251_sysfs_lock);
+		mutex_unlock(&et61x251_sysfs_lock);
 		return -ENODEV;
 	}
 
 	value = et61x251_strtou8(buf, len, &count);
 	if (!count) {
-		up(&et61x251_sysfs_lock);
+		mutex_unlock(&et61x251_sysfs_lock);
 		return -EINVAL;
 	}
 
 	err = et61x251_write_reg(cam, value, cam->sysfs.reg);
 	if (err) {
-		up(&et61x251_sysfs_lock);
+		mutex_unlock(&et61x251_sysfs_lock);
 		return -EIO;
 	}
 
@@ -822,7 +821,7 @@
 	    cam->sysfs.reg, value);
 	DBG(3, "Written bytes: %zd", count);
 
-	up(&et61x251_sysfs_lock);
+	mutex_unlock(&et61x251_sysfs_lock);
 
 	return count;
 }
@@ -833,12 +832,12 @@
 	struct et61x251_device* cam;
 	ssize_t count;
 
-	if (down_interruptible(&et61x251_sysfs_lock))
+	if (mutex_lock_interruptible(&et61x251_sysfs_lock))
 		return -ERESTARTSYS;
 
 	cam = video_get_drvdata(to_video_device(cd));
 	if (!cam) {
-		up(&et61x251_sysfs_lock);
+		mutex_unlock(&et61x251_sysfs_lock);
 		return -ENODEV;
 	}
 
@@ -846,7 +845,7 @@
 
 	DBG(3, "Read bytes: %zd", count);
 
-	up(&et61x251_sysfs_lock);
+	mutex_unlock(&et61x251_sysfs_lock);
 
 	return count;
 }
@@ -859,18 +858,18 @@
 	u8 index;
 	ssize_t count;
 
-	if (down_interruptible(&et61x251_sysfs_lock))
+	if (mutex_lock_interruptible(&et61x251_sysfs_lock))
 		return -ERESTARTSYS;
 
 	cam = video_get_drvdata(to_video_device(cd));
 	if (!cam) {
-		up(&et61x251_sysfs_lock);
+		mutex_unlock(&et61x251_sysfs_lock);
 		return -ENODEV;
 	}
 
 	index = et61x251_strtou8(buf, len, &count);
 	if (!count) {
-		up(&et61x251_sysfs_lock);
+		mutex_unlock(&et61x251_sysfs_lock);
 		return -EINVAL;
 	}
 
@@ -879,7 +878,7 @@
 	DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg);
 	DBG(3, "Written bytes: %zd", count);
 
-	up(&et61x251_sysfs_lock);
+	mutex_unlock(&et61x251_sysfs_lock);
 
 	return count;
 }
@@ -891,22 +890,22 @@
 	ssize_t count;
 	int val;
 
-	if (down_interruptible(&et61x251_sysfs_lock))
+	if (mutex_lock_interruptible(&et61x251_sysfs_lock))
 		return -ERESTARTSYS;
 
 	cam = video_get_drvdata(to_video_device(cd));
 	if (!cam) {
-		up(&et61x251_sysfs_lock);
+		mutex_unlock(&et61x251_sysfs_lock);
 		return -ENODEV;
 	}
 
-	if (!(cam->sensor->sysfs_ops & ET61X251_I2C_READ)) {
-		up(&et61x251_sysfs_lock);
+	if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) {
+		mutex_unlock(&et61x251_sysfs_lock);
 		return -ENOSYS;
 	}
 
 	if ((val = et61x251_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) {
-		up(&et61x251_sysfs_lock);
+		mutex_unlock(&et61x251_sysfs_lock);
 		return -EIO;
 	}
 
@@ -914,7 +913,7 @@
 
 	DBG(3, "Read bytes: %zd", count);
 
-	up(&et61x251_sysfs_lock);
+	mutex_unlock(&et61x251_sysfs_lock);
 
 	return count;
 }
@@ -928,29 +927,29 @@
 	ssize_t count;
 	int err;
 
-	if (down_interruptible(&et61x251_sysfs_lock))
+	if (mutex_lock_interruptible(&et61x251_sysfs_lock))
 		return -ERESTARTSYS;
 
 	cam = video_get_drvdata(to_video_device(cd));
 	if (!cam) {
-		up(&et61x251_sysfs_lock);
+		mutex_unlock(&et61x251_sysfs_lock);
 		return -ENODEV;
 	}
 
-	if (!(cam->sensor->sysfs_ops & ET61X251_I2C_READ)) {
-		up(&et61x251_sysfs_lock);
+	if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) {
+		mutex_unlock(&et61x251_sysfs_lock);
 		return -ENOSYS;
 	}
 
 	value = et61x251_strtou8(buf, len, &count);
 	if (!count) {
-		up(&et61x251_sysfs_lock);
+		mutex_unlock(&et61x251_sysfs_lock);
 		return -EINVAL;
 	}
 
 	err = et61x251_i2c_write(cam, cam->sysfs.i2c_reg, value);
 	if (err) {
-		up(&et61x251_sysfs_lock);
+		mutex_unlock(&et61x251_sysfs_lock);
 		return -EIO;
 	}
 
@@ -958,7 +957,7 @@
 	    cam->sysfs.i2c_reg, value);
 	DBG(3, "Written bytes: %zd", count);
 
-	up(&et61x251_sysfs_lock);
+	mutex_unlock(&et61x251_sysfs_lock);
 
 	return count;
 }
@@ -980,7 +979,7 @@
 
 	video_device_create_file(v4ldev, &class_device_attr_reg);
 	video_device_create_file(v4ldev, &class_device_attr_val);
-	if (cam->sensor && cam->sensor->sysfs_ops) {
+	if (cam->sensor.sysfs_ops) {
 		video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
 		video_device_create_file(v4ldev, &class_device_attr_i2c_val);
 	}
@@ -1048,7 +1047,7 @@
 static int
 et61x251_set_crop(struct et61x251_device* cam, struct v4l2_rect* rect)
 {
-	struct et61x251_sensor* s = cam->sensor;
+	struct et61x251_sensor* s = &cam->sensor;
 	u16 fmw_sx = (u16)(rect->left - s->cropcap.bounds.left +
 	                   s->active_pixel.left),
 	    fmw_sy = (u16)(rect->top - s->cropcap.bounds.top +
@@ -1076,7 +1075,7 @@
 
 static int et61x251_init(struct et61x251_device* cam)
 {
-	struct et61x251_sensor* s = cam->sensor;
+	struct et61x251_sensor* s = &cam->sensor;
 	struct v4l2_control ctrl;
 	struct v4l2_queryctrl *qctrl;
 	struct v4l2_rect* rect;
@@ -1143,7 +1142,7 @@
 	}
 
 	if (!(cam->state & DEV_INITIALIZED)) {
-		init_MUTEX(&cam->fileop_sem);
+		mutex_init(&cam->fileop_mutex);
 		spin_lock_init(&cam->queue_lock);
 		init_waitqueue_head(&cam->wait_frame);
 		init_waitqueue_head(&cam->wait_stream);
@@ -1161,13 +1160,15 @@
 
 static void et61x251_release_resources(struct et61x251_device* cam)
 {
-	down(&et61x251_sysfs_lock);
+	mutex_lock(&et61x251_sysfs_lock);
 
 	DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
 	video_set_drvdata(cam->v4ldev, NULL);
 	video_unregister_device(cam->v4ldev);
 
-	up(&et61x251_sysfs_lock);
+	usb_put_dev(cam->usbdev);
+
+	mutex_unlock(&et61x251_sysfs_lock);
 
 	kfree(cam->control_buffer);
 }
@@ -1188,7 +1189,7 @@
 
 	cam = video_get_drvdata(video_devdata(filp));
 
-	if (down_interruptible(&cam->dev_sem)) {
+	if (mutex_lock_interruptible(&cam->dev_mutex)) {
 		up_read(&et61x251_disconnect);
 		return -ERESTARTSYS;
 	}
@@ -1200,7 +1201,7 @@
 			err = -EWOULDBLOCK;
 			goto out;
 		}
-		up(&cam->dev_sem);
+		mutex_unlock(&cam->dev_mutex);
 		err = wait_event_interruptible_exclusive(cam->open,
 		                                  cam->state & DEV_DISCONNECTED
 		                                         || !cam->users);
@@ -1212,7 +1213,7 @@
 			up_read(&et61x251_disconnect);
 			return -ENODEV;
 		}
-		down(&cam->dev_sem);
+		mutex_lock(&cam->dev_mutex);
 	}
 
 
@@ -1240,7 +1241,7 @@
 	DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
 
 out:
-	up(&cam->dev_sem);
+	mutex_unlock(&cam->dev_mutex);
 	up_read(&et61x251_disconnect);
 	return err;
 }
@@ -1250,7 +1251,7 @@
 {
 	struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
 
-	down(&cam->dev_sem); /* prevent disconnect() to be called */
+	mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
 
 	et61x251_stop_transfer(cam);
 
@@ -1258,7 +1259,7 @@
 
 	if (cam->state & DEV_DISCONNECTED) {
 		et61x251_release_resources(cam);
-		up(&cam->dev_sem);
+		mutex_unlock(&cam->dev_mutex);
 		kfree(cam);
 		return 0;
 	}
@@ -1268,7 +1269,7 @@
 
 	DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
 
-	up(&cam->dev_sem);
+	mutex_unlock(&cam->dev_mutex);
 
 	return 0;
 }
@@ -1281,28 +1282,29 @@
 	struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
 	struct et61x251_frame_t* f, * i;
 	unsigned long lock_flags;
+	long timeout;
 	int err = 0;
 
-	if (down_interruptible(&cam->fileop_sem))
+	if (mutex_lock_interruptible(&cam->fileop_mutex))
 		return -ERESTARTSYS;
 
 	if (cam->state & DEV_DISCONNECTED) {
 		DBG(1, "Device not present");
-		up(&cam->fileop_sem);
+		mutex_unlock(&cam->fileop_mutex);
 		return -ENODEV;
 	}
 
 	if (cam->state & DEV_MISCONFIGURED) {
 		DBG(1, "The camera is misconfigured. Close and open it "
 		       "again.");
-		up(&cam->fileop_sem);
+		mutex_unlock(&cam->fileop_mutex);
 		return -EIO;
 	}
 
 	if (cam->io == IO_MMAP) {
 		DBG(3, "Close and open the device again to choose the read "
 		       "method");
-		up(&cam->fileop_sem);
+		mutex_unlock(&cam->fileop_mutex);
 		return -EINVAL;
 	}
 
@@ -1310,7 +1312,7 @@
 		if (!et61x251_request_buffers(cam, cam->nreadbuffers,
 		                              IO_READ)) {
 			DBG(1, "read() failed, not enough memory");
-			up(&cam->fileop_sem);
+			mutex_unlock(&cam->fileop_mutex);
 			return -ENOMEM;
 		}
 		cam->io = IO_READ;
@@ -1324,30 +1326,32 @@
 	}
 
 	if (!count) {
-		up(&cam->fileop_sem);
+		mutex_unlock(&cam->fileop_mutex);
 		return 0;
 	}
 
 	if (list_empty(&cam->outqueue)) {
 		if (filp->f_flags & O_NONBLOCK) {
-			up(&cam->fileop_sem);
+			mutex_unlock(&cam->fileop_mutex);
 			return -EAGAIN;
 		}
-		err = wait_event_interruptible
-		      ( cam->wait_frame,
-		        (!list_empty(&cam->outqueue)) ||
-		        (cam->state & DEV_DISCONNECTED) ||
-			(cam->state & DEV_MISCONFIGURED) );
-		if (err) {
-			up(&cam->fileop_sem);
-			return err;
+		timeout = wait_event_interruptible_timeout
+		          ( cam->wait_frame,
+		            (!list_empty(&cam->outqueue)) ||
+		            (cam->state & DEV_DISCONNECTED) ||
+		            (cam->state & DEV_MISCONFIGURED),
+		            cam->module_param.frame_timeout *
+		            1000 * msecs_to_jiffies(1) );
+		if (timeout < 0) {
+			mutex_unlock(&cam->fileop_mutex);
+			return timeout;
 		}
 		if (cam->state & DEV_DISCONNECTED) {
-			up(&cam->fileop_sem);
+			mutex_unlock(&cam->fileop_mutex);
 			return -ENODEV;
 		}
-		if (cam->state & DEV_MISCONFIGURED) {
-			up(&cam->fileop_sem);
+		if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
+			mutex_unlock(&cam->fileop_mutex);
 			return -EIO;
 		}
 	}
@@ -1375,7 +1379,7 @@
 	PDBGG("Frame #%lu, bytes read: %zu",
 	      (unsigned long)f->buf.index, count);
 
-	up(&cam->fileop_sem);
+	mutex_unlock(&cam->fileop_mutex);
 
 	return err ? err : count;
 }
@@ -1388,7 +1392,7 @@
 	unsigned long lock_flags;
 	unsigned int mask = 0;
 
-	if (down_interruptible(&cam->fileop_sem))
+	if (mutex_lock_interruptible(&cam->fileop_mutex))
 		return POLLERR;
 
 	if (cam->state & DEV_DISCONNECTED) {
@@ -1426,12 +1430,12 @@
 	if (!list_empty(&cam->outqueue))
 		mask |= POLLIN | POLLRDNORM;
 
-	up(&cam->fileop_sem);
+	mutex_unlock(&cam->fileop_mutex);
 
 	return mask;
 
 error:
-	up(&cam->fileop_sem);
+	mutex_unlock(&cam->fileop_mutex);
 	return POLLERR;
 }
 
@@ -1465,25 +1469,25 @@
 	void *pos;
 	u32 i;
 
-	if (down_interruptible(&cam->fileop_sem))
+	if (mutex_lock_interruptible(&cam->fileop_mutex))
 		return -ERESTARTSYS;
 
 	if (cam->state & DEV_DISCONNECTED) {
 		DBG(1, "Device not present");
-		up(&cam->fileop_sem);
+		mutex_unlock(&cam->fileop_mutex);
 		return -ENODEV;
 	}
 
 	if (cam->state & DEV_MISCONFIGURED) {
 		DBG(1, "The camera is misconfigured. Close and open it "
 		       "again.");
-		up(&cam->fileop_sem);
+		mutex_unlock(&cam->fileop_mutex);
 		return -EIO;
 	}
 
 	if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
 	    size != PAGE_ALIGN(cam->frame[0].buf.length)) {
-		up(&cam->fileop_sem);
+		mutex_unlock(&cam->fileop_mutex);
 		return -EINVAL;
 	}
 
@@ -1492,7 +1496,7 @@
 			break;
 	}
 	if (i == cam->nbuffers) {
-		up(&cam->fileop_sem);
+		mutex_unlock(&cam->fileop_mutex);
 		return -EINVAL;
 	}
 
@@ -1502,7 +1506,7 @@
 	pos = cam->frame[i].bufmem;
 	while (size > 0) { /* size is page-aligned */
 		if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
-			up(&cam->fileop_sem);
+			mutex_unlock(&cam->fileop_mutex);
 			return -EAGAIN;
 		}
 		start += PAGE_SIZE;
@@ -1515,7 +1519,7 @@
 
 	et61x251_vm_open(vma);
 
-	up(&cam->fileop_sem);
+	mutex_unlock(&cam->fileop_mutex);
 
 	return 0;
 }
@@ -1557,6 +1561,7 @@
 
 	memset(&i, 0, sizeof(i));
 	strcpy(i.name, "Camera");
+	i.type = V4L2_INPUT_TYPE_CAMERA;
 
 	if (copy_to_user(arg, &i, sizeof(i)))
 		return -EFAULT;
@@ -1566,7 +1571,19 @@
 
 
 static int
-et61x251_vidioc_gs_input(struct et61x251_device* cam, void __user * arg)
+et61x251_vidioc_g_input(struct et61x251_device* cam, void __user * arg)
+{
+	int index = 0;
+
+	if (copy_to_user(arg, &index, sizeof(index)))
+		return -EFAULT;
+
+	return 0;
+}
+
+
+static int
+et61x251_vidioc_s_input(struct et61x251_device* cam, void __user * arg)
 {
 	int index;
 
@@ -1583,7 +1600,7 @@
 static int
 et61x251_vidioc_query_ctrl(struct et61x251_device* cam, void __user * arg)
 {
-	struct et61x251_sensor* s = cam->sensor;
+	struct et61x251_sensor* s = &cam->sensor;
 	struct v4l2_queryctrl qc;
 	u8 i;
 
@@ -1605,7 +1622,7 @@
 static int
 et61x251_vidioc_g_ctrl(struct et61x251_device* cam, void __user * arg)
 {
-	struct et61x251_sensor* s = cam->sensor;
+	struct et61x251_sensor* s = &cam->sensor;
 	struct v4l2_control ctrl;
 	int err = 0;
 	u8 i;
@@ -1637,7 +1654,7 @@
 static int
 et61x251_vidioc_s_ctrl(struct et61x251_device* cam, void __user * arg)
 {
-	struct et61x251_sensor* s = cam->sensor;
+	struct et61x251_sensor* s = &cam->sensor;
 	struct v4l2_control ctrl;
 	u8 i;
 	int err = 0;
@@ -1650,6 +1667,8 @@
 
 	for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
 		if (ctrl.id == s->qctrl[i].id) {
+			if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
+				return -EINVAL;
 			if (ctrl.value < s->qctrl[i].minimum ||
 			    ctrl.value > s->qctrl[i].maximum)
 				return -ERANGE;
@@ -1669,7 +1688,7 @@
 static int
 et61x251_vidioc_cropcap(struct et61x251_device* cam, void __user * arg)
 {
-	struct v4l2_cropcap* cc = &(cam->sensor->cropcap);
+	struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
 
 	cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 	cc->pixelaspect.numerator = 1;
@@ -1685,7 +1704,7 @@
 static int
 et61x251_vidioc_g_crop(struct et61x251_device* cam, void __user * arg)
 {
-	struct et61x251_sensor* s = cam->sensor;
+	struct et61x251_sensor* s = &cam->sensor;
 	struct v4l2_crop crop = {
 		.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
 	};
@@ -1702,7 +1721,7 @@
 static int
 et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg)
 {
-	struct et61x251_sensor* s = cam->sensor;
+	struct et61x251_sensor* s = &cam->sensor;
 	struct v4l2_crop crop;
 	struct v4l2_rect* rect;
 	struct v4l2_rect* bounds = &(s->cropcap.bounds);
@@ -1843,7 +1862,7 @@
 et61x251_vidioc_g_fmt(struct et61x251_device* cam, void __user * arg)
 {
 	struct v4l2_format format;
-	struct v4l2_pix_format* pfmt = &(cam->sensor->pix_format);
+	struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
 
 	if (copy_from_user(&format, arg, sizeof(format)))
 		return -EFAULT;
@@ -1868,7 +1887,7 @@
 et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd,
                           void __user * arg)
 {
-	struct et61x251_sensor* s = cam->sensor;
+	struct et61x251_sensor* s = &cam->sensor;
 	struct v4l2_format format;
 	struct v4l2_pix_format* pix;
 	struct v4l2_pix_format* pfmt = &(s->pix_format);
@@ -2155,7 +2174,7 @@
 	struct v4l2_buffer b;
 	struct et61x251_frame_t *f;
 	unsigned long lock_flags;
-	int err = 0;
+	long timeout;
 
 	if (copy_from_user(&b, arg, sizeof(b)))
 		return -EFAULT;
@@ -2168,16 +2187,18 @@
 			return -EINVAL;
 		if (filp->f_flags & O_NONBLOCK)
 			return -EAGAIN;
-		err = wait_event_interruptible
-		      ( cam->wait_frame,
-		        (!list_empty(&cam->outqueue)) ||
-		        (cam->state & DEV_DISCONNECTED) ||
-		        (cam->state & DEV_MISCONFIGURED) );
-		if (err)
-			return err;
+		timeout = wait_event_interruptible_timeout
+		          ( cam->wait_frame,
+		            (!list_empty(&cam->outqueue)) ||
+		            (cam->state & DEV_DISCONNECTED) ||
+		            (cam->state & DEV_MISCONFIGURED),
+		            cam->module_param.frame_timeout *
+		            1000 * msecs_to_jiffies(1) );
+		if (timeout < 0)
+			return timeout;
 		if (cam->state & DEV_DISCONNECTED)
 			return -ENODEV;
-		if (cam->state & DEV_MISCONFIGURED)
+		if (!timeout || (cam->state & DEV_MISCONFIGURED))
 			return -EIO;
 	}
 
@@ -2309,8 +2330,10 @@
 		return et61x251_vidioc_enuminput(cam, arg);
 
 	case VIDIOC_G_INPUT:
+		return et61x251_vidioc_g_input(cam, arg);
+
 	case VIDIOC_S_INPUT:
-		return et61x251_vidioc_gs_input(cam, arg);
+		return et61x251_vidioc_s_input(cam, arg);
 
 	case VIDIOC_QUERYCTRL:
 		return et61x251_vidioc_query_ctrl(cam, arg);
@@ -2393,19 +2416,19 @@
 	struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
 	int err = 0;
 
-	if (down_interruptible(&cam->fileop_sem))
+	if (mutex_lock_interruptible(&cam->fileop_mutex))
 		return -ERESTARTSYS;
 
 	if (cam->state & DEV_DISCONNECTED) {
 		DBG(1, "Device not present");
-		up(&cam->fileop_sem);
+		mutex_unlock(&cam->fileop_mutex);
 		return -ENODEV;
 	}
 
 	if (cam->state & DEV_MISCONFIGURED) {
 		DBG(1, "The camera is misconfigured. Close and open it "
 		       "again.");
-		up(&cam->fileop_sem);
+		mutex_unlock(&cam->fileop_mutex);
 		return -EIO;
 	}
 
@@ -2413,7 +2436,7 @@
 
 	err = et61x251_ioctl_v4l2(inode, filp, cmd, (void __user *)arg);
 
-	up(&cam->fileop_sem);
+	mutex_unlock(&cam->fileop_mutex);
 
 	return err;
 }
@@ -2459,7 +2482,7 @@
 		goto fail;
 	}
 
-	init_MUTEX(&cam->dev_sem);
+	mutex_init(&cam->dev_mutex);
 
 	DBG(2, "ET61X[12]51 PC Camera Controller detected "
 	       "(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct);
@@ -2470,8 +2493,8 @@
 			break;
 	}
 
-	if (!err && cam->sensor)
-		DBG(2, "%s image sensor detected", cam->sensor->name);
+	if (!err)
+		DBG(2, "%s image sensor detected", cam->sensor.name);
 	else {
 		DBG(1, "No supported image sensor detected");
 		err = -ENODEV;
@@ -2492,7 +2515,7 @@
 	cam->v4ldev->release = video_device_release;
 	video_set_drvdata(cam->v4ldev, cam);
 
-	down(&cam->dev_sem);
+	mutex_lock(&cam->dev_mutex);
 
 	err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
 	                            video_nr[dev_nr]);
@@ -2502,13 +2525,14 @@
 			DBG(1, "Free /dev/videoX node not found");
 		video_nr[dev_nr] = -1;
 		dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
-		up(&cam->dev_sem);
+		mutex_unlock(&cam->dev_mutex);
 		goto fail;
 	}
 
 	DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
 
 	cam->module_param.force_munmap = force_munmap[dev_nr];
+	cam->module_param.frame_timeout = frame_timeout[dev_nr];
 
 	dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
 
@@ -2519,7 +2543,7 @@
 
 	usb_set_intfdata(intf, cam);
 
-	up(&cam->dev_sem);
+	mutex_unlock(&cam->dev_mutex);
 
 	return 0;
 
@@ -2543,7 +2567,7 @@
 
 	down_write(&et61x251_disconnect);
 
-	down(&cam->dev_sem);
+	mutex_lock(&cam->dev_mutex);
 
 	DBG(2, "Disconnecting %s...", cam->v4ldev->name);
 
@@ -2557,13 +2581,14 @@
 		et61x251_stop_transfer(cam);
 		cam->state |= DEV_DISCONNECTED;
 		wake_up_interruptible(&cam->wait_frame);
-		wake_up_interruptible(&cam->wait_stream);
+		wake_up(&cam->wait_stream);
+		usb_get_dev(cam->usbdev);
 	} else {
 		cam->state |= DEV_DISCONNECTED;
 		et61x251_release_resources(cam);
 	}
 
-	up(&cam->dev_sem);
+	mutex_unlock(&cam->dev_mutex);
 
 	if (!cam->users)
 		kfree(cam);
diff --git a/drivers/usb/media/et61x251_sensor.h b/drivers/usb/media/et61x251_sensor.h
index b9df910..56841ae 100644
--- a/drivers/usb/media/et61x251_sensor.h
+++ b/drivers/usb/media/et61x251_sensor.h
@@ -42,6 +42,9 @@
 	NULL,                                                                 \
 };
 
+extern struct et61x251_device*
+et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id);
+
 extern void
 et61x251_attach_sensor(struct et61x251_device* cam,
                        struct et61x251_sensor* sensor);
@@ -105,8 +108,6 @@
 	int (*set_pix_format)(struct et61x251_device* cam,
 	                      const struct v4l2_pix_format* pix);
 
-	const struct usb_device* usbdev;
-
 	/* Private */
 	struct v4l2_queryctrl _qctrl[ET61X251_MAX_CTRLS];
 	struct v4l2_rect _rect;
diff --git a/drivers/usb/media/et61x251_tas5130d1b.c b/drivers/usb/media/et61x251_tas5130d1b.c
index 65f1ae9..3998d76 100644
--- a/drivers/usb/media/et61x251_tas5130d1b.c
+++ b/drivers/usb/media/et61x251_tas5130d1b.c
@@ -126,12 +126,16 @@
 
 int et61x251_probe_tas5130d1b(struct et61x251_device* cam)
 {
-	/* This sensor has no identifiers, so let's attach it anyway */
-	et61x251_attach_sensor(cam, &tas5130d1b);
+	const struct usb_device_id tas5130d1b_id_table[] = {
+		{ USB_DEVICE(0x102c, 0x6251), },
+		{ }
+	};
 
 	/* Sensor detection is based on USB pid/vid */
-	if (le16_to_cpu(tas5130d1b.usbdev->descriptor.idProduct) != 0x6251)
+	if (!et61x251_match_id(cam, tas5130d1b_id_table))
 		return -ENODEV;
 
+	et61x251_attach_sensor(cam, &tas5130d1b);
+
 	return 0;
 }
diff --git a/drivers/usb/media/ov511.c b/drivers/usb/media/ov511.c
index 51e9cc0..da44579 100644
--- a/drivers/usb/media/ov511.c
+++ b/drivers/usb/media/ov511.c
@@ -365,14 +365,14 @@
 
 	PDEBUG(5, "0x%02X:0x%02X", reg, value);
 
-	down(&ov->cbuf_lock);
+	mutex_lock(&ov->cbuf_lock);
 	ov->cbuf[0] = value;
 	rc = usb_control_msg(ov->dev,
 			     usb_sndctrlpipe(ov->dev, 0),
 			     (ov->bclass == BCL_OV518)?1:2 /* REG_IO */,
 			     USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			     0, (__u16)reg, &ov->cbuf[0], 1, 1000);
-	up(&ov->cbuf_lock);
+	mutex_unlock(&ov->cbuf_lock);
 
 	if (rc < 0)
 		err("reg write: error %d: %s", rc, symbolic(urb_errlist, rc));
@@ -387,7 +387,7 @@
 {
 	int rc;
 
-	down(&ov->cbuf_lock);
+	mutex_lock(&ov->cbuf_lock);
 	rc = usb_control_msg(ov->dev,
 			     usb_rcvctrlpipe(ov->dev, 0),
 			     (ov->bclass == BCL_OV518)?1:3 /* REG_IO */,
@@ -401,7 +401,7 @@
 		PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]);
 	}
 
-	up(&ov->cbuf_lock);
+	mutex_unlock(&ov->cbuf_lock);
 
 	return rc;
 }
@@ -444,7 +444,7 @@
 
 	PDEBUG(5, "0x%02X:%7d, n=%d", reg, val, n);
 
-	down(&ov->cbuf_lock);
+	mutex_lock(&ov->cbuf_lock);
 
 	*((__le32 *)ov->cbuf) = __cpu_to_le32(val);
 
@@ -453,7 +453,7 @@
 			     1 /* REG_IO */,
 			     USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			     0, (__u16)reg, ov->cbuf, n, 1000);
-	up(&ov->cbuf_lock);
+	mutex_unlock(&ov->cbuf_lock);
 
 	if (rc < 0)
 		err("reg write multiple: error %d: %s", rc,
@@ -768,14 +768,14 @@
 {
 	int rc;
 
-	down(&ov->i2c_lock);
+	mutex_lock(&ov->i2c_lock);
 
 	if (ov->bclass == BCL_OV518)
 		rc = ov518_i2c_read_internal(ov, reg);
 	else
 		rc = ov511_i2c_read_internal(ov, reg);
 
-	up(&ov->i2c_lock);
+	mutex_unlock(&ov->i2c_lock);
 
 	return rc;
 }
@@ -785,14 +785,14 @@
 {
 	int rc;
 
-	down(&ov->i2c_lock);
+	mutex_lock(&ov->i2c_lock);
 
 	if (ov->bclass == BCL_OV518)
 		rc = ov518_i2c_write_internal(ov, reg, value);
 	else
 		rc = ov511_i2c_write_internal(ov, reg, value);
 
-	up(&ov->i2c_lock);
+	mutex_unlock(&ov->i2c_lock);
 
 	return rc;
 }
@@ -842,9 +842,9 @@
 {
 	int rc;
 
-	down(&ov->i2c_lock);
+	mutex_lock(&ov->i2c_lock);
 	rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask);
-	up(&ov->i2c_lock);
+	mutex_unlock(&ov->i2c_lock);
 
 	return rc;
 }
@@ -880,7 +880,7 @@
 {
 	int rc = 0;
 
-	down(&ov->i2c_lock);
+	mutex_lock(&ov->i2c_lock);
 
 	/* Set new slave IDs */
 	rc = i2c_set_slave_internal(ov, slave);
@@ -894,7 +894,7 @@
 	if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
 		err("Couldn't restore primary I2C slave");
 
-	up(&ov->i2c_lock);
+	mutex_unlock(&ov->i2c_lock);
 	return rc;
 }
 
@@ -906,7 +906,7 @@
 {
 	int rc;
 
-	down(&ov->i2c_lock);
+	mutex_lock(&ov->i2c_lock);
 
 	/* Set new slave IDs */
 	rc = i2c_set_slave_internal(ov, slave);
@@ -923,7 +923,7 @@
 	if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
 		err("Couldn't restore primary I2C slave");
 
-	up(&ov->i2c_lock);
+	mutex_unlock(&ov->i2c_lock);
 	return rc;
 }
 
@@ -933,7 +933,7 @@
 {
 	int rc;
 
-	down(&ov->i2c_lock);
+	mutex_lock(&ov->i2c_lock);
 
 	rc = i2c_set_slave_internal(ov, sid);
 	if (rc < 0)
@@ -942,7 +942,7 @@
 	// FIXME: Is this actually necessary?
 	rc = ov51x_reset(ov, OV511_RESET_NOREGS);
 out:
-	up(&ov->i2c_lock);
+	mutex_unlock(&ov->i2c_lock);
 	return rc;
 }
 
@@ -3832,7 +3832,7 @@
 	const int raw_bufsize = OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h);
 
 	PDEBUG(4, "entered");
-	down(&ov->buf_lock);
+	mutex_lock(&ov->buf_lock);
 
 	if (ov->buf_state == BUF_ALLOCATED)
 		goto out;
@@ -3879,12 +3879,12 @@
 
 	ov->buf_state = BUF_ALLOCATED;
 out:
-	up(&ov->buf_lock);
+	mutex_unlock(&ov->buf_lock);
 	PDEBUG(4, "leaving");
 	return 0;
 error:
 	ov51x_do_dealloc(ov);
-	up(&ov->buf_lock);
+	mutex_unlock(&ov->buf_lock);
 	PDEBUG(4, "errored");
 	return -ENOMEM;
 }
@@ -3893,9 +3893,9 @@
 ov51x_dealloc(struct usb_ov511 *ov)
 {
 	PDEBUG(4, "entered");
-	down(&ov->buf_lock);
+	mutex_lock(&ov->buf_lock);
 	ov51x_do_dealloc(ov);
-	up(&ov->buf_lock);
+	mutex_unlock(&ov->buf_lock);
 	PDEBUG(4, "leaving");
 }
 
@@ -3914,7 +3914,7 @@
 
 	PDEBUG(4, "opening");
 
-	down(&ov->lock);
+	mutex_lock(&ov->lock);
 
 	err = -EBUSY;
 	if (ov->user)
@@ -3958,7 +3958,7 @@
 		ov51x_led_control(ov, 1);
 
 out:
-	up(&ov->lock);
+	mutex_unlock(&ov->lock);
 	return err;
 }
 
@@ -3970,7 +3970,7 @@
 
 	PDEBUG(4, "ov511_close");
 
-	down(&ov->lock);
+	mutex_lock(&ov->lock);
 
 	ov->user--;
 	ov51x_stop_isoc(ov);
@@ -3981,15 +3981,15 @@
 	if (ov->dev)
 		ov51x_dealloc(ov);
 
-	up(&ov->lock);
+	mutex_unlock(&ov->lock);
 
 	/* Device unplugged while open. Only a minimum of unregistration is done
 	 * here; the disconnect callback already did the rest. */
 	if (!ov->dev) {
-		down(&ov->cbuf_lock);
+		mutex_lock(&ov->cbuf_lock);
 		kfree(ov->cbuf);
 		ov->cbuf = NULL;
-		up(&ov->cbuf_lock);
+		mutex_unlock(&ov->cbuf_lock);
 
 		ov51x_dealloc(ov);
 		kfree(ov);
@@ -4449,12 +4449,12 @@
 	struct usb_ov511 *ov = video_get_drvdata(vdev);
 	int rc;
 
-	if (down_interruptible(&ov->lock))
+	if (mutex_lock_interruptible(&ov->lock))
 		return -EINTR;
 
 	rc = video_usercopy(inode, file, cmd, arg, ov51x_v4l1_ioctl_internal);
 
-	up(&ov->lock);
+	mutex_unlock(&ov->lock);
 	return rc;
 }
 
@@ -4468,7 +4468,7 @@
 	int i, rc = 0, frmx = -1;
 	struct ov511_frame *frame;
 
-	if (down_interruptible(&ov->lock))
+	if (mutex_lock_interruptible(&ov->lock))
 		return -EINTR;
 
 	PDEBUG(4, "%ld bytes, noblock=%d", count, noblock);
@@ -4604,11 +4604,11 @@
 
 	PDEBUG(4, "read finished, returning %ld (sweet)", count);
 
-	up(&ov->lock);
+	mutex_unlock(&ov->lock);
 	return count;
 
 error:
-	up(&ov->lock);
+	mutex_unlock(&ov->lock);
 	return rc;
 }
 
@@ -4631,14 +4631,14 @@
 	              + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))))
 		return -EINVAL;
 
-	if (down_interruptible(&ov->lock))
+	if (mutex_lock_interruptible(&ov->lock))
 		return -EINTR;
 
 	pos = (unsigned long)ov->fbuf;
 	while (size > 0) {
 		page = vmalloc_to_pfn((void *)pos);
 		if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-			up(&ov->lock);
+			mutex_unlock(&ov->lock);
 			return -EAGAIN;
 		}
 		start += PAGE_SIZE;
@@ -4649,7 +4649,7 @@
 			size = 0;
 	}
 
-	up(&ov->lock);
+	mutex_unlock(&ov->lock);
 	return 0;
 }
 
@@ -5639,7 +5639,7 @@
 static ssize_t show_exposure(struct class_device *cd, char *buf)
 {
 	struct usb_ov511 *ov = cd_to_ov(cd);
-	unsigned char exp;
+	unsigned char exp = 0;
 
 	if (!ov->dev)
 		return -ENODEV;
@@ -5686,13 +5686,11 @@
 	if (idesc->bInterfaceSubClass != 0x00)
 		return -ENODEV;
 
-	if ((ov = kmalloc(sizeof(*ov), GFP_KERNEL)) == NULL) {
+	if ((ov = kzalloc(sizeof(*ov), GFP_KERNEL)) == NULL) {
 		err("couldn't kmalloc ov struct");
 		goto error_out;
 	}
 
-	memset(ov, 0, sizeof(*ov));
-
 	ov->dev = dev;
 	ov->iface = idesc->bInterfaceNumber;
 	ov->led_policy = led;
@@ -5738,11 +5736,10 @@
 
 	init_waitqueue_head(&ov->wq);
 
-	init_MUTEX(&ov->lock);	/* to 1 == available */
-	init_MUTEX(&ov->buf_lock);
-	init_MUTEX(&ov->param_lock);
-	init_MUTEX(&ov->i2c_lock);
-	init_MUTEX(&ov->cbuf_lock);
+	mutex_init(&ov->lock);	/* to 1 == available */
+	mutex_init(&ov->buf_lock);
+	mutex_init(&ov->i2c_lock);
+	mutex_init(&ov->cbuf_lock);
 
 	ov->buf_state = BUF_NOT_ALLOCATED;
 
@@ -5833,10 +5830,10 @@
 	}
 
 	if (ov->cbuf) {
-		down(&ov->cbuf_lock);
+		mutex_lock(&ov->cbuf_lock);
 		kfree(ov->cbuf);
 		ov->cbuf = NULL;
-		up(&ov->cbuf_lock);
+		mutex_unlock(&ov->cbuf_lock);
 	}
 
 	kfree(ov);
@@ -5881,10 +5878,10 @@
 
 	/* Free the memory */
 	if (ov && !ov->user) {
-		down(&ov->cbuf_lock);
+		mutex_lock(&ov->cbuf_lock);
 		kfree(ov->cbuf);
 		ov->cbuf = NULL;
-		up(&ov->cbuf_lock);
+		mutex_unlock(&ov->cbuf_lock);
 
 		ov51x_dealloc(ov);
 		kfree(ov);
diff --git a/drivers/usb/media/ov511.h b/drivers/usb/media/ov511.h
index 086509a..bce9b36 100644
--- a/drivers/usb/media/ov511.h
+++ b/drivers/usb/media/ov511.h
@@ -5,6 +5,7 @@
 #include <linux/videodev.h>
 #include <linux/smp_lock.h>
 #include <linux/usb.h>
+#include <linux/mutex.h>
 
 #define OV511_DEBUG	/* Turn on debug messages */
 
@@ -435,7 +436,7 @@
 
 	int led_policy;		/* LED: off|on|auto; OV511+ only */
 
-	struct semaphore lock;	/* Serializes user-accessible operations */
+	struct mutex lock;	/* Serializes user-accessible operations */
 	int user;		/* user count for exclusive use */
 
 	int streaming;		/* Are we streaming Isochronous? */
@@ -473,11 +474,9 @@
 	int packet_size;	/* Frame size per isoc desc */
 	int packet_numbering;	/* Is ISO frame numbering enabled? */
 
-	struct semaphore param_lock;	/* params lock for this camera */
-
 	/* Framebuffer/sbuf management */
 	int buf_state;
-	struct semaphore buf_lock;
+	struct mutex buf_lock;
 
 	struct ov51x_decomp_ops *decomp_ops;
 
@@ -494,12 +493,12 @@
 	int pal;		/* Device is designed for PAL resolution */
 
 	/* I2C interface */
-	struct semaphore i2c_lock;	  /* Protect I2C controller regs */
+	struct mutex i2c_lock;	  /* Protect I2C controller regs */
 	unsigned char primary_i2c_slave;  /* I2C write id of sensor */
 
 	/* Control transaction stuff */
 	unsigned char *cbuf;		/* Buffer for payload */
-	struct semaphore cbuf_lock;
+	struct mutex cbuf_lock;
 };
 
 /* Used to represent a list of values and their respective symbolic names */
diff --git a/drivers/usb/media/pwc/pwc-ctrl.c b/drivers/usb/media/pwc/pwc-ctrl.c
index 3ebb6e9..0398b81 100644
--- a/drivers/usb/media/pwc/pwc-ctrl.c
+++ b/drivers/usb/media/pwc/pwc-ctrl.c
@@ -41,7 +41,6 @@
 #include <asm/uaccess.h> 
 #endif
 #include <asm/errno.h>
-#include <linux/version.h>
  
 #include "pwc.h"
 #include "pwc-ioctl.h"
diff --git a/drivers/usb/media/pwc/pwc-if.c b/drivers/usb/media/pwc/pwc-if.c
index 4f9b0dc..90eb260 100644
--- a/drivers/usb/media/pwc/pwc-if.c
+++ b/drivers/usb/media/pwc/pwc-if.c
@@ -62,7 +62,6 @@
 #include <linux/poll.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
-#include <linux/version.h>
 #include <asm/io.h>
 
 #include "pwc.h"
@@ -827,13 +826,10 @@
 	/* Get the current alternate interface, adjust packet size */
 	if (!udev->actconfig)
 		return -EFAULT;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,5)
-	idesc = &udev->actconfig->interface[0]->altsetting[pdev->valternate];
-#else
+
 	intf = usb_ifnum_to_if(udev, 0);
 	if (intf)
 		idesc = usb_altnum_to_altsetting(intf, pdev->valternate);
-#endif
 		
 	if (!idesc)
 		return -EFAULT;
@@ -1871,12 +1867,11 @@
 		Info("Warning: more than 1 configuration available.\n");
 
 	/* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */
-	pdev = kmalloc(sizeof(struct pwc_device), GFP_KERNEL);
+	pdev = kzalloc(sizeof(struct pwc_device), GFP_KERNEL);
 	if (pdev == NULL) {
 		Err("Oops, could not allocate memory for pwc_device.\n");
 		return -ENOMEM;
 	}
-	memset(pdev, 0, sizeof(struct pwc_device));
 	pdev->type = type_id;
 	pdev->vsize = default_size;
 	pdev->vframes = default_fps;
diff --git a/drivers/usb/media/se401.c b/drivers/usb/media/se401.c
index 2ba56228..f03ea7f 100644
--- a/drivers/usb/media/se401.c
+++ b/drivers/usb/media/se401.c
@@ -1157,21 +1157,21 @@
 	unsigned long size  = vma->vm_end-vma->vm_start;
 	unsigned long page, pos;
 
-	down(&se401->lock);
+	mutex_lock(&se401->lock);
 
 	if (se401->dev == NULL) {
-		up(&se401->lock);
+		mutex_unlock(&se401->lock);
 		return -EIO;
 	}
 	if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) {
-		up(&se401->lock);
+		mutex_unlock(&se401->lock);
 		return -EINVAL;
 	}
 	pos = (unsigned long)se401->fbuf;
 	while (size > 0) {
 		page = vmalloc_to_pfn((void *)pos);
 		if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-			up(&se401->lock);
+			mutex_unlock(&se401->lock);
 			return -EAGAIN;
 		}
 		start += PAGE_SIZE;
@@ -1181,7 +1181,7 @@
 		else
 			size = 0;
 	}
-	up(&se401->lock);
+	mutex_unlock(&se401->lock);
 
         return 0;
 }
@@ -1345,13 +1345,11 @@
         /* We found one */
         info("SE401 camera found: %s", camera_name);
 
-        if ((se401 = kmalloc(sizeof(*se401), GFP_KERNEL)) == NULL) {
+        if ((se401 = kzalloc(sizeof(*se401), GFP_KERNEL)) == NULL) {
                 err("couldn't kmalloc se401 struct");
 		return -ENOMEM;
         }
 
-        memset(se401, 0, sizeof(*se401));
-
         se401->dev = dev;
         se401->iface = interface->bInterfaceNumber;
         se401->camera_name = camera_name;
@@ -1366,7 +1364,7 @@
 	memcpy(&se401->vdev, &se401_template, sizeof(se401_template));
 	memcpy(se401->vdev.name, se401->camera_name, strlen(se401->camera_name));
 	init_waitqueue_head(&se401->wq);
-	init_MUTEX(&se401->lock);
+	mutex_init(&se401->lock);
 	wmb();
 
 	if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
diff --git a/drivers/usb/media/se401.h b/drivers/usb/media/se401.h
index 2e5846f..e88a40d 100644
--- a/drivers/usb/media/se401.h
+++ b/drivers/usb/media/se401.h
@@ -5,6 +5,7 @@
 #include <asm/uaccess.h>
 #include <linux/videodev.h>
 #include <linux/smp_lock.h>
+#include <linux/mutex.h>
 
 #define se401_DEBUG	/* Turn on debug messages */
 
@@ -189,7 +190,7 @@
 	int maxframesize;
 	int cframesize;		/* current framesize */
 
-	struct semaphore lock;
+	struct mutex lock;
 	int user;		/* user count for exclusive use */
 	int removed;		/* device disconnected */
 
diff --git a/drivers/usb/media/sn9c102.h b/drivers/usb/media/sn9c102.h
index 17d60c1..1d70a62 100644
--- a/drivers/usb/media/sn9c102.h
+++ b/drivers/usb/media/sn9c102.h
@@ -33,7 +33,9 @@
 #include <linux/types.h>
 #include <linux/param.h>
 #include <linux/rwsem.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
+#include <linux/string.h>
+#include <linux/stddef.h>
 
 #include "sn9c102_sensor.h"
 
@@ -50,6 +52,7 @@
 #define SN9C102_ALTERNATE_SETTING 8
 #define SN9C102_URB_TIMEOUT       msecs_to_jiffies(2 * SN9C102_ISO_PACKETS)
 #define SN9C102_CTRL_TIMEOUT      300
+#define SN9C102_FRAME_TIMEOUT     2
 
 /*****************************************************************************/
 
@@ -107,16 +110,17 @@
 
 struct sn9c102_module_param {
 	u8 force_munmap;
+	u16 frame_timeout;
 };
 
-static DECLARE_MUTEX(sn9c102_sysfs_lock);
+static DEFINE_MUTEX(sn9c102_sysfs_lock);
 static DECLARE_RWSEM(sn9c102_disconnect);
 
 struct sn9c102_device {
 	struct video_device* v4ldev;
 
 	enum sn9c102_bridge bridge;
-	struct sn9c102_sensor* sensor;
+	struct sn9c102_sensor sensor;
 
 	struct usb_device* usbdev;
 	struct urb* urb[SN9C102_URBS];
@@ -141,19 +145,28 @@
 	enum sn9c102_dev_state state;
 	u8 users;
 
-	struct semaphore dev_sem, fileop_sem;
+	struct mutex dev_mutex, fileop_mutex;
 	spinlock_t queue_lock;
 	wait_queue_head_t open, wait_frame, wait_stream;
 };
 
 /*****************************************************************************/
 
+struct sn9c102_device*
+sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id)
+{
+	if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id))
+		return cam;
+
+	return NULL;
+}
+
+
 void
 sn9c102_attach_sensor(struct sn9c102_device* cam,
                       struct sn9c102_sensor* sensor)
 {
-	cam->sensor = sensor;
-	cam->sensor->usbdev = cam->usbdev;
+	memcpy(&cam->sensor, sensor, sizeof(struct sn9c102_sensor));
 }
 
 /*****************************************************************************/
@@ -196,7 +209,8 @@
 
 #undef PDBG
 #define PDBG(fmt, args...)                                                    \
-dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args)
+dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",                              \
+         __FUNCTION__, __LINE__ , ## args)
 
 #undef PDBGG
 #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
diff --git a/drivers/usb/media/sn9c102_core.c b/drivers/usb/media/sn9c102_core.c
index c81397e..4c6cc63 100644
--- a/drivers/usb/media/sn9c102_core.c
+++ b/drivers/usb/media/sn9c102_core.c
@@ -25,11 +25,9 @@
 #include <linux/moduleparam.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
-#include <linux/string.h>
 #include <linux/device.h>
 #include <linux/fs.h>
 #include <linux/delay.h>
-#include <linux/stddef.h>
 #include <linux/compiler.h>
 #include <linux/ioctl.h>
 #include <linux/poll.h>
@@ -49,8 +47,8 @@
 #define SN9C102_MODULE_AUTHOR   "(C) 2004-2006 Luca Risolia"
 #define SN9C102_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
 #define SN9C102_MODULE_LICENSE  "GPL"
-#define SN9C102_MODULE_VERSION  "1:1.26"
-#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 26)
+#define SN9C102_MODULE_VERSION  "1:1.27"
+#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 27)
 
 /*****************************************************************************/
 
@@ -89,6 +87,15 @@
                  "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
                  "\n");
 
+static unsigned int frame_timeout[] = {[0 ... SN9C102_MAX_DEVICES-1] =
+                                       SN9C102_FRAME_TIMEOUT};
+module_param_array(frame_timeout, uint, NULL, 0644);
+MODULE_PARM_DESC(frame_timeout,
+                 "\n<n[,...]> Timeout for a video frame in seconds."
+                 "\nThis parameter is specific for each detected camera."
+                 "\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"."
+                 "\n");
+
 #ifdef SN9C102_DEBUG
 static unsigned short debug = SN9C102_DEBUG_LEVEL;
 module_param(debug, ushort, 0644);
@@ -128,8 +135,8 @@
 sn9c102_request_buffers(struct sn9c102_device* cam, u32 count, 
                         enum sn9c102_io_method io)
 {
-	struct v4l2_pix_format* p = &(cam->sensor->pix_format);
-	struct v4l2_rect* r = &(cam->sensor->cropcap.bounds);
+	struct v4l2_pix_format* p = &(cam->sensor.pix_format);
+	struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
 	const size_t imagesize = cam->module_param.force_munmap ||
 	                         io == IO_READ ?
 	                         (p->width * p->height * p->priv) / 8 :
@@ -449,19 +456,13 @@
 
 int sn9c102_i2c_read(struct sn9c102_device* cam, u8 address)
 {
-	if (!cam->sensor)
-		return -1;
-
-	return sn9c102_i2c_try_read(cam, cam->sensor, address);
+	return sn9c102_i2c_try_read(cam, &cam->sensor, address);
 }
 
 
 int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value)
 {
-	if (!cam->sensor)
-		return -1;
-
-	return sn9c102_i2c_try_write(cam, cam->sensor, address, value);
+	return sn9c102_i2c_try_write(cam, &cam->sensor, address, value);
 }
 
 /*****************************************************************************/
@@ -505,7 +506,7 @@
 	size_t eoflen = sizeof(sn9c102_eof_header_t), i;
 	unsigned j, n = sizeof(sn9c102_eof_header) / eoflen;
 
-	if (cam->sensor->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
+	if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
 		return NULL; /* EOF header does not exist in compressed data */
 
 	for (i = 0; (len >= eoflen) && (i <= len - eoflen); i++)
@@ -535,7 +536,7 @@
 		if ((*f))
 			(*f)->state = F_QUEUED;
 		DBG(3, "Stream interrupted");
-		wake_up_interruptible(&cam->wait_stream);
+		wake_up(&cam->wait_stream);
 	}
 
 	if (cam->state & DEV_DISCONNECTED)
@@ -553,9 +554,9 @@
 		(*f) = list_entry(cam->inqueue.next, struct sn9c102_frame_t,
 		                  frame);
 
-	imagesize = (cam->sensor->pix_format.width *
-	             cam->sensor->pix_format.height *
-	             cam->sensor->pix_format.priv) / 8;
+	imagesize = (cam->sensor.pix_format.width *
+	             cam->sensor.pix_format.height *
+	             cam->sensor.pix_format.priv) / 8;
 
 	soflen = (cam->bridge) == BRIDGE_SN9C103 ?
 	                          sizeof(sn9c103_sof_header_t) :
@@ -579,7 +580,7 @@
 
 redo:
 		sof = sn9c102_find_sof_header(cam, pos, len);
-		if (!sof) {
+		if (likely(!sof)) {
 			eof = sn9c102_find_eof_header(cam, pos, len);
 			if ((*f)->state == F_GRABBING) {
 end_of_frame:
@@ -589,8 +590,9 @@
 					img = (eof > pos) ? eof - pos - 1 : 0;
 
 				if ((*f)->buf.bytesused+img > imagesize) {
-					u32 b = (*f)->buf.bytesused + img -
-					        imagesize;
+					u32 b;
+					b = (*f)->buf.bytesused + img -
+					    imagesize;
 					img = imagesize - (*f)->buf.bytesused;
 					DBG(3, "Expected EOF not found: "
 					       "video frame cut");
@@ -608,9 +610,10 @@
 				(*f)->buf.bytesused += img;
 
 				if ((*f)->buf.bytesused == imagesize ||
-				    (cam->sensor->pix_format.pixelformat ==
+				    (cam->sensor.pix_format.pixelformat ==
 				                V4L2_PIX_FMT_SN9C10X && eof)) {
-					u32 b = (*f)->buf.bytesused;
+					u32 b;
+					b = (*f)->buf.bytesused;
 					(*f)->state = F_DONE;
 					(*f)->buf.sequence= ++cam->frame_count;
 					spin_lock(&cam->queue_lock);
@@ -667,7 +670,7 @@
 			if (eof && eof < sof)
 				goto end_of_frame; /* (1) */
 			else {
-				if (cam->sensor->pix_format.pixelformat ==
+				if (cam->sensor.pix_format.pixelformat ==
 				    V4L2_PIX_FMT_SN9C10X) {
 					eof = sof - soflen;
 					goto end_of_frame;
@@ -808,20 +811,21 @@
 
 static int sn9c102_stream_interrupt(struct sn9c102_device* cam)
 {
-	int err = 0;
+	long timeout;
 
 	cam->stream = STREAM_INTERRUPT;
-	err = wait_event_timeout(cam->wait_stream,
-	                         (cam->stream == STREAM_OFF) ||
-	                         (cam->state & DEV_DISCONNECTED),
-	                         SN9C102_URB_TIMEOUT);
+	timeout = wait_event_timeout(cam->wait_stream,
+	                             (cam->stream == STREAM_OFF) ||
+	                             (cam->state & DEV_DISCONNECTED),
+	                             SN9C102_URB_TIMEOUT);
 	if (cam->state & DEV_DISCONNECTED)
 		return -ENODEV;
-	else if (err) {
+	else if (cam->stream != STREAM_OFF) {
 		cam->state |= DEV_MISCONFIGURED;
-		DBG(1, "The camera is misconfigured. To use it, close and "
-		       "open /dev/video%d again.", cam->v4ldev->minor);
-		return err;
+		DBG(1, "URB timeout reached. The camera is misconfigured. "
+		       "To use it, close and open /dev/video%d again.",
+		    cam->v4ldev->minor);
+		return -EIO;
 	}
 
 	return 0;
@@ -866,18 +870,18 @@
 	struct sn9c102_device* cam;
 	ssize_t count;
 
-	if (down_interruptible(&sn9c102_sysfs_lock))
+	if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
 		return -ERESTARTSYS;
 
 	cam = video_get_drvdata(to_video_device(cd));
 	if (!cam) {
-		up(&sn9c102_sysfs_lock);
+		mutex_unlock(&sn9c102_sysfs_lock);
 		return -ENODEV;
 	}
 
 	count = sprintf(buf, "%u\n", cam->sysfs.reg);
 
-	up(&sn9c102_sysfs_lock);
+	mutex_unlock(&sn9c102_sysfs_lock);
 
 	return count;
 } 
@@ -890,18 +894,18 @@
 	u8 index;
 	ssize_t count;
 
-	if (down_interruptible(&sn9c102_sysfs_lock))
+	if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
 		return -ERESTARTSYS;
 
 	cam = video_get_drvdata(to_video_device(cd));
 	if (!cam) {
-		up(&sn9c102_sysfs_lock);
+		mutex_unlock(&sn9c102_sysfs_lock);
 		return -ENODEV;
 	}
 
 	index = sn9c102_strtou8(buf, len, &count);
 	if (index > 0x1f || !count) {
-		up(&sn9c102_sysfs_lock);
+		mutex_unlock(&sn9c102_sysfs_lock);
 		return -EINVAL;
 	}
 
@@ -910,7 +914,7 @@
 	DBG(2, "Moved SN9C10X register index to 0x%02X", cam->sysfs.reg);
 	DBG(3, "Written bytes: %zd", count);
 
-	up(&sn9c102_sysfs_lock);
+	mutex_unlock(&sn9c102_sysfs_lock);
 
 	return count;
 }
@@ -922,17 +926,17 @@
 	ssize_t count;
 	int val;
 
-	if (down_interruptible(&sn9c102_sysfs_lock))
+	if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
 		return -ERESTARTSYS;
 
 	cam = video_get_drvdata(to_video_device(cd));
 	if (!cam) {
-		up(&sn9c102_sysfs_lock);
+		mutex_unlock(&sn9c102_sysfs_lock);
 		return -ENODEV;
 	}
 
 	if ((val = sn9c102_read_reg(cam, cam->sysfs.reg)) < 0) {
-		up(&sn9c102_sysfs_lock);
+		mutex_unlock(&sn9c102_sysfs_lock);
 		return -EIO;
 	}
 
@@ -940,7 +944,7 @@
 
 	DBG(3, "Read bytes: %zd", count);
 
-	up(&sn9c102_sysfs_lock);
+	mutex_unlock(&sn9c102_sysfs_lock);
 
 	return count;
 } 
@@ -954,24 +958,24 @@
 	ssize_t count;
 	int err;
 
-	if (down_interruptible(&sn9c102_sysfs_lock))
+	if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
 		return -ERESTARTSYS;
 
 	cam = video_get_drvdata(to_video_device(cd));
 	if (!cam) {
-		up(&sn9c102_sysfs_lock);
+		mutex_unlock(&sn9c102_sysfs_lock);
 		return -ENODEV;
 	}
 
 	value = sn9c102_strtou8(buf, len, &count);
 	if (!count) {
-		up(&sn9c102_sysfs_lock);
+		mutex_unlock(&sn9c102_sysfs_lock);
 		return -EINVAL;
 	}
 
 	err = sn9c102_write_reg(cam, value, cam->sysfs.reg);
 	if (err) {
-		up(&sn9c102_sysfs_lock);
+		mutex_unlock(&sn9c102_sysfs_lock);
 		return -EIO;
 	}
 
@@ -979,7 +983,7 @@
 	    cam->sysfs.reg, value);
 	DBG(3, "Written bytes: %zd", count);
 
-	up(&sn9c102_sysfs_lock);
+	mutex_unlock(&sn9c102_sysfs_lock);
 
 	return count;
 }
@@ -990,12 +994,12 @@
 	struct sn9c102_device* cam;
 	ssize_t count;
 
-	if (down_interruptible(&sn9c102_sysfs_lock))
+	if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
 		return -ERESTARTSYS;
 
 	cam = video_get_drvdata(to_video_device(cd));
 	if (!cam) {
-		up(&sn9c102_sysfs_lock);
+		mutex_unlock(&sn9c102_sysfs_lock);
 		return -ENODEV;
 	}
 
@@ -1003,7 +1007,7 @@
 
 	DBG(3, "Read bytes: %zd", count);
 
-	up(&sn9c102_sysfs_lock);
+	mutex_unlock(&sn9c102_sysfs_lock);
 
 	return count;
 }
@@ -1016,18 +1020,18 @@
 	u8 index;
 	ssize_t count;
 
-	if (down_interruptible(&sn9c102_sysfs_lock))
+	if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
 		return -ERESTARTSYS;
 
 	cam = video_get_drvdata(to_video_device(cd));
 	if (!cam) {
-		up(&sn9c102_sysfs_lock);
+		mutex_unlock(&sn9c102_sysfs_lock);
 		return -ENODEV;
 	}
 
 	index = sn9c102_strtou8(buf, len, &count);
 	if (!count) {
-		up(&sn9c102_sysfs_lock);
+		mutex_unlock(&sn9c102_sysfs_lock);
 		return -EINVAL;
 	}
 
@@ -1036,7 +1040,7 @@
 	DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg);
 	DBG(3, "Written bytes: %zd", count);
 
-	up(&sn9c102_sysfs_lock);
+	mutex_unlock(&sn9c102_sysfs_lock);
 
 	return count;
 }
@@ -1048,22 +1052,22 @@
 	ssize_t count;
 	int val;
 
-	if (down_interruptible(&sn9c102_sysfs_lock))
+	if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
 		return -ERESTARTSYS;
 
 	cam = video_get_drvdata(to_video_device(cd));
 	if (!cam) {
-		up(&sn9c102_sysfs_lock);
+		mutex_unlock(&sn9c102_sysfs_lock);
 		return -ENODEV;
 	}
 
-	if (!(cam->sensor->sysfs_ops & SN9C102_I2C_READ)) {
-		up(&sn9c102_sysfs_lock);
+	if (!(cam->sensor.sysfs_ops & SN9C102_I2C_READ)) {
+		mutex_unlock(&sn9c102_sysfs_lock);
 		return -ENOSYS;
 	}
 
 	if ((val = sn9c102_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) {
-		up(&sn9c102_sysfs_lock);
+		mutex_unlock(&sn9c102_sysfs_lock);
 		return -EIO;
 	}
 
@@ -1071,7 +1075,7 @@
 
 	DBG(3, "Read bytes: %zd", count);
 
-	up(&sn9c102_sysfs_lock);
+	mutex_unlock(&sn9c102_sysfs_lock);
 
 	return count;
 } 
@@ -1085,29 +1089,29 @@
 	ssize_t count;
 	int err;
 
-	if (down_interruptible(&sn9c102_sysfs_lock))
+	if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
 		return -ERESTARTSYS;
 
 	cam = video_get_drvdata(to_video_device(cd));
 	if (!cam) {
-		up(&sn9c102_sysfs_lock);
+		mutex_unlock(&sn9c102_sysfs_lock);
 		return -ENODEV;
 	}
 
-	if (!(cam->sensor->sysfs_ops & SN9C102_I2C_WRITE)) {
-		up(&sn9c102_sysfs_lock);
+	if (!(cam->sensor.sysfs_ops & SN9C102_I2C_WRITE)) {
+		mutex_unlock(&sn9c102_sysfs_lock);
 		return -ENOSYS;
 	}
 
 	value = sn9c102_strtou8(buf, len, &count);
 	if (!count) {
-		up(&sn9c102_sysfs_lock);
+		mutex_unlock(&sn9c102_sysfs_lock);
 		return -EINVAL;
 	}
 
 	err = sn9c102_i2c_write(cam, cam->sysfs.i2c_reg, value);
 	if (err) {
-		up(&sn9c102_sysfs_lock);
+		mutex_unlock(&sn9c102_sysfs_lock);
 		return -EIO;
 	}
 
@@ -1115,7 +1119,7 @@
 	    cam->sysfs.i2c_reg, value);
 	DBG(3, "Written bytes: %zd", count);
 
-	up(&sn9c102_sysfs_lock);
+	mutex_unlock(&sn9c102_sysfs_lock);
 
 	return count;
 }
@@ -1130,18 +1134,18 @@
 	u8 value;
 	ssize_t count;
 
-	if (down_interruptible(&sn9c102_sysfs_lock))
+	if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
 		return -ERESTARTSYS;
 
 	cam = video_get_drvdata(to_video_device(cd));
 	if (!cam) {
-		up(&sn9c102_sysfs_lock);
+		mutex_unlock(&sn9c102_sysfs_lock);
 		return -ENODEV;
 	}
 
 	bridge = cam->bridge;
 
-	up(&sn9c102_sysfs_lock);
+	mutex_unlock(&sn9c102_sysfs_lock);
 
 	value = sn9c102_strtou8(buf, len, &count);
 	if (!count)
@@ -1249,7 +1253,7 @@
 		video_device_create_file(v4ldev, &class_device_attr_blue);
 		video_device_create_file(v4ldev, &class_device_attr_red);
 	}
-	if (cam->sensor && cam->sensor->sysfs_ops) {
+	if (cam->sensor.sysfs_ops) {
 		video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
 		video_device_create_file(v4ldev, &class_device_attr_i2c_val);
 	}
@@ -1312,7 +1316,7 @@
 
 static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect)
 {
-	struct sn9c102_sensor* s = cam->sensor;
+	struct sn9c102_sensor* s = &cam->sensor;
 	u8 h_start = (u8)(rect->left - s->cropcap.bounds.left),
 	   v_start = (u8)(rect->top - s->cropcap.bounds.top),
 	   h_size = (u8)(rect->width / 16),
@@ -1335,7 +1339,7 @@
 
 static int sn9c102_init(struct sn9c102_device* cam)
 {
-	struct sn9c102_sensor* s = cam->sensor;
+	struct sn9c102_sensor* s = &cam->sensor;
 	struct v4l2_control ctrl;
 	struct v4l2_queryctrl *qctrl;
 	struct v4l2_rect* rect;
@@ -1404,7 +1408,7 @@
 	}
 
 	if (!(cam->state & DEV_INITIALIZED)) {
-		init_MUTEX(&cam->fileop_sem);
+		mutex_init(&cam->fileop_mutex);
 		spin_lock_init(&cam->queue_lock);
 		init_waitqueue_head(&cam->wait_frame);
 		init_waitqueue_head(&cam->wait_stream);
@@ -1422,13 +1426,15 @@
 
 static void sn9c102_release_resources(struct sn9c102_device* cam)
 {
-	down(&sn9c102_sysfs_lock);
+	mutex_lock(&sn9c102_sysfs_lock);
 
 	DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
 	video_set_drvdata(cam->v4ldev, NULL);
 	video_unregister_device(cam->v4ldev);
 
-	up(&sn9c102_sysfs_lock);
+	usb_put_dev(cam->usbdev);
+
+	mutex_unlock(&sn9c102_sysfs_lock);
 
 	kfree(cam->control_buffer);
 }
@@ -1449,7 +1455,7 @@
 
 	cam = video_get_drvdata(video_devdata(filp));
 
-	if (down_interruptible(&cam->dev_sem)) {
+	if (mutex_lock_interruptible(&cam->dev_mutex)) {
 		up_read(&sn9c102_disconnect);
 		return -ERESTARTSYS;
 	}
@@ -1461,7 +1467,7 @@
 			err = -EWOULDBLOCK;
 			goto out;
 		}
-		up(&cam->dev_sem);
+		mutex_unlock(&cam->dev_mutex);
 		err = wait_event_interruptible_exclusive(cam->open,
 		                                  cam->state & DEV_DISCONNECTED
 		                                         || !cam->users);
@@ -1473,7 +1479,7 @@
 			up_read(&sn9c102_disconnect);
 			return -ENODEV;
 		}
-		down(&cam->dev_sem);
+		mutex_lock(&cam->dev_mutex);
 	}
 
 
@@ -1501,7 +1507,7 @@
 	DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
 
 out:
-	up(&cam->dev_sem);
+	mutex_unlock(&cam->dev_mutex);
 	up_read(&sn9c102_disconnect);
 	return err;
 }
@@ -1511,7 +1517,7 @@
 {
 	struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
 
-	down(&cam->dev_sem); /* prevent disconnect() to be called */
+	mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
 
 	sn9c102_stop_transfer(cam);
 
@@ -1519,7 +1525,7 @@
 
 	if (cam->state & DEV_DISCONNECTED) {
 		sn9c102_release_resources(cam);
-		up(&cam->dev_sem);
+		mutex_unlock(&cam->dev_mutex);
 		kfree(cam);
 		return 0;
 	}
@@ -1529,7 +1535,7 @@
 
 	DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
 
-	up(&cam->dev_sem);
+	mutex_unlock(&cam->dev_mutex);
 
 	return 0;
 }
@@ -1541,35 +1547,36 @@
 	struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
 	struct sn9c102_frame_t* f, * i;
 	unsigned long lock_flags;
+	long timeout;
 	int err = 0;
 
-	if (down_interruptible(&cam->fileop_sem))
+	if (mutex_lock_interruptible(&cam->fileop_mutex))
 		return -ERESTARTSYS;
 
 	if (cam->state & DEV_DISCONNECTED) {
 		DBG(1, "Device not present");
-		up(&cam->fileop_sem);
+		mutex_unlock(&cam->fileop_mutex);
 		return -ENODEV;
 	}
 
 	if (cam->state & DEV_MISCONFIGURED) {
 		DBG(1, "The camera is misconfigured. Close and open it "
 		       "again.");
-		up(&cam->fileop_sem);
+		mutex_unlock(&cam->fileop_mutex);
 		return -EIO;
 	}
 
 	if (cam->io == IO_MMAP) {
 		DBG(3, "Close and open the device again to choose "
 		       "the read method");
-		up(&cam->fileop_sem);
+		mutex_unlock(&cam->fileop_mutex);
 		return -EINVAL;
 	}
 
 	if (cam->io == IO_NONE) {
 		if (!sn9c102_request_buffers(cam,cam->nreadbuffers, IO_READ)) {
 			DBG(1, "read() failed, not enough memory");
-			up(&cam->fileop_sem);
+			mutex_unlock(&cam->fileop_mutex);
 			return -ENOMEM;
 		}
 		cam->io = IO_READ;
@@ -1583,30 +1590,32 @@
 	}
 
 	if (!count) {
-		up(&cam->fileop_sem);
+		mutex_unlock(&cam->fileop_mutex);
 		return 0;
 	}
 
 	if (list_empty(&cam->outqueue)) {
 		if (filp->f_flags & O_NONBLOCK) {
-			up(&cam->fileop_sem);
+			mutex_unlock(&cam->fileop_mutex);
 			return -EAGAIN;
 		}
-		err = wait_event_interruptible
-		      ( cam->wait_frame, 
-		        (!list_empty(&cam->outqueue)) ||
-		        (cam->state & DEV_DISCONNECTED) ||
-			(cam->state & DEV_MISCONFIGURED) );
-		if (err) {
-			up(&cam->fileop_sem);
-			return err;
+		timeout = wait_event_interruptible_timeout
+		          ( cam->wait_frame,
+		            (!list_empty(&cam->outqueue)) ||
+		            (cam->state & DEV_DISCONNECTED) ||
+		            (cam->state & DEV_MISCONFIGURED),
+		            cam->module_param.frame_timeout *
+		            1000 * msecs_to_jiffies(1) );
+		if (timeout < 0) {
+			mutex_unlock(&cam->fileop_mutex);
+			return timeout;
 		}
 		if (cam->state & DEV_DISCONNECTED) {
-			up(&cam->fileop_sem);
+			mutex_unlock(&cam->fileop_mutex);
 			return -ENODEV;
 		}
-		if (cam->state & DEV_MISCONFIGURED) {
-			up(&cam->fileop_sem);
+		if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
+			mutex_unlock(&cam->fileop_mutex);
 			return -EIO;
 		}
 	}
@@ -1634,7 +1643,7 @@
 	PDBGG("Frame #%lu, bytes read: %zu",
 	      (unsigned long)f->buf.index, count);
 
-	up(&cam->fileop_sem);
+	mutex_unlock(&cam->fileop_mutex);
 
 	return count;
 }
@@ -1647,7 +1656,7 @@
 	unsigned long lock_flags;
 	unsigned int mask = 0;
 
-	if (down_interruptible(&cam->fileop_sem))
+	if (mutex_lock_interruptible(&cam->fileop_mutex))
 		return POLLERR;
 
 	if (cam->state & DEV_DISCONNECTED) {
@@ -1685,12 +1694,12 @@
 	if (!list_empty(&cam->outqueue))
 		mask |= POLLIN | POLLRDNORM;
 
-	up(&cam->fileop_sem);
+	mutex_unlock(&cam->fileop_mutex);
 
 	return mask;
 
 error:
-	up(&cam->fileop_sem);
+	mutex_unlock(&cam->fileop_mutex);
 	return POLLERR;
 }
 
@@ -1724,25 +1733,25 @@
 	void *pos;
 	u32 i;
 
-	if (down_interruptible(&cam->fileop_sem))
+	if (mutex_lock_interruptible(&cam->fileop_mutex))
 		return -ERESTARTSYS;
 
 	if (cam->state & DEV_DISCONNECTED) {
 		DBG(1, "Device not present");
-		up(&cam->fileop_sem);
+		mutex_unlock(&cam->fileop_mutex);
 		return -ENODEV;
 	}
 
 	if (cam->state & DEV_MISCONFIGURED) {
 		DBG(1, "The camera is misconfigured. Close and open it "
 		       "again.");
-		up(&cam->fileop_sem);
+		mutex_unlock(&cam->fileop_mutex);
 		return -EIO;
 	}
 
 	if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
 	    size != PAGE_ALIGN(cam->frame[0].buf.length)) {
-		up(&cam->fileop_sem);
+		mutex_unlock(&cam->fileop_mutex);
 		return -EINVAL;
 	}
 
@@ -1751,7 +1760,7 @@
 			break;
 	}
 	if (i == cam->nbuffers) {
-		up(&cam->fileop_sem);
+		mutex_unlock(&cam->fileop_mutex);
 		return -EINVAL;
 	}
 
@@ -1761,7 +1770,7 @@
 	pos = cam->frame[i].bufmem;
 	while (size > 0) { /* size is page-aligned */
 		if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
-			up(&cam->fileop_sem);
+			mutex_unlock(&cam->fileop_mutex);
 			return -EAGAIN;
 		}
 		start += PAGE_SIZE;
@@ -1774,7 +1783,7 @@
 
 	sn9c102_vm_open(vma);
 
-	up(&cam->fileop_sem);
+	mutex_unlock(&cam->fileop_mutex);
 
 	return 0;
 }
@@ -1816,6 +1825,7 @@
 
 	memset(&i, 0, sizeof(i));
 	strcpy(i.name, "Camera");
+	i.type = V4L2_INPUT_TYPE_CAMERA;
 
 	if (copy_to_user(arg, &i, sizeof(i)))
 		return -EFAULT;
@@ -1825,7 +1835,19 @@
 
 
 static int
-sn9c102_vidioc_gs_input(struct sn9c102_device* cam, void __user * arg)
+sn9c102_vidioc_g_input(struct sn9c102_device* cam, void __user * arg)
+{
+	int index = 0;
+
+	if (copy_to_user(arg, &index, sizeof(index)))
+		return -EFAULT;
+
+	return 0;
+}
+
+
+static int
+sn9c102_vidioc_s_input(struct sn9c102_device* cam, void __user * arg)
 {
 	int index;
 
@@ -1842,7 +1864,7 @@
 static int
 sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg)
 {
-	struct sn9c102_sensor* s = cam->sensor;
+	struct sn9c102_sensor* s = &cam->sensor;
 	struct v4l2_queryctrl qc;
 	u8 i;
 
@@ -1864,7 +1886,7 @@
 static int
 sn9c102_vidioc_g_ctrl(struct sn9c102_device* cam, void __user * arg)
 {
-	struct sn9c102_sensor* s = cam->sensor;
+	struct sn9c102_sensor* s = &cam->sensor;
 	struct v4l2_control ctrl;
 	int err = 0;
 	u8 i;
@@ -1896,7 +1918,7 @@
 static int
 sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg)
 {
-	struct sn9c102_sensor* s = cam->sensor;
+	struct sn9c102_sensor* s = &cam->sensor;
 	struct v4l2_control ctrl;
 	u8 i;
 	int err = 0;
@@ -1909,6 +1931,8 @@
 
 	for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
 		if (ctrl.id == s->qctrl[i].id) {
+			if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
+				return -EINVAL;
 			if (ctrl.value < s->qctrl[i].minimum ||
 			    ctrl.value > s->qctrl[i].maximum)
 				return -ERANGE;
@@ -1931,7 +1955,7 @@
 static int
 sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg)
 {
-	struct v4l2_cropcap* cc = &(cam->sensor->cropcap);
+	struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
 
 	cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 	cc->pixelaspect.numerator = 1;
@@ -1947,7 +1971,7 @@
 static int
 sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg)
 {
-	struct sn9c102_sensor* s = cam->sensor;
+	struct sn9c102_sensor* s = &cam->sensor;
 	struct v4l2_crop crop = {
 		.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
 	};
@@ -1964,7 +1988,7 @@
 static int
 sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg)
 {
-	struct sn9c102_sensor* s = cam->sensor;
+	struct sn9c102_sensor* s = &cam->sensor;
 	struct v4l2_crop crop;
 	struct v4l2_rect* rect;
 	struct v4l2_rect* bounds = &(s->cropcap.bounds);
@@ -2105,7 +2129,7 @@
 sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg)
 {
 	struct v4l2_format format;
-	struct v4l2_pix_format* pfmt = &(cam->sensor->pix_format);
+	struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
 
 	if (copy_from_user(&format, arg, sizeof(format)))
 		return -EFAULT;
@@ -2130,7 +2154,7 @@
 sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
                          void __user * arg)
 {
-	struct sn9c102_sensor* s = cam->sensor;
+	struct sn9c102_sensor* s = &cam->sensor;
 	struct v4l2_format format;
 	struct v4l2_pix_format* pix;
 	struct v4l2_pix_format* pfmt = &(s->pix_format);
@@ -2417,7 +2441,7 @@
 	struct v4l2_buffer b;
 	struct sn9c102_frame_t *f;
 	unsigned long lock_flags;
-	int err = 0;
+	long timeout;
 
 	if (copy_from_user(&b, arg, sizeof(b)))
 		return -EFAULT;
@@ -2430,16 +2454,18 @@
 			return -EINVAL;
 		if (filp->f_flags & O_NONBLOCK)
 			return -EAGAIN;
-		err = wait_event_interruptible
-		      ( cam->wait_frame,
-		        (!list_empty(&cam->outqueue)) ||
-		        (cam->state & DEV_DISCONNECTED) ||
-		        (cam->state & DEV_MISCONFIGURED) );
-		if (err)
-			return err;
+		timeout = wait_event_interruptible_timeout
+		          ( cam->wait_frame,
+		            (!list_empty(&cam->outqueue)) ||
+		            (cam->state & DEV_DISCONNECTED) ||
+		            (cam->state & DEV_MISCONFIGURED),
+		            cam->module_param.frame_timeout *
+		            1000 * msecs_to_jiffies(1) );
+		if (timeout < 0)
+			return timeout;
 		if (cam->state & DEV_DISCONNECTED)
 			return -ENODEV;
-		if (cam->state & DEV_MISCONFIGURED)
+		if (!timeout || (cam->state & DEV_MISCONFIGURED))
 			return -EIO;
 	}
 
@@ -2571,8 +2597,10 @@
 		return sn9c102_vidioc_enuminput(cam, arg);
 
 	case VIDIOC_G_INPUT:
+		return sn9c102_vidioc_g_input(cam, arg);
+
 	case VIDIOC_S_INPUT:
-		return sn9c102_vidioc_gs_input(cam, arg);
+		return sn9c102_vidioc_s_input(cam, arg);
 
 	case VIDIOC_QUERYCTRL:
 		return sn9c102_vidioc_query_ctrl(cam, arg);
@@ -2655,19 +2683,19 @@
 	struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
 	int err = 0;
 
-	if (down_interruptible(&cam->fileop_sem))
+	if (mutex_lock_interruptible(&cam->fileop_mutex))
 		return -ERESTARTSYS;
 
 	if (cam->state & DEV_DISCONNECTED) {
 		DBG(1, "Device not present");
-		up(&cam->fileop_sem);
+		mutex_unlock(&cam->fileop_mutex);
 		return -ENODEV;
 	}
 
 	if (cam->state & DEV_MISCONFIGURED) {
 		DBG(1, "The camera is misconfigured. Close and open it "
 		       "again.");
-		up(&cam->fileop_sem);
+		mutex_unlock(&cam->fileop_mutex);
 		return -EIO;
 	}
 
@@ -2675,7 +2703,7 @@
 
 	err = sn9c102_ioctl_v4l2(inode, filp, cmd, (void __user *)arg);
 
-	up(&cam->fileop_sem);
+	mutex_unlock(&cam->fileop_mutex);
 
 	return err;
 }
@@ -2722,7 +2750,7 @@
 		goto fail;
 	}
 
-	init_MUTEX(&cam->dev_sem);
+	mutex_init(&cam->dev_mutex);
 
 	r = sn9c102_read_reg(cam, 0x00);
 	if (r < 0 || r != 0x10) {
@@ -2752,10 +2780,10 @@
 			break;
 	}
 
-	if (!err && cam->sensor) {
-		DBG(2, "%s image sensor detected", cam->sensor->name);
+	if (!err) {
+		DBG(2, "%s image sensor detected", cam->sensor.name);
 		DBG(3, "Support for %s maintained by %s",
-		    cam->sensor->name, cam->sensor->maintainer);
+		    cam->sensor.name, cam->sensor.maintainer);
 	} else {
 		DBG(1, "No supported image sensor detected");
 		err = -ENODEV;
@@ -2776,7 +2804,7 @@
 	cam->v4ldev->release = video_device_release;
 	video_set_drvdata(cam->v4ldev, cam);
 
-	down(&cam->dev_sem);
+	mutex_lock(&cam->dev_mutex);
 
 	err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
 	                            video_nr[dev_nr]);
@@ -2786,13 +2814,14 @@
 			DBG(1, "Free /dev/videoX node not found");
 		video_nr[dev_nr] = -1;
 		dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
-		up(&cam->dev_sem);
+		mutex_unlock(&cam->dev_mutex);
 		goto fail;
 	}
 
 	DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
 
 	cam->module_param.force_munmap = force_munmap[dev_nr];
+	cam->module_param.frame_timeout = frame_timeout[dev_nr];
 
 	dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
 
@@ -2803,7 +2832,7 @@
 
 	usb_set_intfdata(intf, cam);
 
-	up(&cam->dev_sem);
+	mutex_unlock(&cam->dev_mutex);
 
 	return 0;
 
@@ -2827,7 +2856,7 @@
 
 	down_write(&sn9c102_disconnect);
 
-	down(&cam->dev_sem); 
+	mutex_lock(&cam->dev_mutex);
 
 	DBG(2, "Disconnecting %s...", cam->v4ldev->name);
 
@@ -2841,13 +2870,14 @@
 		sn9c102_stop_transfer(cam);
 		cam->state |= DEV_DISCONNECTED;
 		wake_up_interruptible(&cam->wait_frame);
-		wake_up_interruptible(&cam->wait_stream);
+		wake_up(&cam->wait_stream);
+		usb_get_dev(cam->usbdev);
 	} else {
 		cam->state |= DEV_DISCONNECTED;
 		sn9c102_release_resources(cam);
 	}
 
-	up(&cam->dev_sem);
+	mutex_unlock(&cam->dev_mutex);
 
 	if (!cam->users)
 		kfree(cam);
diff --git a/drivers/usb/media/sn9c102_ov7630.c b/drivers/usb/media/sn9c102_ov7630.c
index 4a36519..42852b7 100644
--- a/drivers/usb/media/sn9c102_ov7630.c
+++ b/drivers/usb/media/sn9c102_ov7630.c
@@ -34,8 +34,8 @@
 	err += sn9c102_write_reg(cam, 0x0f, 0x18);
 	err += sn9c102_write_reg(cam, 0x50, 0x19);
 
-	err += sn9c102_i2c_write(cam, 0x12, 0x8d);
-	err += sn9c102_i2c_write(cam, 0x11, 0x00);
+	err += sn9c102_i2c_write(cam, 0x12, 0x80);
+	err += sn9c102_i2c_write(cam, 0x11, 0x01);
 	err += sn9c102_i2c_write(cam, 0x15, 0x34);
 	err += sn9c102_i2c_write(cam, 0x16, 0x03);
 	err += sn9c102_i2c_write(cam, 0x17, 0x1c);
@@ -43,12 +43,14 @@
 	err += sn9c102_i2c_write(cam, 0x19, 0x06);
 	err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
 	err += sn9c102_i2c_write(cam, 0x1b, 0x04);
-	err += sn9c102_i2c_write(cam, 0x20, 0x44);
+	err += sn9c102_i2c_write(cam, 0x20, 0xf6);
 	err += sn9c102_i2c_write(cam, 0x23, 0xee);
 	err += sn9c102_i2c_write(cam, 0x26, 0xa0);
 	err += sn9c102_i2c_write(cam, 0x27, 0x9a);
-	err += sn9c102_i2c_write(cam, 0x28, 0x20);
+	err += sn9c102_i2c_write(cam, 0x28, 0xa0);
 	err += sn9c102_i2c_write(cam, 0x29, 0x30);
+	err += sn9c102_i2c_write(cam, 0x2a, 0xa0);
+	err += sn9c102_i2c_write(cam, 0x2b, 0x1f);
 	err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
 	err += sn9c102_i2c_write(cam, 0x30, 0x24);
 	err += sn9c102_i2c_write(cam, 0x32, 0x86);
@@ -80,7 +82,7 @@
 		err += sn9c102_i2c_write(cam, 0x02, ctrl->value);
 		break;
 	case V4L2_CID_BLUE_BALANCE:
-		err += sn9c102_i2c_write(cam, 0x03, ctrl->value);
+		err += sn9c102_i2c_write(cam, 0x01, ctrl->value);
 		break;
 	case V4L2_CID_GAIN:
 		err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
@@ -108,7 +110,7 @@
 		err += sn9c102_i2c_write(cam, 0x0d, ctrl->value);
 		break;
 	case V4L2_CID_AUTO_WHITE_BALANCE:
-		err += sn9c102_i2c_write(cam, 0x12, (ctrl->value << 2) | 0x09);
+		err += sn9c102_i2c_write(cam, 0x12, (ctrl->value << 2) | 0x78);
 		break;
 	case V4L2_CID_AUTOGAIN:
 		err += sn9c102_i2c_write(cam, 0x13, ctrl->value);
@@ -371,26 +373,29 @@
 
 int sn9c102_probe_ov7630(struct sn9c102_device* cam)
 {
+	const struct usb_device_id ov7630_id_table[] = {
+		{ USB_DEVICE(0x0c45, 0x602c), },
+		{ USB_DEVICE(0x0c45, 0x602d), },
+		{ USB_DEVICE(0x0c45, 0x608f), },
+		{ USB_DEVICE(0x0c45, 0x60b0), },
+		{ }
+	};
 	int err = 0;
 
-	sn9c102_attach_sensor(cam, &ov7630);
-
-	if (le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x602c &&
-	    le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x602d &&
-	    le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x608f &&
-	    le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x60b0)
+	if (!sn9c102_match_id(cam, ov7630_id_table))
 		return -ENODEV;
 
 	err += sn9c102_write_reg(cam, 0x01, 0x01);
 	err += sn9c102_write_reg(cam, 0x00, 0x01);
 	err += sn9c102_write_reg(cam, 0x28, 0x17);
-
 	if (err)
 		return -EIO;
 
-	err += sn9c102_i2c_write(cam, 0x0b, 0);
+	err += sn9c102_i2c_try_write(cam, &ov7630, 0x0b, 0);
 	if (err)
 		return -ENODEV;
 
+	sn9c102_attach_sensor(cam, &ov7630);
+
 	return 0;
 }
diff --git a/drivers/usb/media/sn9c102_pas202bca.c b/drivers/usb/media/sn9c102_pas202bca.c
new file mode 100644
index 0000000..3453237
--- /dev/null
+++ b/drivers/usb/media/sn9c102_pas202bca.c
@@ -0,0 +1,238 @@
+/***************************************************************************
+ * Plug-in for PAS202BCA image sensor connected to the SN9C10x PC Camera   *
+ * Controllers                                                             *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include <linux/delay.h>
+#include "sn9c102_sensor.h"
+
+
+static struct sn9c102_sensor pas202bca;
+
+
+static int pas202bca_init(struct sn9c102_device* cam)
+{
+	int err = 0;
+
+	err += sn9c102_write_reg(cam, 0x00, 0x10);
+	err += sn9c102_write_reg(cam, 0x00, 0x11);
+	err += sn9c102_write_reg(cam, 0x00, 0x14);
+	err += sn9c102_write_reg(cam, 0x20, 0x17);
+	err += sn9c102_write_reg(cam, 0x30, 0x19);
+	err += sn9c102_write_reg(cam, 0x09, 0x18);
+
+	err += sn9c102_i2c_write(cam, 0x02, 0x14);
+	err += sn9c102_i2c_write(cam, 0x03, 0x40);
+	err += sn9c102_i2c_write(cam, 0x0d, 0x2c);
+	err += sn9c102_i2c_write(cam, 0x0e, 0x01);
+	err += sn9c102_i2c_write(cam, 0x0f, 0xa9);
+	err += sn9c102_i2c_write(cam, 0x10, 0x08);
+	err += sn9c102_i2c_write(cam, 0x13, 0x63);
+	err += sn9c102_i2c_write(cam, 0x15, 0x70);
+	err += sn9c102_i2c_write(cam, 0x11, 0x01);
+
+	msleep(400);
+
+	return err;
+}
+
+
+static int pas202bca_set_pix_format(struct sn9c102_device* cam,
+                                    const struct v4l2_pix_format* pix)
+{
+	int err = 0;
+
+	if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+		err += sn9c102_write_reg(cam, 0x24, 0x17);
+	else
+		err += sn9c102_write_reg(cam, 0x20, 0x17);
+
+	return err;
+}
+
+
+static int pas202bca_set_ctrl(struct sn9c102_device* cam,
+                              const struct v4l2_control* ctrl)
+{
+	int err = 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_EXPOSURE:
+		err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6);
+		err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f);
+		break;
+	case V4L2_CID_RED_BALANCE:
+		err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
+		break;
+	case V4L2_CID_BLUE_BALANCE:
+		err += sn9c102_i2c_write(cam, 0x07, ctrl->value);
+		break;
+	case V4L2_CID_GAIN:
+		err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
+		break;
+	case SN9C102_V4L2_CID_GREEN_BALANCE:
+		err += sn9c102_i2c_write(cam, 0x08, ctrl->value);
+		break;
+	case SN9C102_V4L2_CID_DAC_MAGNITUDE:
+		err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
+		break;
+	default:
+		return -EINVAL;
+	}
+	err += sn9c102_i2c_write(cam, 0x11, 0x01);
+
+	return err ? -EIO : 0;
+}
+
+
+static int pas202bca_set_crop(struct sn9c102_device* cam,
+                              const struct v4l2_rect* rect)
+{
+	struct sn9c102_sensor* s = &pas202bca;
+	int err = 0;
+	u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3,
+	   v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
+
+	err += sn9c102_write_reg(cam, h_start, 0x12);
+	err += sn9c102_write_reg(cam, v_start, 0x13);
+
+	return err;
+}
+
+
+static struct sn9c102_sensor pas202bca = {
+	.name = "PAS202BCA",
+	.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+	.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
+	.frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
+	.interface = SN9C102_I2C_2WIRES,
+	.i2c_slave_id = 0x40,
+	.init = &pas202bca_init,
+	.qctrl = {
+		{
+			.id = V4L2_CID_EXPOSURE,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "exposure",
+			.minimum = 0x01e5,
+			.maximum = 0x3fff,
+			.step = 0x0001,
+			.default_value = 0x01e5,
+			.flags = 0,
+		},
+		{
+			.id = V4L2_CID_GAIN,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "global gain",
+			.minimum = 0x00,
+			.maximum = 0x1f,
+			.step = 0x01,
+			.default_value = 0x0c,
+			.flags = 0,
+		},
+		{
+			.id = V4L2_CID_RED_BALANCE,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "red balance",
+			.minimum = 0x00,
+			.maximum = 0x0f,
+			.step = 0x01,
+			.default_value = 0x01,
+			.flags = 0,
+		},
+		{
+			.id = V4L2_CID_BLUE_BALANCE,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "blue balance",
+			.minimum = 0x00,
+			.maximum = 0x0f,
+			.step = 0x01,
+			.default_value = 0x05,
+			.flags = 0,
+		},
+		{
+			.id = SN9C102_V4L2_CID_GREEN_BALANCE,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "green balance",
+			.minimum = 0x00,
+			.maximum = 0x0f,
+			.step = 0x01,
+			.default_value = 0x00,
+			.flags = 0,
+		},
+		{
+			.id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "DAC magnitude",
+			.minimum = 0x00,
+			.maximum = 0xff,
+			.step = 0x01,
+			.default_value = 0x04,
+			.flags = 0,
+		},
+	},
+	.set_ctrl = &pas202bca_set_ctrl,
+	.cropcap = {
+		.bounds = {
+			.left = 0,
+			.top = 0,
+			.width = 640,
+			.height = 480,
+		},
+		.defrect = {
+			.left = 0,
+			.top = 0,
+			.width = 640,
+			.height = 480,
+		},
+	},
+	.set_crop = &pas202bca_set_crop,
+	.pix_format = {
+		.width = 640,
+		.height = 480,
+		.pixelformat = V4L2_PIX_FMT_SBGGR8,
+		.priv = 8,
+	},
+	.set_pix_format = &pas202bca_set_pix_format
+};
+
+
+int sn9c102_probe_pas202bca(struct sn9c102_device* cam)
+{
+	const struct usb_device_id pas202bca_id_table[] = {
+		{ USB_DEVICE(0x0c45, 0x60af), },
+		{ }
+	};
+	int err = 0;
+
+	if (!sn9c102_match_id(cam,pas202bca_id_table))
+		return -ENODEV;
+
+	err += sn9c102_write_reg(cam, 0x01, 0x01);
+	err += sn9c102_write_reg(cam, 0x40, 0x01);
+	err += sn9c102_write_reg(cam, 0x28, 0x17);
+	if (err)
+		return -EIO;
+
+	if (sn9c102_i2c_try_write(cam, &pas202bca, 0x10, 0)) /* try to write */
+		return -ENODEV;
+
+	sn9c102_attach_sensor(cam, &pas202bca);
+
+	return 0;
+}
diff --git a/drivers/usb/media/sn9c102_pas202bcb.c b/drivers/usb/media/sn9c102_pas202bcb.c
index 5ca54c7..d068616 100644
--- a/drivers/usb/media/sn9c102_pas202bcb.c
+++ b/drivers/usb/media/sn9c102_pas202bcb.c
@@ -263,7 +263,7 @@
 
 
 int sn9c102_probe_pas202bcb(struct sn9c102_device* cam)
-{       
+{
 	int r0 = 0, r1 = 0, err = 0;
 	unsigned int pid = 0;
 
diff --git a/drivers/usb/media/sn9c102_sensor.h b/drivers/usb/media/sn9c102_sensor.h
index 7d953b2..2afd9e9 100644
--- a/drivers/usb/media/sn9c102_sensor.h
+++ b/drivers/usb/media/sn9c102_sensor.h
@@ -66,6 +66,7 @@
 extern int sn9c102_probe_mi0343(struct sn9c102_device* cam);
 extern int sn9c102_probe_ov7630(struct sn9c102_device* cam);
 extern int sn9c102_probe_pas106b(struct sn9c102_device* cam);
+extern int sn9c102_probe_pas202bca(struct sn9c102_device* cam);
 extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam);
 extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam);
 extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam);
@@ -81,12 +82,17 @@
 	&sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */    \
 	&sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */  \
 	&sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */    \
+	&sn9c102_probe_pas202bca, /* detection mostly based on USB pid/vid */ \
 	&sn9c102_probe_ov7630, /* detection mostly based on USB pid/vid */    \
 	&sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */       \
 	&sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */       \
 	NULL,                                                                 \
 };
 
+/* Device identification */
+extern struct sn9c102_device*
+sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id);
+
 /* Attach a probed sensor to the camera. */
 extern void 
 sn9c102_attach_sensor(struct sn9c102_device* cam,
@@ -108,6 +114,7 @@
 static const struct usb_device_id sn9c102_id_table[] = {                      \
 	{ USB_DEVICE(0x0c45, 0x6001), }, /* TAS5110C1B */                     \
 	{ USB_DEVICE(0x0c45, 0x6005), }, /* TAS5110C1B */                     \
+	{ USB_DEVICE(0x0c45, 0x6007), },                                      \
 	{ USB_DEVICE(0x0c45, 0x6009), }, /* PAS106B */                        \
 	{ USB_DEVICE(0x0c45, 0x600d), }, /* PAS106B */                        \
 	{ USB_DEVICE(0x0c45, 0x6024), },                                      \
@@ -126,7 +133,7 @@
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6088, 0xff), },                        \
 	{ SN9C102_USB_DEVICE(0x0c45, 0x608a, 0xff), },                        \
 	{ SN9C102_USB_DEVICE(0x0c45, 0x608b, 0xff), },                        \
-	{ SN9C102_USB_DEVICE(0x0c45, 0x608c, 0xff), }, /* HV7131x */          \
+	{ SN9C102_USB_DEVICE(0x0c45, 0x608c, 0xff), }, /* HV7131/R */         \
 	{ SN9C102_USB_DEVICE(0x0c45, 0x608e, 0xff), }, /* CIS-VF10 */         \
 	{ SN9C102_USB_DEVICE(0x0c45, 0x608f, 0xff), }, /* OV7630 */           \
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60a0, 0xff), },                        \
@@ -359,12 +366,6 @@
 	   error code without rolling back.
 	*/
 
-	const struct usb_device* usbdev;
-	/*
-	   Points to the usb_device struct after the sensor is attached.
-	   Do not touch unless you know what you are doing.
-	*/
-
 	/*
 	   Do NOT write to the data below, it's READ ONLY. It is used by the
 	   core module to store successfully updated values of the above
diff --git a/drivers/usb/media/sn9c102_tas5110c1b.c b/drivers/usb/media/sn9c102_tas5110c1b.c
index 32ddf23..2e08c55 100644
--- a/drivers/usb/media/sn9c102_tas5110c1b.c
+++ b/drivers/usb/media/sn9c102_tas5110c1b.c
@@ -142,14 +142,18 @@
 
 int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam)
 {
-	/* This sensor has no identifiers, so let's attach it anyway */
-	sn9c102_attach_sensor(cam, &tas5110c1b);
+	const struct usb_device_id tas5110c1b_id_table[] = {
+		{ USB_DEVICE(0x0c45, 0x6001), },
+		{ USB_DEVICE(0x0c45, 0x6005), },
+		{ USB_DEVICE(0x0c45, 0x60ab), },
+		{ }
+	};
 
 	/* Sensor detection is based on USB pid/vid */
-	if (le16_to_cpu(tas5110c1b.usbdev->descriptor.idProduct) != 0x6001 &&
-	    le16_to_cpu(tas5110c1b.usbdev->descriptor.idProduct) != 0x6005 &&
-	    le16_to_cpu(tas5110c1b.usbdev->descriptor.idProduct) != 0x60ab)
+	if (!sn9c102_match_id(cam, tas5110c1b_id_table))
 		return -ENODEV;
 
+	sn9c102_attach_sensor(cam, &tas5110c1b);
+
 	return 0;
 }
diff --git a/drivers/usb/media/sn9c102_tas5130d1b.c b/drivers/usb/media/sn9c102_tas5130d1b.c
index a0728f0..c7b3397 100644
--- a/drivers/usb/media/sn9c102_tas5130d1b.c
+++ b/drivers/usb/media/sn9c102_tas5130d1b.c
@@ -153,13 +153,17 @@
 
 int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam)
 {
-	/* This sensor has no identifiers, so let's attach it anyway */
-	sn9c102_attach_sensor(cam, &tas5130d1b);
+	const struct usb_device_id tas5130d1b_id_table[] = {
+		{ USB_DEVICE(0x0c45, 0x6025), },
+		{ USB_DEVICE(0x0c45, 0x60aa), },
+		{ }
+	};
 
 	/* Sensor detection is based on USB pid/vid */
-	if (le16_to_cpu(tas5130d1b.usbdev->descriptor.idProduct) != 0x6025 &&
-	    le16_to_cpu(tas5130d1b.usbdev->descriptor.idProduct) != 0x60aa)
+	if (!sn9c102_match_id(cam, tas5130d1b_id_table))
 		return -ENODEV;
 
+	sn9c102_attach_sensor(cam, &tas5130d1b);
+
 	return 0;
 }
diff --git a/drivers/usb/media/stv680.c b/drivers/usb/media/stv680.c
index b497a6a..9636da2 100644
--- a/drivers/usb/media/stv680.c
+++ b/drivers/usb/media/stv680.c
@@ -67,6 +67,7 @@
 #include <linux/errno.h>
 #include <linux/videodev.h>
 #include <linux/usb.h>
+#include <linux/mutex.h>
 
 #include "stv680.h"
 
@@ -317,12 +318,11 @@
 	unsigned char *buffer;
 	unsigned long int bufsize;
 
-	buffer = kmalloc (40, GFP_KERNEL);
+	buffer = kzalloc (40, GFP_KERNEL);
 	if (buffer == NULL) {
 		PDEBUG (0, "STV(e): Out of (small buf) memory");
 		return -1;
 	}
-	memset (buffer, 0, 40);
 	udelay (100);
 
 	/* set config 1, interface 0, alternate 0 */
@@ -1258,22 +1258,22 @@
 	unsigned long size  = vma->vm_end-vma->vm_start;
 	unsigned long page, pos;
 
-	down (&stv680->lock);
+	mutex_lock(&stv680->lock);
 
 	if (stv680->udev == NULL) {
-		up (&stv680->lock);
+		mutex_unlock(&stv680->lock);
 		return -EIO;
 	}
 	if (size > (((STV680_NUMFRAMES * stv680->maxframesize) + PAGE_SIZE - 1)
 		    & ~(PAGE_SIZE - 1))) {
-		up (&stv680->lock);
+		mutex_unlock(&stv680->lock);
 		return -EINVAL;
 	}
 	pos = (unsigned long) stv680->fbuf;
 	while (size > 0) {
 		page = vmalloc_to_pfn((void *)pos);
 		if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-			up (&stv680->lock);
+			mutex_unlock(&stv680->lock);
 			return -EAGAIN;
 		}
 		start += PAGE_SIZE;
@@ -1283,7 +1283,7 @@
 		else
 			size = 0;
 	}
-	up (&stv680->lock);
+	mutex_unlock(&stv680->lock);
 
 	return 0;
 }
@@ -1387,14 +1387,12 @@
 		goto error;
 	}
 	/* We found one */
-	if ((stv680 = kmalloc (sizeof (*stv680), GFP_KERNEL)) == NULL) {
+	if ((stv680 = kzalloc (sizeof (*stv680), GFP_KERNEL)) == NULL) {
 		PDEBUG (0, "STV(e): couldn't kmalloc stv680 struct.");
 		retval = -ENOMEM;
 		goto error;
 	}
 
-	memset (stv680, 0, sizeof (*stv680));
-
 	stv680->udev = dev;
 	stv680->camera_name = camera_name;
 
@@ -1409,7 +1407,7 @@
 
 	memcpy (stv680->vdev->name, stv680->camera_name, strlen (stv680->camera_name));
 	init_waitqueue_head (&stv680->wq);
-	init_MUTEX (&stv680->lock);
+	mutex_init (&stv680->lock);
 	wmb ();
 
 	if (video_register_device (stv680->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
diff --git a/drivers/usb/media/stv680.h b/drivers/usb/media/stv680.h
index b0551cd..ea46e00 100644
--- a/drivers/usb/media/stv680.h
+++ b/drivers/usb/media/stv680.h
@@ -118,7 +118,7 @@
 	int origGain;
 	int origMode;		/* original camera mode */
 
-	struct semaphore lock;	/* to lock the structure */
+	struct mutex lock;	/* to lock the structure */
 	int user;		/* user count for exclusive use */
 	int removed;		/* device disconnected */
 	int streaming;		/* Are we streaming video? */
diff --git a/drivers/usb/media/usbvideo.c b/drivers/usb/media/usbvideo.c
index 63a72e5..0b51fae 100644
--- a/drivers/usb/media/usbvideo.c
+++ b/drivers/usb/media/usbvideo.c
@@ -690,14 +690,13 @@
 	}
 
 	base_size = num_cams * sizeof(struct uvd) + sizeof(struct usbvideo);
-	cams = (struct usbvideo *) kmalloc(base_size, GFP_KERNEL);
+	cams = (struct usbvideo *) kzalloc(base_size, GFP_KERNEL);
 	if (cams == NULL) {
 		err("Failed to allocate %d. bytes for usbvideo struct", base_size);
 		return -ENOMEM;
 	}
 	dbg("%s: Allocated $%p (%d. bytes) for %d. cameras",
 	    __FUNCTION__, cams, base_size, num_cams);
-	memset(cams, 0, base_size);
 
 	/* Copy callbacks, apply defaults for those that are not set */
 	memmove(&cams->cb, cbTbl, sizeof(cams->cb));
@@ -715,7 +714,7 @@
 	cams->md_module = md;
 	if (cams->md_module == NULL)
 		warn("%s: module == NULL!", __FUNCTION__);
-	init_MUTEX(&cams->lock);	/* to 1 == available */
+	mutex_init(&cams->lock);	/* to 1 == available */
 
 	for (i = 0; i < num_cams; i++) {
 		struct uvd *up = &cams->cam[i];
@@ -863,7 +862,7 @@
 	if (uvd->debug > 0)
 		info("%s(%p.)", __FUNCTION__, intf);
 
-	down(&uvd->lock);
+	mutex_lock(&uvd->lock);
 	uvd->remove_pending = 1; /* Now all ISO data will be ignored */
 
 	/* At this time we ask to cancel outstanding URBs */
@@ -883,7 +882,7 @@
 		info("%s: In use, disconnect pending.", __FUNCTION__);
 	else
 		usbvideo_CameraRelease(uvd);
-	up(&uvd->lock);
+	mutex_unlock(&uvd->lock);
 	info("USB camera disconnected.");
 
 	usbvideo_ClientDecModCount(uvd);
@@ -930,19 +929,19 @@
 		err("No usbvideo handle?");
 		return -1;
 	}
-	down(&cams->lock);
+	mutex_lock(&cams->lock);
 	for (u = 0; u < cams->num_cameras; u++) {
 		struct uvd *uvd = &cams->cam[u];
 		if (!uvd->uvd_used) /* This one is free */
 		{
 			uvd->uvd_used = 1;	/* In use now */
-			init_MUTEX(&uvd->lock);	/* to 1 == available */
+			mutex_init(&uvd->lock);	/* to 1 == available */
 			uvd->dev = NULL;
 			rv = u;
 			break;
 		}
 	}
-	up(&cams->lock);
+	mutex_unlock(&cams->lock);
 	return rv;
 }
 
@@ -984,7 +983,7 @@
 	/* Not relying upon caller we increase module counter ourselves */
 	usbvideo_ClientIncModCount(uvd);
 
-	down(&uvd->lock);
+	mutex_lock(&uvd->lock);
 	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
 		uvd->sbuf[i].urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
 		if (uvd->sbuf[i].urb == NULL) {
@@ -1007,7 +1006,7 @@
 	 * return control to the client's probe function right now.
 	 */
 allocate_done:
-	up (&uvd->lock);
+	mutex_unlock(&uvd->lock);
 	usbvideo_ClientDecModCount(uvd);
 	return uvd;
 }
@@ -1121,7 +1120,7 @@
 		info("%s($%p)", __FUNCTION__, dev);
 
 	usbvideo_ClientIncModCount(uvd);
-	down(&uvd->lock);
+	mutex_lock(&uvd->lock);
 
 	if (uvd->user) {
 		err("%s: Someone tried to open an already opened device!", __FUNCTION__);
@@ -1202,7 +1201,7 @@
 			}
 		}
 	}
-	up(&uvd->lock);
+	mutex_unlock(&uvd->lock);
 	if (errCode != 0)
 		usbvideo_ClientDecModCount(uvd);
 	if (uvd->debug > 0)
@@ -1231,7 +1230,7 @@
 	if (uvd->debug > 1)
 		info("%s($%p)", __FUNCTION__, dev);
 
-	down(&uvd->lock);
+	mutex_lock(&uvd->lock);
 	GET_CALLBACK(uvd, stopDataPump)(uvd);
 	usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size);
 	uvd->fbuf = NULL;
@@ -1252,7 +1251,7 @@
 			info("usbvideo_v4l_close: Final disconnect.");
 		usbvideo_CameraRelease(uvd);
 	}
-	up(&uvd->lock);
+	mutex_unlock(&uvd->lock);
 	usbvideo_ClientDecModCount(uvd);
 
 	if (uvd->debug > 1)
@@ -1512,7 +1511,7 @@
 	if (uvd->debug >= 1)
 		info("%s: %Zd. bytes, noblock=%d.", __FUNCTION__, count, noblock);
 
-	down(&uvd->lock);	
+	mutex_lock(&uvd->lock);
 
 	/* See if a frame is completed, then use it. */
 	for(i = 0; i < USBVIDEO_NUMFRAMES; i++) {
@@ -1644,7 +1643,7 @@
 		}
 	}
 read_done:
-	up(&uvd->lock);	
+	mutex_unlock(&uvd->lock);
 	return count;
 }
 
diff --git a/drivers/usb/media/usbvideo.h b/drivers/usb/media/usbvideo.h
index 6c390a1f..135433c 100644
--- a/drivers/usb/media/usbvideo.h
+++ b/drivers/usb/media/usbvideo.h
@@ -19,6 +19,7 @@
 #include <linux/config.h>
 #include <linux/videodev.h>
 #include <linux/usb.h>
+#include <linux/mutex.h>
 
 /* Most helpful debugging aid */
 #define assert(expr) ((void) ((expr) ? 0 : (err("assert failed at line %d",__LINE__))))
@@ -213,7 +214,7 @@
 	unsigned long flags;		/* FLAGS_USBVIDEO_xxx */
 	unsigned long paletteBits;	/* Which palettes we accept? */
 	unsigned short defaultPalette;	/* What palette to use for read() */
-	struct semaphore lock;
+	struct mutex lock;
 	int user;		/* user count for exclusive use */
 
 	videosize_t videosize;	/* Current setting */
@@ -272,7 +273,7 @@
 	int num_cameras;		/* As allocated */
 	struct usb_driver usbdrv;	/* Interface to the USB stack */
 	char drvName[80];		/* Driver name */
-	struct semaphore lock;		/* Mutex protecting camera structures */
+	struct mutex lock;		/* Mutex protecting camera structures */
 	struct usbvideo_cb cb;		/* Table of callbacks (virtual methods) */
 	struct video_device vdt;	/* Video device template */
 	struct uvd *cam;			/* Array of camera structures */
diff --git a/drivers/usb/media/vicam.c b/drivers/usb/media/vicam.c
index 5df1440..1d06e53 100644
--- a/drivers/usb/media/vicam.c
+++ b/drivers/usb/media/vicam.c
@@ -42,6 +42,7 @@
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
 #include <linux/proc_fs.h>
+#include <linux/mutex.h>
 #include "usbvideo.h"
 
 // #define VICAM_DEBUG
@@ -407,7 +408,7 @@
 	struct usb_device *udev;	// usb device
 
 	/* guard against simultaneous accesses to the camera */
-	struct semaphore cam_lock;
+	struct mutex cam_lock;
 
 	int is_initialized;
 	u8 open_count;
@@ -461,12 +462,12 @@
 			    u16 size)
 {
 	int status = -ENODEV;
-	down(&cam->cam_lock);
+	mutex_lock(&cam->cam_lock);
 	if (cam->udev) {
 		status = __send_control_msg(cam, request, value,
 					    index, cp, size);
 	}
-	up(&cam->cam_lock);
+	mutex_unlock(&cam->cam_lock);
 	return status;
 }
 static int
@@ -763,6 +764,7 @@
 	if (!cam) {
 		printk(KERN_ERR
 		       "vicam video_device improperly initialized");
+		return -EINVAL;
 	}
 
 	/* the videodev_lock held above us protects us from
@@ -831,13 +833,13 @@
 	rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
 	kfree(cam->cntrlbuf);
 
-	down(&cam->cam_lock);
+	mutex_lock(&cam->cam_lock);
 
 	cam->open_count--;
 	open_count = cam->open_count;
 	udev = cam->udev;
 
-	up(&cam->cam_lock);
+	mutex_unlock(&cam->cam_lock);
 
 	if (!open_count && !udev) {
 		kfree(cam);
@@ -960,7 +962,7 @@
 	request[8] = 0;
 	// bytes 9-15 do not seem to affect exposure or image quality
 
-	down(&cam->cam_lock);
+	mutex_lock(&cam->cam_lock);
 
 	if (!cam->udev) {
 		goto done;
@@ -985,7 +987,7 @@
 	}
 
  done:
-	up(&cam->cam_lock);
+	mutex_unlock(&cam->cam_lock);
 }
 
 static ssize_t
@@ -1309,7 +1311,7 @@
 
 	cam->shutter_speed = 15;
 
-	init_MUTEX(&cam->cam_lock);
+	mutex_init(&cam->cam_lock);
 
 	memcpy(&cam->vdev, &vicam_template,
 	       sizeof (vicam_template));
@@ -1351,7 +1353,7 @@
 
 	/* stop the camera from being used */
 
-	down(&cam->cam_lock);
+	mutex_lock(&cam->cam_lock);
 
 	/* mark the camera as gone */
 
@@ -1368,7 +1370,7 @@
 
 	open_count = cam->open_count;
 
-	up(&cam->cam_lock);
+	mutex_unlock(&cam->cam_lock);
 
 	if (!open_count) {
 		kfree(cam);
diff --git a/drivers/usb/media/w9968cf.c b/drivers/usb/media/w9968cf.c
index 9937fc6..b57dec3 100644
--- a/drivers/usb/media/w9968cf.c
+++ b/drivers/usb/media/w9968cf.c
@@ -47,6 +47,13 @@
 #include "w9968cf.h"
 #include "w9968cf_decoder.h"
 
+static struct w9968cf_vpp_t* w9968cf_vpp;
+static DECLARE_WAIT_QUEUE_HEAD(w9968cf_vppmod_wait);
+
+static LIST_HEAD(w9968cf_dev_list); /* head of V4L registered cameras list */
+static DEFINE_MUTEX(w9968cf_devlist_mutex); /* semaphore for list traversal */
+
+static DECLARE_RWSEM(w9968cf_disconnect); /* prevent races with open() */
 
 
 /****************************************************************************
@@ -695,13 +702,12 @@
 	/* Allocate memory for the isochronous transfer buffers */
 	for (i = 0; i < W9968CF_URBS; i++) {
 		if (!(cam->transfer_buffer[i] =
-		      kmalloc(W9968CF_ISO_PACKETS*p_size, GFP_KERNEL))) {
+		      kzalloc(W9968CF_ISO_PACKETS*p_size, GFP_KERNEL))) {
 			DBG(1, "Couldn't allocate memory for the isochronous "
 			       "transfer buffers (%u bytes)", 
 			    p_size * W9968CF_ISO_PACKETS)
 			return -ENOMEM;
 		}
-		memset(cam->transfer_buffer[i], 0, W9968CF_ISO_PACKETS*p_size);
 	}
 
 	/* Allocate memory for the temporary frame buffer */
@@ -2419,7 +2425,7 @@
                          enum w9968cf_model_id mod_id,
                          const unsigned short dev_nr)
 {
-	init_MUTEX(&cam->fileop_sem);
+	mutex_init(&cam->fileop_mutex);
 	init_waitqueue_head(&cam->open);
 	spin_lock_init(&cam->urb_lock);
 	spin_lock_init(&cam->flist_lock);
@@ -2647,7 +2653,7 @@
   --------------------------------------------------------------------------*/
 static void w9968cf_release_resources(struct w9968cf_device* cam)
 {
-	down(&w9968cf_devlist_sem);
+	mutex_lock(&w9968cf_devlist_mutex);
 
 	DBG(2, "V4L device deregistered: /dev/video%d", cam->v4ldev->minor)
 
@@ -2658,7 +2664,7 @@
 	kfree(cam->control_buffer);
 	kfree(cam->data_buffer);
 
-	up(&w9968cf_devlist_sem);
+	mutex_unlock(&w9968cf_devlist_mutex);
 }
 
 
@@ -2678,14 +2684,14 @@
 
 	cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
 
-	down(&cam->dev_sem);
+	mutex_lock(&cam->dev_mutex);
 
 	if (cam->sensor == CC_UNKNOWN) {
 		DBG(2, "No supported image sensor has been detected by the "
 		       "'ovcamchip' module for the %s (/dev/video%d). Make "
 		       "sure it is loaded *before* (re)connecting the camera.",
 		    symbolic(camlist, cam->id), cam->v4ldev->minor)
-		up(&cam->dev_sem);
+		mutex_unlock(&cam->dev_mutex);
 		up_read(&w9968cf_disconnect);
 		return -ENODEV;
 	}
@@ -2694,11 +2700,11 @@
 		DBG(2, "%s (/dev/video%d) has been already occupied by '%s'",
 		    symbolic(camlist, cam->id),cam->v4ldev->minor,cam->command)
 		if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) {
-			up(&cam->dev_sem);
+			mutex_unlock(&cam->dev_mutex);
 			up_read(&w9968cf_disconnect);
 			return -EWOULDBLOCK;
 		}
-		up(&cam->dev_sem);
+		mutex_unlock(&cam->dev_mutex);
 		err = wait_event_interruptible_exclusive(cam->open,
 		                                         cam->disconnected ||
 		                                         !cam->users);
@@ -2710,7 +2716,7 @@
 			up_read(&w9968cf_disconnect);
 			return -ENODEV;
 		}
-		down(&cam->dev_sem);
+		mutex_lock(&cam->dev_mutex);
 	}
 
 	DBG(5, "Opening '%s', /dev/video%d ...",
@@ -2739,7 +2745,7 @@
 
 	DBG(5, "Video device is open")
 
-	up(&cam->dev_sem);
+	mutex_unlock(&cam->dev_mutex);
 	up_read(&w9968cf_disconnect);
 
 	return 0;
@@ -2747,7 +2753,7 @@
 deallocate_memory:
 	w9968cf_deallocate_memory(cam);
 	DBG(2, "Failed to open the video device")
-	up(&cam->dev_sem);
+	mutex_unlock(&cam->dev_mutex);
 	up_read(&w9968cf_disconnect);
 	return err;
 }
@@ -2759,13 +2765,13 @@
 
 	cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
 
-	down(&cam->dev_sem); /* prevent disconnect() to be called */
+	mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
 
 	w9968cf_stop_transfer(cam);
 
 	if (cam->disconnected) {
 		w9968cf_release_resources(cam);
-		up(&cam->dev_sem);
+		mutex_unlock(&cam->dev_mutex);
 		kfree(cam);
 		return 0;
 	}
@@ -2775,7 +2781,7 @@
 	wake_up_interruptible_nr(&cam->open, 1);
 
 	DBG(5, "Video device closed")
-	up(&cam->dev_sem);
+	mutex_unlock(&cam->dev_mutex);
 	return 0;
 }
 
@@ -2792,18 +2798,18 @@
 	if (filp->f_flags & O_NONBLOCK)
 		return -EWOULDBLOCK;
 
-	if (down_interruptible(&cam->fileop_sem))
+	if (mutex_lock_interruptible(&cam->fileop_mutex))
 		return -ERESTARTSYS;
 
 	if (cam->disconnected) {
 		DBG(2, "Device not present")
-		up(&cam->fileop_sem);
+		mutex_unlock(&cam->fileop_mutex);
 		return -ENODEV;
 	}
 
 	if (cam->misconfigured) {
 		DBG(2, "The camera is misconfigured. Close and open it again.")
-		up(&cam->fileop_sem);
+		mutex_unlock(&cam->fileop_mutex);
 		return -EIO;
 	}
 
@@ -2818,11 +2824,11 @@
 	                               cam->frame[1].status == F_READY ||
 	                               cam->disconnected);
 	if (err) {
-		up(&cam->fileop_sem);
+		mutex_unlock(&cam->fileop_mutex);
 		return err;
 	}
 	if (cam->disconnected) {
-		up(&cam->fileop_sem);
+		mutex_unlock(&cam->fileop_mutex);
 		return -ENODEV;
 	}
 
@@ -2836,7 +2842,7 @@
 
 	if (copy_to_user(buf, fr->buffer, count)) {
 		fr->status = F_UNUSED;
-		up(&cam->fileop_sem);
+		mutex_unlock(&cam->fileop_mutex);
 		return -EFAULT;
 	}
 	*f_pos += count;
@@ -2845,7 +2851,7 @@
 
 	DBG(5, "%zu bytes read", count)
 
-	up(&cam->fileop_sem);
+	mutex_unlock(&cam->fileop_mutex);
 	return count;
 }
 
@@ -2899,24 +2905,24 @@
 
 	cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
 
-	if (down_interruptible(&cam->fileop_sem))
+	if (mutex_lock_interruptible(&cam->fileop_mutex))
 		return -ERESTARTSYS;
 
 	if (cam->disconnected) {
 		DBG(2, "Device not present")
-		up(&cam->fileop_sem);
+		mutex_unlock(&cam->fileop_mutex);
 		return -ENODEV;
 	}
 
 	if (cam->misconfigured) {
 		DBG(2, "The camera is misconfigured. Close and open it again.")
-		up(&cam->fileop_sem);
+		mutex_unlock(&cam->fileop_mutex);
 		return -EIO;
 	}
 
 	err = w9968cf_v4l_ioctl(inode, filp, cmd, (void __user *)arg);
 
-	up(&cam->fileop_sem);
+	mutex_unlock(&cam->fileop_mutex);
 	return err;
 }
 
@@ -3499,14 +3505,12 @@
 		return -ENODEV;
 
 	cam = (struct w9968cf_device*)
-	          kmalloc(sizeof(struct w9968cf_device), GFP_KERNEL);
+	          kzalloc(sizeof(struct w9968cf_device), GFP_KERNEL);
 	if (!cam)
 		return -ENOMEM;
 
-	memset(cam, 0, sizeof(*cam));
-
-	init_MUTEX(&cam->dev_sem);
-	down(&cam->dev_sem);
+	mutex_init(&cam->dev_mutex);
+	mutex_lock(&cam->dev_mutex);
 
 	cam->usbdev = udev;
 	/* NOTE: a local copy is used to avoid possible race conditions */
@@ -3518,10 +3522,10 @@
 		simcams = W9968CF_SIMCAMS;
 
 	/* How many cameras are connected ? */
-	down(&w9968cf_devlist_sem);
+	mutex_lock(&w9968cf_devlist_mutex);
 	list_for_each(ptr, &w9968cf_dev_list)
 		sc++;
-	up(&w9968cf_devlist_sem);
+	mutex_unlock(&w9968cf_devlist_mutex);
 
 	if (sc >= simcams) {
 		DBG(2, "Device rejected: too many connected cameras "
@@ -3532,21 +3536,19 @@
 
 
 	/* Allocate 2 bytes of memory for camera control USB transfers */
-	if (!(cam->control_buffer = kmalloc(2, GFP_KERNEL))) {
+	if (!(cam->control_buffer = kzalloc(2, GFP_KERNEL))) {
 		DBG(1,"Couldn't allocate memory for camera control transfers")
 		err = -ENOMEM;
 		goto fail;
 	}
-	memset(cam->control_buffer, 0, 2);
 
 	/* Allocate 8 bytes of memory for USB data transfers to the FSB */
-	if (!(cam->data_buffer = kmalloc(8, GFP_KERNEL))) {
+	if (!(cam->data_buffer = kzalloc(8, GFP_KERNEL))) {
 		DBG(1, "Couldn't allocate memory for data "
 		       "transfers to the FSB")
 		err = -ENOMEM;
 		goto fail;
 	}
-	memset(cam->data_buffer, 0, 8);
 
 	/* Register the V4L device */
 	cam->v4ldev = video_device_alloc();
@@ -3583,9 +3585,9 @@
 	w9968cf_configure_camera(cam, udev, mod_id, dev_nr);
 
 	/* Add a new entry into the list of V4L registered devices */
-	down(&w9968cf_devlist_sem);
+	mutex_lock(&w9968cf_devlist_mutex);
 	list_add(&cam->v4llist, &w9968cf_dev_list);
-	up(&w9968cf_devlist_sem);
+	mutex_unlock(&w9968cf_devlist_mutex);
 	dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0;
 
 	w9968cf_turn_on_led(cam);
@@ -3593,7 +3595,7 @@
 	w9968cf_i2c_init(cam);
 
 	usb_set_intfdata(intf, cam);
-	up(&cam->dev_sem);
+	mutex_unlock(&cam->dev_mutex);
 	return 0;
 
 fail: /* Free unused memory */
@@ -3601,7 +3603,7 @@
 	kfree(cam->data_buffer);
 	if (cam->v4ldev)
 		video_device_release(cam->v4ldev);
-	up(&cam->dev_sem);
+	mutex_unlock(&cam->dev_mutex);
 	kfree(cam);
 	return err;
 }
@@ -3616,7 +3618,7 @@
 
 	if (cam) {
 		/* Prevent concurrent accesses to data */
-		down(&cam->dev_sem); 
+		mutex_lock(&cam->dev_mutex);
 
 		cam->disconnected = 1;
 
@@ -3635,7 +3637,7 @@
 		} else
 			w9968cf_release_resources(cam);
 
-		up(&cam->dev_sem);
+		mutex_unlock(&cam->dev_mutex);
 
 		if (!cam->users)
 			kfree(cam);
diff --git a/drivers/usb/media/w9968cf.h b/drivers/usb/media/w9968cf.h
index 47a6ff7..a87be71 100644
--- a/drivers/usb/media/w9968cf.h
+++ b/drivers/usb/media/w9968cf.h
@@ -32,7 +32,7 @@
 #include <linux/param.h>
 #include <linux/types.h>
 #include <linux/rwsem.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #include <media/ovcamchip.h>
 
@@ -194,14 +194,6 @@
 	VPP_UYVY_TO_RGBX = 0x08,
 };
 
-static struct w9968cf_vpp_t* w9968cf_vpp;
-static DECLARE_WAIT_QUEUE_HEAD(w9968cf_vppmod_wait);
-
-static LIST_HEAD(w9968cf_dev_list); /* head of V4L registered cameras list */
-static DECLARE_MUTEX(w9968cf_devlist_sem); /* semaphore for list traversal */
-
-static DECLARE_RWSEM(w9968cf_disconnect); /* prevent races with open() */
-
 /* Main device driver structure */
 struct w9968cf_device {
 	struct device dev; /* device structure */
@@ -277,8 +269,8 @@
 	struct i2c_client* sensor_client;
 
 	/* Locks */
-	struct semaphore dev_sem,    /* for probe, disconnect,open and close */
-	                 fileop_sem; /* for read and ioctl */
+	struct mutex dev_mutex,    /* for probe, disconnect,open and close */
+	                 fileop_mutex; /* for read and ioctl */
 	spinlock_t urb_lock,   /* for submit_urb() and unlink_urb() */
 	           flist_lock; /* for requested frame list accesses */
 	wait_queue_head_t open, wait_queue;
diff --git a/drivers/usb/media/zc0301.h b/drivers/usb/media/zc0301.h
new file mode 100644
index 0000000..8e06551
--- /dev/null
+++ b/drivers/usb/media/zc0301.h
@@ -0,0 +1,192 @@
+/***************************************************************************
+ * V4L2 driver for ZC0301 Image Processor and Control Chip                 *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * 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 _ZC0301_H_
+#define _ZC0301_H_
+
+#include <linux/version.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/types.h>
+#include <linux/param.h>
+#include <linux/mutex.h>
+#include <linux/rwsem.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
+
+#include "zc0301_sensor.h"
+
+/*****************************************************************************/
+
+#define ZC0301_DEBUG
+#define ZC0301_DEBUG_LEVEL         2
+#define ZC0301_MAX_DEVICES         64
+#define ZC0301_FORCE_MUNMAP        0
+#define ZC0301_MAX_FRAMES          32
+#define ZC0301_COMPRESSION_QUALITY 0
+#define ZC0301_URBS                2
+#define ZC0301_ISO_PACKETS         7
+#define ZC0301_ALTERNATE_SETTING   7
+#define ZC0301_URB_TIMEOUT         msecs_to_jiffies(2 * ZC0301_ISO_PACKETS)
+#define ZC0301_CTRL_TIMEOUT        100
+#define ZC0301_FRAME_TIMEOUT       2
+
+/*****************************************************************************/
+
+ZC0301_ID_TABLE
+ZC0301_SENSOR_TABLE
+
+enum zc0301_frame_state {
+	F_UNUSED,
+	F_QUEUED,
+	F_GRABBING,
+	F_DONE,
+	F_ERROR,
+};
+
+struct zc0301_frame_t {
+	void* bufmem;
+	struct v4l2_buffer buf;
+	enum zc0301_frame_state state;
+	struct list_head frame;
+	unsigned long vma_use_count;
+};
+
+enum zc0301_dev_state {
+	DEV_INITIALIZED = 0x01,
+	DEV_DISCONNECTED = 0x02,
+	DEV_MISCONFIGURED = 0x04,
+};
+
+enum zc0301_io_method {
+	IO_NONE,
+	IO_READ,
+	IO_MMAP,
+};
+
+enum zc0301_stream_state {
+	STREAM_OFF,
+	STREAM_INTERRUPT,
+	STREAM_ON,
+};
+
+struct zc0301_module_param {
+	u8 force_munmap;
+	u16 frame_timeout;
+};
+
+static DECLARE_RWSEM(zc0301_disconnect);
+
+struct zc0301_device {
+	struct video_device* v4ldev;
+
+	struct zc0301_sensor sensor;
+
+	struct usb_device* usbdev;
+	struct urb* urb[ZC0301_URBS];
+	void* transfer_buffer[ZC0301_URBS];
+	u8* control_buffer;
+
+	struct zc0301_frame_t *frame_current, frame[ZC0301_MAX_FRAMES];
+	struct list_head inqueue, outqueue;
+	u32 frame_count, nbuffers, nreadbuffers;
+
+	enum zc0301_io_method io;
+	enum zc0301_stream_state stream;
+
+	struct v4l2_jpegcompression compression;
+
+	struct zc0301_module_param module_param;
+
+	enum zc0301_dev_state state;
+	u8 users;
+
+	struct mutex dev_mutex, fileop_mutex;
+	spinlock_t queue_lock;
+	wait_queue_head_t open, wait_frame, wait_stream;
+};
+
+/*****************************************************************************/
+
+struct zc0301_device*
+zc0301_match_id(struct zc0301_device* cam, const struct usb_device_id *id)
+{
+	return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL;
+}
+
+void
+zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor)
+{
+	memcpy(&cam->sensor, sensor, sizeof(struct zc0301_sensor));
+}
+
+/*****************************************************************************/
+
+#undef DBG
+#undef KDBG
+#ifdef ZC0301_DEBUG
+#	define DBG(level, fmt, args...)                                       \
+do {                                                                          \
+	if (debug >= (level)) {                                               \
+		if ((level) == 1)                                             \
+			dev_err(&cam->usbdev->dev, fmt "\n", ## args);        \
+		else if ((level) == 2)                                        \
+			dev_info(&cam->usbdev->dev, fmt "\n", ## args);       \
+		else if ((level) >= 3)                                        \
+			dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",      \
+			         __FUNCTION__, __LINE__ , ## args);           \
+	}                                                                     \
+} while (0)
+#	define KDBG(level, fmt, args...)                                      \
+do {                                                                          \
+	if (debug >= (level)) {                                               \
+		if ((level) == 1 || (level) == 2)                             \
+			pr_info("zc0301: " fmt "\n", ## args);                \
+		else if ((level) == 3)                                        \
+			pr_debug("zc0301: [%s:%d] " fmt "\n", __FUNCTION__,   \
+			         __LINE__ , ## args);                         \
+	}                                                                     \
+} while (0)
+#	define V4LDBG(level, name, cmd)                                       \
+do {                                                                          \
+	if (debug >= (level))                                                 \
+		v4l_print_ioctl(name, cmd);                                   \
+} while (0)
+#else
+#	define DBG(level, fmt, args...) do {;} while(0)
+#	define KDBG(level, fmt, args...) do {;} while(0)
+#	define V4LDBG(level, name, cmd) do {;} while(0)
+#endif
+
+#undef PDBG
+#define PDBG(fmt, args...)                                                    \
+dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",                              \
+         __FUNCTION__, __LINE__ , ## args)
+
+#undef PDBGG
+#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
+
+#endif /* _ZC0301_H_ */
diff --git a/drivers/usb/media/zc0301_core.c b/drivers/usb/media/zc0301_core.c
new file mode 100644
index 0000000..4036c626
--- /dev/null
+++ b/drivers/usb/media/zc0301_core.c
@@ -0,0 +1,2055 @@
+/***************************************************************************
+ * Video4Linux2 driver for ZC0301 Image Processor and Control Chip         *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * Informations about the chip internals needed to enable the I2C protocol *
+ * have been taken from the documentation of the ZC030x Video4Linux1       *
+ * driver written by Andrew Birkett <andy@nobugs.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.               *
+ ***************************************************************************/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/compiler.h>
+#include <linux/ioctl.h>
+#include <linux/poll.h>
+#include <linux/stat.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/page-flags.h>
+#include <linux/byteorder/generic.h>
+#include <asm/page.h>
+#include <asm/uaccess.h>
+
+#include "zc0301.h"
+
+/*****************************************************************************/
+
+#define ZC0301_MODULE_NAME    "V4L2 driver for ZC0301 "                       \
+                              "Image Processor and Control Chip"
+#define ZC0301_MODULE_AUTHOR  "(C) 2006 Luca Risolia"
+#define ZC0301_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"
+#define ZC0301_MODULE_LICENSE "GPL"
+#define ZC0301_MODULE_VERSION "1:1.03"
+#define ZC0301_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 3)
+
+/*****************************************************************************/
+
+MODULE_DEVICE_TABLE(usb, zc0301_id_table);
+
+MODULE_AUTHOR(ZC0301_MODULE_AUTHOR " " ZC0301_AUTHOR_EMAIL);
+MODULE_DESCRIPTION(ZC0301_MODULE_NAME);
+MODULE_VERSION(ZC0301_MODULE_VERSION);
+MODULE_LICENSE(ZC0301_MODULE_LICENSE);
+
+static short video_nr[] = {[0 ... ZC0301_MAX_DEVICES-1] = -1};
+module_param_array(video_nr, short, NULL, 0444);
+MODULE_PARM_DESC(video_nr,
+                 "\n<-1|n[,...]> Specify V4L2 minor mode number."
+                 "\n -1 = use next available (default)"
+                 "\n  n = use minor number n (integer >= 0)"
+                 "\nYou can specify up to "
+                 __MODULE_STRING(ZC0301_MAX_DEVICES) " cameras this way."
+                 "\nFor example:"
+                 "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
+                 "\nthe second registered camera and use auto for the first"
+                 "\none and for every other camera."
+                 "\n");
+
+static short force_munmap[] = {[0 ... ZC0301_MAX_DEVICES-1] =
+                               ZC0301_FORCE_MUNMAP};
+module_param_array(force_munmap, bool, NULL, 0444);
+MODULE_PARM_DESC(force_munmap,
+                 "\n<0|1[,...]> Force the application to unmap previously"
+                 "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
+                 "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
+                 "\nthis feature. This parameter is specific for each"
+                 "\ndetected camera."
+                 "\n 0 = do not force memory unmapping"
+                 "\n 1 = force memory unmapping (save memory)"
+                 "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
+                 "\n");
+
+static unsigned int frame_timeout[] = {[0 ... ZC0301_MAX_DEVICES-1] =
+                                       ZC0301_FRAME_TIMEOUT};
+module_param_array(frame_timeout, uint, NULL, 0644);
+MODULE_PARM_DESC(frame_timeout,
+                 "\n<n[,...]> Timeout for a video frame in seconds."
+                 "\nThis parameter is specific for each detected camera."
+                 "\nDefault value is "__MODULE_STRING(ZC0301_FRAME_TIMEOUT)"."
+                 "\n");
+
+#ifdef ZC0301_DEBUG
+static unsigned short debug = ZC0301_DEBUG_LEVEL;
+module_param(debug, ushort, 0644);
+MODULE_PARM_DESC(debug,
+                 "\n<n> Debugging information level, from 0 to 3:"
+                 "\n0 = none (use carefully)"
+                 "\n1 = critical errors"
+                 "\n2 = significant informations"
+                 "\n3 = more verbose messages"
+                 "\nLevel 3 is useful for testing only, when only "
+                 "one device is used."
+                 "\nDefault value is "__MODULE_STRING(ZC0301_DEBUG_LEVEL)"."
+                 "\n");
+#endif
+
+/*****************************************************************************/
+
+static u32
+zc0301_request_buffers(struct zc0301_device* cam, u32 count,
+                       enum zc0301_io_method io)
+{
+	struct v4l2_pix_format* p = &(cam->sensor.pix_format);
+	struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
+	const size_t imagesize = cam->module_param.force_munmap ||
+	                         io == IO_READ ?
+	                         (p->width * p->height * p->priv) / 8 :
+	                         (r->width * r->height * p->priv) / 8;
+	void* buff = NULL;
+	u32 i;
+
+	if (count > ZC0301_MAX_FRAMES)
+		count = ZC0301_MAX_FRAMES;
+
+	cam->nbuffers = count;
+	while (cam->nbuffers > 0) {
+		if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize))))
+			break;
+		cam->nbuffers--;
+	}
+
+	for (i = 0; i < cam->nbuffers; i++) {
+		cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize);
+		cam->frame[i].buf.index = i;
+		cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize);
+		cam->frame[i].buf.length = imagesize;
+		cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		cam->frame[i].buf.sequence = 0;
+		cam->frame[i].buf.field = V4L2_FIELD_NONE;
+		cam->frame[i].buf.memory = V4L2_MEMORY_MMAP;
+		cam->frame[i].buf.flags = 0;
+	}
+
+	return cam->nbuffers;
+}
+
+
+static void zc0301_release_buffers(struct zc0301_device* cam)
+{
+	if (cam->nbuffers) {
+		vfree(cam->frame[0].bufmem);
+		cam->nbuffers = 0;
+	}
+	cam->frame_current = NULL;
+}
+
+
+static void zc0301_empty_framequeues(struct zc0301_device* cam)
+{
+	u32 i;
+
+	INIT_LIST_HEAD(&cam->inqueue);
+	INIT_LIST_HEAD(&cam->outqueue);
+
+	for (i = 0; i < ZC0301_MAX_FRAMES; i++) {
+		cam->frame[i].state = F_UNUSED;
+		cam->frame[i].buf.bytesused = 0;
+	}
+}
+
+
+static void zc0301_requeue_outqueue(struct zc0301_device* cam)
+{
+	struct zc0301_frame_t *i;
+
+	list_for_each_entry(i, &cam->outqueue, frame) {
+		i->state = F_QUEUED;
+		list_add(&i->frame, &cam->inqueue);
+	}
+
+	INIT_LIST_HEAD(&cam->outqueue);
+}
+
+
+static void zc0301_queue_unusedframes(struct zc0301_device* cam)
+{
+	unsigned long lock_flags;
+	u32 i;
+
+	for (i = 0; i < cam->nbuffers; i++)
+		if (cam->frame[i].state == F_UNUSED) {
+			cam->frame[i].state = F_QUEUED;
+			spin_lock_irqsave(&cam->queue_lock, lock_flags);
+			list_add_tail(&cam->frame[i].frame, &cam->inqueue);
+			spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+		}
+}
+
+/*****************************************************************************/
+
+int zc0301_write_reg(struct zc0301_device* cam, u16 index, u16 value)
+{
+	struct usb_device* udev = cam->usbdev;
+	int res;
+
+	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0xa0, 0x40,
+	                      value, index, NULL, 0, ZC0301_CTRL_TIMEOUT);
+	if (res < 0) {
+		DBG(3, "Failed to write a register (index 0x%04X, "
+		       "value 0x%02X, error %d)",index, value, res);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int zc0301_read_reg(struct zc0301_device* cam, u16 index)
+{
+	struct usb_device* udev = cam->usbdev;
+	u8* buff = cam->control_buffer;
+	int res;
+
+	res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0xa1, 0xc0,
+	                      0x0001, index, buff, 1, ZC0301_CTRL_TIMEOUT);
+	if (res < 0)
+		DBG(3, "Failed to read a register (index 0x%04X, error %d)",
+		    index, res);
+
+	PDBGG("Read: index 0x%04X, value: 0x%04X", index, (int)(*buff));
+
+	return (res >= 0) ? (int)(*buff) : -1;
+}
+
+
+int zc0301_i2c_read(struct zc0301_device* cam, u16 address, u8 length)
+{
+	int err = 0, res, r0, r1;
+
+	err += zc0301_write_reg(cam, 0x0092, address);
+	err += zc0301_write_reg(cam, 0x0090, 0x02);
+
+	msleep(1);
+
+	res = zc0301_read_reg(cam, 0x0091);
+	if (res < 0)
+		err += res;
+	r0 = zc0301_read_reg(cam, 0x0095);
+	if (r0 < 0)
+		err += r0;
+	r1 = zc0301_read_reg(cam, 0x0096);
+	if (r1 < 0)
+		err += r1;
+
+	res = (length <= 1) ? r0 : r0 | (r1 << 8);
+
+	if (err)
+		DBG(3, "I2C read failed at address 0x%04X, value: 0x%04X",
+		    address, res);
+
+
+	PDBGG("I2C read: address 0x%04X, value: 0x%04X", address, res);
+
+	return err ? -1 : res;
+}
+
+
+int zc0301_i2c_write(struct zc0301_device* cam, u16 address, u16 value)
+{
+	int err = 0, res;
+
+	err += zc0301_write_reg(cam, 0x0092, address);
+	err += zc0301_write_reg(cam, 0x0093, value & 0xff);
+	err += zc0301_write_reg(cam, 0x0094, value >> 8);
+	err += zc0301_write_reg(cam, 0x0090, 0x01);
+
+	msleep(1);
+
+	res = zc0301_read_reg(cam, 0x0091);
+	if (res < 0)
+		err += res;
+
+	if (err)
+		DBG(3, "I2C write failed at address 0x%04X, value: 0x%04X",
+		    address, value);
+
+	PDBGG("I2C write: address 0x%04X, value: 0x%04X", address, value);
+
+	return err ? -1 : 0;
+}
+
+/*****************************************************************************/
+
+static void zc0301_urb_complete(struct urb *urb, struct pt_regs* regs)
+{
+	struct zc0301_device* cam = urb->context;
+	struct zc0301_frame_t** f;
+	size_t imagesize;
+	u8 i;
+	int err = 0;
+
+	if (urb->status == -ENOENT)
+		return;
+
+	f = &cam->frame_current;
+
+	if (cam->stream == STREAM_INTERRUPT) {
+		cam->stream = STREAM_OFF;
+		if ((*f))
+			(*f)->state = F_QUEUED;
+		DBG(3, "Stream interrupted");
+		wake_up(&cam->wait_stream);
+	}
+
+	if (cam->state & DEV_DISCONNECTED)
+		return;
+
+	if (cam->state & DEV_MISCONFIGURED) {
+		wake_up_interruptible(&cam->wait_frame);
+		return;
+	}
+
+	if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue))
+		goto resubmit_urb;
+
+	if (!(*f))
+		(*f) = list_entry(cam->inqueue.next, struct zc0301_frame_t,
+		                  frame);
+
+	imagesize = (cam->sensor.pix_format.width *
+	             cam->sensor.pix_format.height *
+	             cam->sensor.pix_format.priv) / 8;
+
+	for (i = 0; i < urb->number_of_packets; i++) {
+		unsigned int len, status;
+		void *pos;
+		u16* soi;
+		u8 sof;
+
+		len = urb->iso_frame_desc[i].actual_length;
+		status = urb->iso_frame_desc[i].status;
+		pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
+
+		if (status) {
+			DBG(3, "Error in isochronous frame");
+			(*f)->state = F_ERROR;
+			continue;
+		}
+
+		sof = (*(soi = pos) == 0xd8ff);
+
+		PDBGG("Isochrnous frame: length %u, #%u i,", len, i);
+
+		if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR)
+start_of_frame:
+			if (sof) {
+				(*f)->state = F_GRABBING;
+				(*f)->buf.bytesused = 0;
+				do_gettimeofday(&(*f)->buf.timestamp);
+				DBG(3, "SOF detected: new video frame");
+			}
+
+		if ((*f)->state == F_GRABBING) {
+			if (sof && (*f)->buf.bytesused)
+					goto end_of_frame;
+
+			if ((*f)->buf.bytesused + len > imagesize) {
+				DBG(3, "Video frame size exceeded");
+				(*f)->state = F_ERROR;
+				continue;
+			}
+
+			memcpy((*f)->bufmem+(*f)->buf.bytesused, pos, len);
+			(*f)->buf.bytesused += len;
+
+			if ((*f)->buf.bytesused == imagesize) {
+				u32 b;
+end_of_frame:
+				b = (*f)->buf.bytesused;
+				(*f)->state = F_DONE;
+				(*f)->buf.sequence= ++cam->frame_count;
+				spin_lock(&cam->queue_lock);
+				list_move_tail(&(*f)->frame, &cam->outqueue);
+				if (!list_empty(&cam->inqueue))
+					(*f) = list_entry(cam->inqueue.next,
+					               struct zc0301_frame_t,
+					                  frame);
+				else
+					(*f) = NULL;
+				spin_unlock(&cam->queue_lock);
+				DBG(3, "Video frame captured: : %lu bytes",
+				       (unsigned long)(b));
+
+				if (!(*f))
+					goto resubmit_urb;
+
+				if (sof)
+					goto start_of_frame;
+			}
+		}
+	}
+
+resubmit_urb:
+	urb->dev = cam->usbdev;
+	err = usb_submit_urb(urb, GFP_ATOMIC);
+	if (err < 0 && err != -EPERM) {
+		cam->state |= DEV_MISCONFIGURED;
+		DBG(1, "usb_submit_urb() failed");
+	}
+
+	wake_up_interruptible(&cam->wait_frame);
+}
+
+
+static int zc0301_start_transfer(struct zc0301_device* cam)
+{
+	struct usb_device *udev = cam->usbdev;
+	struct urb* urb;
+	const unsigned int wMaxPacketSize[] = {0, 128, 192, 256, 384,
+	                                       512, 768, 1023};
+	const unsigned int psz = wMaxPacketSize[ZC0301_ALTERNATE_SETTING];
+	s8 i, j;
+	int err = 0;
+
+	for (i = 0; i < ZC0301_URBS; i++) {
+		cam->transfer_buffer[i] = kzalloc(ZC0301_ISO_PACKETS * psz,
+		                                  GFP_KERNEL);
+		if (!cam->transfer_buffer[i]) {
+			err = -ENOMEM;
+			DBG(1, "Not enough memory");
+			goto free_buffers;
+		}
+	}
+
+	for (i = 0; i < ZC0301_URBS; i++) {
+		urb = usb_alloc_urb(ZC0301_ISO_PACKETS, GFP_KERNEL);
+		cam->urb[i] = urb;
+		if (!urb) {
+			err = -ENOMEM;
+			DBG(1, "usb_alloc_urb() failed");
+			goto free_urbs;
+		}
+		urb->dev = udev;
+		urb->context = cam;
+		urb->pipe = usb_rcvisocpipe(udev, 1);
+		urb->transfer_flags = URB_ISO_ASAP;
+		urb->number_of_packets = ZC0301_ISO_PACKETS;
+		urb->complete = zc0301_urb_complete;
+		urb->transfer_buffer = cam->transfer_buffer[i];
+		urb->transfer_buffer_length = psz * ZC0301_ISO_PACKETS;
+		urb->interval = 1;
+		for (j = 0; j < ZC0301_ISO_PACKETS; j++) {
+			urb->iso_frame_desc[j].offset = psz * j;
+			urb->iso_frame_desc[j].length = psz;
+		}
+	}
+
+	err = usb_set_interface(udev, 0, ZC0301_ALTERNATE_SETTING);
+	if (err) {
+		DBG(1, "usb_set_interface() failed");
+		goto free_urbs;
+	}
+
+	cam->frame_current = NULL;
+
+	for (i = 0; i < ZC0301_URBS; i++) {
+		err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
+		if (err) {
+			for (j = i-1; j >= 0; j--)
+				usb_kill_urb(cam->urb[j]);
+			DBG(1, "usb_submit_urb() failed, error %d", err);
+			goto free_urbs;
+		}
+	}
+
+	return 0;
+
+free_urbs:
+	for (i = 0; (i < ZC0301_URBS) &&  cam->urb[i]; i++)
+		usb_free_urb(cam->urb[i]);
+
+free_buffers:
+	for (i = 0; (i < ZC0301_URBS) && cam->transfer_buffer[i]; i++)
+		kfree(cam->transfer_buffer[i]);
+
+	return err;
+}
+
+
+static int zc0301_stop_transfer(struct zc0301_device* cam)
+{
+	struct usb_device *udev = cam->usbdev;
+	s8 i;
+	int err = 0;
+
+	if (cam->state & DEV_DISCONNECTED)
+		return 0;
+
+	for (i = ZC0301_URBS-1; i >= 0; i--) {
+		usb_kill_urb(cam->urb[i]);
+		usb_free_urb(cam->urb[i]);
+		kfree(cam->transfer_buffer[i]);
+	}
+
+	err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */
+	if (err)
+		DBG(3, "usb_set_interface() failed");
+
+	return err;
+}
+
+
+static int zc0301_stream_interrupt(struct zc0301_device* cam)
+{
+	long timeout;
+
+	cam->stream = STREAM_INTERRUPT;
+	timeout = wait_event_timeout(cam->wait_stream,
+	                             (cam->stream == STREAM_OFF) ||
+	                             (cam->state & DEV_DISCONNECTED),
+	                             ZC0301_URB_TIMEOUT);
+	if (cam->state & DEV_DISCONNECTED)
+		return -ENODEV;
+	else if (cam->stream != STREAM_OFF) {
+		cam->state |= DEV_MISCONFIGURED;
+		DBG(1, "URB timeout reached. The camera is misconfigured. To "
+		       "use it, close and open /dev/video%d again.",
+		    cam->v4ldev->minor);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/*****************************************************************************/
+
+static int
+zc0301_set_compression(struct zc0301_device* cam,
+                       struct v4l2_jpegcompression* compression)
+{
+	int r, err = 0;
+
+	if ((r = zc0301_read_reg(cam, 0x0008)) < 0)
+		err += r;
+	err += zc0301_write_reg(cam, 0x0008, r | 0x11 | compression->quality);
+
+	return err ? -EIO : 0;
+}
+
+
+static int zc0301_init(struct zc0301_device* cam)
+{
+	struct zc0301_sensor* s = &cam->sensor;
+	struct v4l2_control ctrl;
+	struct v4l2_queryctrl *qctrl;
+	struct v4l2_rect* rect;
+	u8 i = 0;
+	int err = 0;
+
+	if (!(cam->state & DEV_INITIALIZED)) {
+		init_waitqueue_head(&cam->open);
+		qctrl = s->qctrl;
+		rect = &(s->cropcap.defrect);
+		cam->compression.quality = ZC0301_COMPRESSION_QUALITY;
+	} else { /* use current values */
+		qctrl = s->_qctrl;
+		rect = &(s->_rect);
+	}
+
+	if (s->init) {
+		err = s->init(cam);
+		if (err) {
+			DBG(3, "Sensor initialization failed");
+			return err;
+		}
+	}
+
+	if ((err = zc0301_set_compression(cam, &cam->compression))) {
+		DBG(3, "set_compression() failed");
+		return err;
+	}
+
+	if (s->set_crop)
+		if ((err = s->set_crop(cam, rect))) {
+			DBG(3, "set_crop() failed");
+			return err;
+		}
+
+	if (s->set_ctrl) {
+		for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+			if (s->qctrl[i].id != 0 &&
+			    !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) {
+				ctrl.id = s->qctrl[i].id;
+				ctrl.value = qctrl[i].default_value;
+				err = s->set_ctrl(cam, &ctrl);
+				if (err) {
+					DBG(3, "Set %s control failed",
+					    s->qctrl[i].name);
+					return err;
+				}
+				DBG(3, "Image sensor supports '%s' control",
+				    s->qctrl[i].name);
+			}
+	}
+
+	if (!(cam->state & DEV_INITIALIZED)) {
+		mutex_init(&cam->fileop_mutex);
+		spin_lock_init(&cam->queue_lock);
+		init_waitqueue_head(&cam->wait_frame);
+		init_waitqueue_head(&cam->wait_stream);
+		cam->nreadbuffers = 2;
+		memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl));
+		memcpy(&(s->_rect), &(s->cropcap.defrect),
+		       sizeof(struct v4l2_rect));
+		cam->state |= DEV_INITIALIZED;
+	}
+
+	DBG(2, "Initialization succeeded");
+	return 0;
+}
+
+
+static void zc0301_release_resources(struct zc0301_device* cam)
+{
+	DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
+	video_set_drvdata(cam->v4ldev, NULL);
+	video_unregister_device(cam->v4ldev);
+	kfree(cam->control_buffer);
+}
+
+/*****************************************************************************/
+
+static int zc0301_open(struct inode* inode, struct file* filp)
+{
+	struct zc0301_device* cam;
+	int err = 0;
+
+	/*
+	   This is the only safe way to prevent race conditions with
+	   disconnect
+	*/
+	if (!down_read_trylock(&zc0301_disconnect))
+		return -ERESTARTSYS;
+
+	cam = video_get_drvdata(video_devdata(filp));
+
+	if (mutex_lock_interruptible(&cam->dev_mutex)) {
+		up_read(&zc0301_disconnect);
+		return -ERESTARTSYS;
+	}
+
+	if (cam->users) {
+		DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+		if ((filp->f_flags & O_NONBLOCK) ||
+		    (filp->f_flags & O_NDELAY)) {
+			err = -EWOULDBLOCK;
+			goto out;
+		}
+		mutex_unlock(&cam->dev_mutex);
+		err = wait_event_interruptible_exclusive(cam->open,
+		                                  cam->state & DEV_DISCONNECTED
+		                                         || !cam->users);
+		if (err) {
+			up_read(&zc0301_disconnect);
+			return err;
+		}
+		if (cam->state & DEV_DISCONNECTED) {
+			up_read(&zc0301_disconnect);
+			return -ENODEV;
+		}
+		mutex_lock(&cam->dev_mutex);
+	}
+
+
+	if (cam->state & DEV_MISCONFIGURED) {
+		err = zc0301_init(cam);
+		if (err) {
+			DBG(1, "Initialization failed again. "
+			       "I will retry on next open().");
+			goto out;
+		}
+		cam->state &= ~DEV_MISCONFIGURED;
+	}
+
+	if ((err = zc0301_start_transfer(cam)))
+		goto out;
+
+	filp->private_data = cam;
+	cam->users++;
+	cam->io = IO_NONE;
+	cam->stream = STREAM_OFF;
+	cam->nbuffers = 0;
+	cam->frame_count = 0;
+	zc0301_empty_framequeues(cam);
+
+	DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
+
+out:
+	mutex_unlock(&cam->dev_mutex);
+	up_read(&zc0301_disconnect);
+	return err;
+}
+
+
+static int zc0301_release(struct inode* inode, struct file* filp)
+{
+	struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+
+	mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
+
+	zc0301_stop_transfer(cam);
+
+	zc0301_release_buffers(cam);
+
+	if (cam->state & DEV_DISCONNECTED) {
+		zc0301_release_resources(cam);
+		usb_put_dev(cam->usbdev);
+		mutex_unlock(&cam->dev_mutex);
+		kfree(cam);
+		return 0;
+	}
+
+	cam->users--;
+	wake_up_interruptible_nr(&cam->open, 1);
+
+	DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
+
+	mutex_unlock(&cam->dev_mutex);
+
+	return 0;
+}
+
+
+static ssize_t
+zc0301_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
+{
+	struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+	struct zc0301_frame_t* f, * i;
+	unsigned long lock_flags;
+	long timeout;
+	int err = 0;
+
+	if (mutex_lock_interruptible(&cam->fileop_mutex))
+		return -ERESTARTSYS;
+
+	if (cam->state & DEV_DISCONNECTED) {
+		DBG(1, "Device not present");
+		mutex_unlock(&cam->fileop_mutex);
+		return -ENODEV;
+	}
+
+	if (cam->state & DEV_MISCONFIGURED) {
+		DBG(1, "The camera is misconfigured. Close and open it "
+		       "again.");
+		mutex_unlock(&cam->fileop_mutex);
+		return -EIO;
+	}
+
+	if (cam->io == IO_MMAP) {
+		DBG(3, "Close and open the device again to choose the read "
+		       "method");
+		mutex_unlock(&cam->fileop_mutex);
+		return -EINVAL;
+	}
+
+	if (cam->io == IO_NONE) {
+		if (!zc0301_request_buffers(cam, cam->nreadbuffers, IO_READ)) {
+			DBG(1, "read() failed, not enough memory");
+			mutex_unlock(&cam->fileop_mutex);
+			return -ENOMEM;
+		}
+		cam->io = IO_READ;
+		cam->stream = STREAM_ON;
+	}
+
+	if (list_empty(&cam->inqueue)) {
+		if (!list_empty(&cam->outqueue))
+			zc0301_empty_framequeues(cam);
+		zc0301_queue_unusedframes(cam);
+	}
+
+	if (!count) {
+		mutex_unlock(&cam->fileop_mutex);
+		return 0;
+	}
+
+	if (list_empty(&cam->outqueue)) {
+		if (filp->f_flags & O_NONBLOCK) {
+			mutex_unlock(&cam->fileop_mutex);
+			return -EAGAIN;
+		}
+		timeout = wait_event_interruptible_timeout
+		          ( cam->wait_frame,
+		            (!list_empty(&cam->outqueue)) ||
+		            (cam->state & DEV_DISCONNECTED) ||
+		            (cam->state & DEV_MISCONFIGURED),
+		            cam->module_param.frame_timeout *
+		            1000 * msecs_to_jiffies(1) );
+		if (timeout < 0) {
+			mutex_unlock(&cam->fileop_mutex);
+			return timeout;
+		}
+		if (cam->state & DEV_DISCONNECTED) {
+			mutex_unlock(&cam->fileop_mutex);
+			return -ENODEV;
+		}
+		if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
+			mutex_unlock(&cam->fileop_mutex);
+			return -EIO;
+		}
+	}
+
+	f = list_entry(cam->outqueue.prev, struct zc0301_frame_t, frame);
+
+	if (count > f->buf.bytesused)
+		count = f->buf.bytesused;
+
+	if (copy_to_user(buf, f->bufmem, count)) {
+		err = -EFAULT;
+		goto exit;
+	}
+	*f_pos += count;
+
+exit:
+	spin_lock_irqsave(&cam->queue_lock, lock_flags);
+	list_for_each_entry(i, &cam->outqueue, frame)
+		i->state = F_UNUSED;
+	INIT_LIST_HEAD(&cam->outqueue);
+	spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+
+	zc0301_queue_unusedframes(cam);
+
+	PDBGG("Frame #%lu, bytes read: %zu",
+	      (unsigned long)f->buf.index, count);
+
+	mutex_unlock(&cam->fileop_mutex);
+
+	return err ? err : count;
+}
+
+
+static unsigned int zc0301_poll(struct file *filp, poll_table *wait)
+{
+	struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+	struct zc0301_frame_t* f;
+	unsigned long lock_flags;
+	unsigned int mask = 0;
+
+	if (mutex_lock_interruptible(&cam->fileop_mutex))
+		return POLLERR;
+
+	if (cam->state & DEV_DISCONNECTED) {
+		DBG(1, "Device not present");
+		goto error;
+	}
+
+	if (cam->state & DEV_MISCONFIGURED) {
+		DBG(1, "The camera is misconfigured. Close and open it "
+		       "again.");
+		goto error;
+	}
+
+	if (cam->io == IO_NONE) {
+		if (!zc0301_request_buffers(cam, cam->nreadbuffers, IO_READ)) {
+			DBG(1, "poll() failed, not enough memory");
+			goto error;
+		}
+		cam->io = IO_READ;
+		cam->stream = STREAM_ON;
+	}
+
+	if (cam->io == IO_READ) {
+		spin_lock_irqsave(&cam->queue_lock, lock_flags);
+		list_for_each_entry(f, &cam->outqueue, frame)
+			f->state = F_UNUSED;
+		INIT_LIST_HEAD(&cam->outqueue);
+		spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+		zc0301_queue_unusedframes(cam);
+	}
+
+	poll_wait(filp, &cam->wait_frame, wait);
+
+	if (!list_empty(&cam->outqueue))
+		mask |= POLLIN | POLLRDNORM;
+
+	mutex_unlock(&cam->fileop_mutex);
+
+	return mask;
+
+error:
+	mutex_unlock(&cam->fileop_mutex);
+	return POLLERR;
+}
+
+
+static void zc0301_vm_open(struct vm_area_struct* vma)
+{
+	struct zc0301_frame_t* f = vma->vm_private_data;
+	f->vma_use_count++;
+}
+
+
+static void zc0301_vm_close(struct vm_area_struct* vma)
+{
+	/* NOTE: buffers are not freed here */
+	struct zc0301_frame_t* f = vma->vm_private_data;
+	f->vma_use_count--;
+}
+
+
+static struct vm_operations_struct zc0301_vm_ops = {
+	.open = zc0301_vm_open,
+	.close = zc0301_vm_close,
+};
+
+
+static int zc0301_mmap(struct file* filp, struct vm_area_struct *vma)
+{
+	struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+	unsigned long size = vma->vm_end - vma->vm_start,
+	              start = vma->vm_start;
+	void *pos;
+	u32 i;
+
+	if (mutex_lock_interruptible(&cam->fileop_mutex))
+		return -ERESTARTSYS;
+
+	if (cam->state & DEV_DISCONNECTED) {
+		DBG(1, "Device not present");
+		mutex_unlock(&cam->fileop_mutex);
+		return -ENODEV;
+	}
+
+	if (cam->state & DEV_MISCONFIGURED) {
+		DBG(1, "The camera is misconfigured. Close and open it "
+		       "again.");
+		mutex_unlock(&cam->fileop_mutex);
+		return -EIO;
+	}
+
+	if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
+	    size != PAGE_ALIGN(cam->frame[0].buf.length)) {
+		mutex_unlock(&cam->fileop_mutex);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < cam->nbuffers; i++) {
+		if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff)
+			break;
+	}
+	if (i == cam->nbuffers) {
+		mutex_unlock(&cam->fileop_mutex);
+		return -EINVAL;
+	}
+
+	vma->vm_flags |= VM_IO;
+	vma->vm_flags |= VM_RESERVED;
+
+	pos = cam->frame[i].bufmem;
+	while (size > 0) { /* size is page-aligned */
+		if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
+			mutex_unlock(&cam->fileop_mutex);
+			return -EAGAIN;
+		}
+		start += PAGE_SIZE;
+		pos += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+
+	vma->vm_ops = &zc0301_vm_ops;
+	vma->vm_private_data = &cam->frame[i];
+
+	zc0301_vm_open(vma);
+
+	mutex_unlock(&cam->fileop_mutex);
+
+	return 0;
+}
+
+/*****************************************************************************/
+
+static int
+zc0301_vidioc_querycap(struct zc0301_device* cam, void __user * arg)
+{
+	struct v4l2_capability cap = {
+		.driver = "zc0301",
+		.version = ZC0301_MODULE_VERSION_CODE,
+		.capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+		                V4L2_CAP_STREAMING,
+	};
+
+	strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
+	if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
+		strlcpy(cap.bus_info, cam->usbdev->dev.bus_id,
+		        sizeof(cap.bus_info));
+
+	if (copy_to_user(arg, &cap, sizeof(cap)))
+		return -EFAULT;
+
+	return 0;
+}
+
+
+static int
+zc0301_vidioc_enuminput(struct zc0301_device* cam, void __user * arg)
+{
+	struct v4l2_input i;
+
+	if (copy_from_user(&i, arg, sizeof(i)))
+		return -EFAULT;
+
+	if (i.index)
+		return -EINVAL;
+
+	memset(&i, 0, sizeof(i));
+	strcpy(i.name, "Camera");
+	i.type = V4L2_INPUT_TYPE_CAMERA;
+
+	if (copy_to_user(arg, &i, sizeof(i)))
+		return -EFAULT;
+
+	return 0;
+}
+
+
+static int
+zc0301_vidioc_g_input(struct zc0301_device* cam, void __user * arg)
+{
+	int index = 0;
+
+	if (copy_to_user(arg, &index, sizeof(index)))
+		return -EFAULT;
+
+	return 0;
+}
+
+
+static int
+zc0301_vidioc_s_input(struct zc0301_device* cam, void __user * arg)
+{
+	int index;
+
+	if (copy_from_user(&index, arg, sizeof(index)))
+		return -EFAULT;
+
+	if (index != 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+
+static int
+zc0301_vidioc_query_ctrl(struct zc0301_device* cam, void __user * arg)
+{
+	struct zc0301_sensor* s = &cam->sensor;
+	struct v4l2_queryctrl qc;
+	u8 i;
+
+	if (copy_from_user(&qc, arg, sizeof(qc)))
+		return -EFAULT;
+
+	for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+		if (qc.id && qc.id == s->qctrl[i].id) {
+			memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
+			if (copy_to_user(arg, &qc, sizeof(qc)))
+				return -EFAULT;
+			return 0;
+		}
+
+	return -EINVAL;
+}
+
+
+static int
+zc0301_vidioc_g_ctrl(struct zc0301_device* cam, void __user * arg)
+{
+	struct zc0301_sensor* s = &cam->sensor;
+	struct v4l2_control ctrl;
+	int err = 0;
+	u8 i;
+
+	if (!s->get_ctrl && !s->set_ctrl)
+		return -EINVAL;
+
+	if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
+		return -EFAULT;
+
+	if (!s->get_ctrl) {
+		for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+			if (ctrl.id == s->qctrl[i].id) {
+				ctrl.value = s->_qctrl[i].default_value;
+				goto exit;
+			}
+		return -EINVAL;
+	} else
+		err = s->get_ctrl(cam, &ctrl);
+
+exit:
+	if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
+		return -EFAULT;
+
+	return err;
+}
+
+
+static int
+zc0301_vidioc_s_ctrl(struct zc0301_device* cam, void __user * arg)
+{
+	struct zc0301_sensor* s = &cam->sensor;
+	struct v4l2_control ctrl;
+	u8 i;
+	int err = 0;
+
+	if (!s->set_ctrl)
+		return -EINVAL;
+
+	if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
+		return -EFAULT;
+
+	for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+		if (ctrl.id == s->qctrl[i].id) {
+			if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
+				return -EINVAL;
+			if (ctrl.value < s->qctrl[i].minimum ||
+			    ctrl.value > s->qctrl[i].maximum)
+				return -ERANGE;
+			ctrl.value -= ctrl.value % s->qctrl[i].step;
+			break;
+		}
+
+	if ((err = s->set_ctrl(cam, &ctrl)))
+		return err;
+
+	s->_qctrl[i].default_value = ctrl.value;
+
+	return 0;
+}
+
+
+static int
+zc0301_vidioc_cropcap(struct zc0301_device* cam, void __user * arg)
+{
+	struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
+
+	cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	cc->pixelaspect.numerator = 1;
+	cc->pixelaspect.denominator = 1;
+
+	if (copy_to_user(arg, cc, sizeof(*cc)))
+		return -EFAULT;
+
+	return 0;
+}
+
+
+static int
+zc0301_vidioc_g_crop(struct zc0301_device* cam, void __user * arg)
+{
+	struct zc0301_sensor* s = &cam->sensor;
+	struct v4l2_crop crop = {
+		.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+	};
+
+	memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
+
+	if (copy_to_user(arg, &crop, sizeof(crop)))
+		return -EFAULT;
+
+	return 0;
+}
+
+
+static int
+zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg)
+{
+	struct zc0301_sensor* s = &cam->sensor;
+	struct v4l2_crop crop;
+	struct v4l2_rect* rect;
+	struct v4l2_rect* bounds = &(s->cropcap.bounds);
+	const enum zc0301_stream_state stream = cam->stream;
+	const u32 nbuffers = cam->nbuffers;
+	u32 i;
+	int err = 0;
+
+	if (copy_from_user(&crop, arg, sizeof(crop)))
+		return -EFAULT;
+
+	rect = &(crop.c);
+
+	if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (cam->module_param.force_munmap)
+		for (i = 0; i < cam->nbuffers; i++)
+			if (cam->frame[i].vma_use_count) {
+				DBG(3, "VIDIOC_S_CROP failed. "
+				       "Unmap the buffers first.");
+				return -EINVAL;
+			}
+
+	if (!s->set_crop) {
+		memcpy(rect, &(s->_rect), sizeof(*rect));
+		if (copy_to_user(arg, &crop, sizeof(crop)))
+			return -EFAULT;
+		return 0;
+	}
+
+	rect->left &= ~7L;
+	rect->top &= ~7L;
+	if (rect->width < 8)
+		rect->width = 8;
+	if (rect->height < 8)
+		rect->height = 8;
+	if (rect->width > bounds->width)
+		rect->width = bounds->width;
+	if (rect->height > bounds->height)
+		rect->height = bounds->height;
+	if (rect->left < bounds->left)
+		rect->left = bounds->left;
+	if (rect->top < bounds->top)
+		rect->top = bounds->top;
+	if (rect->left + rect->width > bounds->left + bounds->width)
+		rect->left = bounds->left+bounds->width - rect->width;
+	if (rect->top + rect->height > bounds->top + bounds->height)
+		rect->top = bounds->top+bounds->height - rect->height;
+	rect->width &= ~7L;
+	rect->height &= ~7L;
+
+	if (cam->stream == STREAM_ON)
+		if ((err = zc0301_stream_interrupt(cam)))
+			return err;
+
+	if (copy_to_user(arg, &crop, sizeof(crop))) {
+		cam->stream = stream;
+		return -EFAULT;
+	}
+
+	if (cam->module_param.force_munmap || cam->io == IO_READ)
+		zc0301_release_buffers(cam);
+
+	if (s->set_crop)
+		err += s->set_crop(cam, rect);
+
+	if (err) { /* atomic, no rollback in ioctl() */
+		cam->state |= DEV_MISCONFIGURED;
+		DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "
+		       "use the camera, close and open /dev/video%d again.",
+		    cam->v4ldev->minor);
+		return -EIO;
+	}
+
+	s->pix_format.width = rect->width;
+	s->pix_format.height = rect->height;
+	memcpy(&(s->_rect), rect, sizeof(*rect));
+
+	if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
+	    nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) {
+		cam->state |= DEV_MISCONFIGURED;
+		DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "
+		       "use the camera, close and open /dev/video%d again.",
+		    cam->v4ldev->minor);
+		return -ENOMEM;
+	}
+
+	if (cam->io == IO_READ)
+		zc0301_empty_framequeues(cam);
+	else if (cam->module_param.force_munmap)
+		zc0301_requeue_outqueue(cam);
+
+	cam->stream = stream;
+
+	return 0;
+}
+
+
+static int
+zc0301_vidioc_enum_fmt(struct zc0301_device* cam, void __user * arg)
+{
+	struct v4l2_fmtdesc fmtd;
+
+	if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
+		return -EFAULT;
+
+	if (fmtd.index == 0) {
+		strcpy(fmtd.description, "JPEG");
+		fmtd.pixelformat = V4L2_PIX_FMT_JPEG;
+		fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
+	} else
+		return -EINVAL;
+
+	fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
+
+	if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
+		return -EFAULT;
+
+	return 0;
+}
+
+
+static int
+zc0301_vidioc_g_fmt(struct zc0301_device* cam, void __user * arg)
+{
+	struct v4l2_format format;
+	struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
+
+	if (copy_from_user(&format, arg, sizeof(format)))
+		return -EFAULT;
+
+	if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	pfmt->bytesperline = 0;
+	pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
+	pfmt->field = V4L2_FIELD_NONE;
+	memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
+
+	if (copy_to_user(arg, &format, sizeof(format)))
+		return -EFAULT;
+
+	return 0;
+}
+
+
+static int
+zc0301_vidioc_try_s_fmt(struct zc0301_device* cam, unsigned int cmd,
+                        void __user * arg)
+{
+	struct zc0301_sensor* s = &cam->sensor;
+	struct v4l2_format format;
+	struct v4l2_pix_format* pix;
+	struct v4l2_pix_format* pfmt = &(s->pix_format);
+	struct v4l2_rect* bounds = &(s->cropcap.bounds);
+	struct v4l2_rect rect;
+	const enum zc0301_stream_state stream = cam->stream;
+	const u32 nbuffers = cam->nbuffers;
+	u32 i;
+	int err = 0;
+
+	if (copy_from_user(&format, arg, sizeof(format)))
+		return -EFAULT;
+
+	pix = &(format.fmt.pix);
+
+	if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	memcpy(&rect, &(s->_rect), sizeof(rect));
+
+	if (!s->set_crop) {
+		pix->width = rect.width;
+		pix->height = rect.height;
+	} else {
+		rect.width = pix->width;
+		rect.height = pix->height;
+	}
+
+	if (rect.width < 8)
+		rect.width = 8;
+	if (rect.height < 8)
+		rect.height = 8;
+	if (rect.width > bounds->left + bounds->width - rect.left)
+		rect.width = bounds->left + bounds->width - rect.left;
+	if (rect.height > bounds->top + bounds->height - rect.top)
+		rect.height = bounds->top + bounds->height - rect.top;
+	rect.width &= ~7L;
+	rect.height &= ~7L;
+
+	pix->width = rect.width;
+	pix->height = rect.height;
+	pix->pixelformat = pfmt->pixelformat;
+	pix->priv = pfmt->priv;
+	pix->colorspace = pfmt->colorspace;
+	pix->bytesperline = 0;
+	pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
+	pix->field = V4L2_FIELD_NONE;
+
+	if (cmd == VIDIOC_TRY_FMT) {
+		if (copy_to_user(arg, &format, sizeof(format)))
+			return -EFAULT;
+		return 0;
+	}
+
+	if (cam->module_param.force_munmap)
+		for (i = 0; i < cam->nbuffers; i++)
+			if (cam->frame[i].vma_use_count) {
+				DBG(3, "VIDIOC_S_FMT failed. "
+				       "Unmap the buffers first.");
+				return -EINVAL;
+			}
+
+	if (cam->stream == STREAM_ON)
+		if ((err = zc0301_stream_interrupt(cam)))
+			return err;
+
+	if (copy_to_user(arg, &format, sizeof(format))) {
+		cam->stream = stream;
+		return -EFAULT;
+	}
+
+	if (cam->module_param.force_munmap || cam->io == IO_READ)
+		zc0301_release_buffers(cam);
+
+	if (s->set_crop)
+		err += s->set_crop(cam, &rect);
+
+	if (err) { /* atomic, no rollback in ioctl() */
+		cam->state |= DEV_MISCONFIGURED;
+		DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "
+		       "use the camera, close and open /dev/video%d again.",
+		    cam->v4ldev->minor);
+		return -EIO;
+	}
+
+	memcpy(pfmt, pix, sizeof(*pix));
+	memcpy(&(s->_rect), &rect, sizeof(rect));
+
+	if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
+	    nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) {
+		cam->state |= DEV_MISCONFIGURED;
+		DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "
+		       "use the camera, close and open /dev/video%d again.",
+		    cam->v4ldev->minor);
+		return -ENOMEM;
+	}
+
+	if (cam->io == IO_READ)
+		zc0301_empty_framequeues(cam);
+	else if (cam->module_param.force_munmap)
+		zc0301_requeue_outqueue(cam);
+
+	cam->stream = stream;
+
+	return 0;
+}
+
+
+static int
+zc0301_vidioc_g_jpegcomp(struct zc0301_device* cam, void __user * arg)
+{
+	if (copy_to_user(arg, &cam->compression, sizeof(cam->compression)))
+		return -EFAULT;
+
+	return 0;
+}
+
+
+static int
+zc0301_vidioc_s_jpegcomp(struct zc0301_device* cam, void __user * arg)
+{
+	struct v4l2_jpegcompression jc;
+	const enum zc0301_stream_state stream = cam->stream;
+	int err = 0;
+
+	if (copy_from_user(&jc, arg, sizeof(jc)))
+		return -EFAULT;
+
+	if (jc.quality != 0)
+		return -EINVAL;
+
+	if (cam->stream == STREAM_ON)
+		if ((err = zc0301_stream_interrupt(cam)))
+			return err;
+
+	err += zc0301_set_compression(cam, &jc);
+	if (err) { /* atomic, no rollback in ioctl() */
+		cam->state |= DEV_MISCONFIGURED;
+		DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
+		       "problems. To use the camera, close and open "
+		       "/dev/video%d again.", cam->v4ldev->minor);
+		return -EIO;
+	}
+
+	cam->compression.quality = jc.quality;
+
+	cam->stream = stream;
+
+	return 0;
+}
+
+
+static int
+zc0301_vidioc_reqbufs(struct zc0301_device* cam, void __user * arg)
+{
+	struct v4l2_requestbuffers rb;
+	u32 i;
+	int err;
+
+	if (copy_from_user(&rb, arg, sizeof(rb)))
+		return -EFAULT;
+
+	if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+	    rb.memory != V4L2_MEMORY_MMAP)
+		return -EINVAL;
+
+	if (cam->io == IO_READ) {
+		DBG(3, "Close and open the device again to choose the mmap "
+		       "I/O method");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < cam->nbuffers; i++)
+		if (cam->frame[i].vma_use_count) {
+			DBG(3, "VIDIOC_REQBUFS failed. "
+			       "Previous buffers are still mapped.");
+			return -EINVAL;
+		}
+
+	if (cam->stream == STREAM_ON)
+		if ((err = zc0301_stream_interrupt(cam)))
+			return err;
+
+	zc0301_empty_framequeues(cam);
+
+	zc0301_release_buffers(cam);
+	if (rb.count)
+		rb.count = zc0301_request_buffers(cam, rb.count, IO_MMAP);
+
+	if (copy_to_user(arg, &rb, sizeof(rb))) {
+		zc0301_release_buffers(cam);
+		cam->io = IO_NONE;
+		return -EFAULT;
+	}
+
+	cam->io = rb.count ? IO_MMAP : IO_NONE;
+
+	return 0;
+}
+
+
+static int
+zc0301_vidioc_querybuf(struct zc0301_device* cam, void __user * arg)
+{
+	struct v4l2_buffer b;
+
+	if (copy_from_user(&b, arg, sizeof(b)))
+		return -EFAULT;
+
+	if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+	    b.index >= cam->nbuffers || cam->io != IO_MMAP)
+		return -EINVAL;
+
+	memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
+
+	if (cam->frame[b.index].vma_use_count)
+		b.flags |= V4L2_BUF_FLAG_MAPPED;
+
+	if (cam->frame[b.index].state == F_DONE)
+		b.flags |= V4L2_BUF_FLAG_DONE;
+	else if (cam->frame[b.index].state != F_UNUSED)
+		b.flags |= V4L2_BUF_FLAG_QUEUED;
+
+	if (copy_to_user(arg, &b, sizeof(b)))
+		return -EFAULT;
+
+	return 0;
+}
+
+
+static int
+zc0301_vidioc_qbuf(struct zc0301_device* cam, void __user * arg)
+{
+	struct v4l2_buffer b;
+	unsigned long lock_flags;
+
+	if (copy_from_user(&b, arg, sizeof(b)))
+		return -EFAULT;
+
+	if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+	    b.index >= cam->nbuffers || cam->io != IO_MMAP)
+		return -EINVAL;
+
+	if (cam->frame[b.index].state != F_UNUSED)
+		return -EINVAL;
+
+	cam->frame[b.index].state = F_QUEUED;
+
+	spin_lock_irqsave(&cam->queue_lock, lock_flags);
+	list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
+	spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+
+	PDBGG("Frame #%lu queued", (unsigned long)b.index);
+
+	return 0;
+}
+
+
+static int
+zc0301_vidioc_dqbuf(struct zc0301_device* cam, struct file* filp,
+                    void __user * arg)
+{
+	struct v4l2_buffer b;
+	struct zc0301_frame_t *f;
+	unsigned long lock_flags;
+	long timeout;
+
+	if (copy_from_user(&b, arg, sizeof(b)))
+		return -EFAULT;
+
+	if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP)
+		return -EINVAL;
+
+	if (list_empty(&cam->outqueue)) {
+		if (cam->stream == STREAM_OFF)
+			return -EINVAL;
+		if (filp->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+		timeout = wait_event_interruptible_timeout
+		          ( cam->wait_frame,
+		            (!list_empty(&cam->outqueue)) ||
+		            (cam->state & DEV_DISCONNECTED) ||
+		            (cam->state & DEV_MISCONFIGURED),
+		            cam->module_param.frame_timeout *
+		            1000 * msecs_to_jiffies(1) );
+		if (timeout < 0)
+			return timeout;
+		if (cam->state & DEV_DISCONNECTED)
+			return -ENODEV;
+		if (!timeout || (cam->state & DEV_MISCONFIGURED))
+			return -EIO;
+	}
+
+	spin_lock_irqsave(&cam->queue_lock, lock_flags);
+	f = list_entry(cam->outqueue.next, struct zc0301_frame_t, frame);
+	list_del(cam->outqueue.next);
+	spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+
+	f->state = F_UNUSED;
+
+	memcpy(&b, &f->buf, sizeof(b));
+	if (f->vma_use_count)
+		b.flags |= V4L2_BUF_FLAG_MAPPED;
+
+	if (copy_to_user(arg, &b, sizeof(b)))
+		return -EFAULT;
+
+	PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index);
+
+	return 0;
+}
+
+
+static int
+zc0301_vidioc_streamon(struct zc0301_device* cam, void __user * arg)
+{
+	int type;
+
+	if (copy_from_user(&type, arg, sizeof(type)))
+		return -EFAULT;
+
+	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
+		return -EINVAL;
+
+	if (list_empty(&cam->inqueue))
+		return -EINVAL;
+
+	cam->stream = STREAM_ON;
+
+	DBG(3, "Stream on");
+
+	return 0;
+}
+
+
+static int
+zc0301_vidioc_streamoff(struct zc0301_device* cam, void __user * arg)
+{
+	int type, err;
+
+	if (copy_from_user(&type, arg, sizeof(type)))
+		return -EFAULT;
+
+	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
+		return -EINVAL;
+
+	if (cam->stream == STREAM_ON)
+		if ((err = zc0301_stream_interrupt(cam)))
+			return err;
+
+	zc0301_empty_framequeues(cam);
+
+	DBG(3, "Stream off");
+
+	return 0;
+}
+
+
+static int
+zc0301_vidioc_g_parm(struct zc0301_device* cam, void __user * arg)
+{
+	struct v4l2_streamparm sp;
+
+	if (copy_from_user(&sp, arg, sizeof(sp)))
+		return -EFAULT;
+
+	if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	sp.parm.capture.extendedmode = 0;
+	sp.parm.capture.readbuffers = cam->nreadbuffers;
+
+	if (copy_to_user(arg, &sp, sizeof(sp)))
+		return -EFAULT;
+
+	return 0;
+}
+
+
+static int
+zc0301_vidioc_s_parm(struct zc0301_device* cam, void __user * arg)
+{
+	struct v4l2_streamparm sp;
+
+	if (copy_from_user(&sp, arg, sizeof(sp)))
+		return -EFAULT;
+
+	if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	sp.parm.capture.extendedmode = 0;
+
+	if (sp.parm.capture.readbuffers == 0)
+		sp.parm.capture.readbuffers = cam->nreadbuffers;
+
+	if (sp.parm.capture.readbuffers > ZC0301_MAX_FRAMES)
+		sp.parm.capture.readbuffers = ZC0301_MAX_FRAMES;
+
+	if (copy_to_user(arg, &sp, sizeof(sp)))
+		return -EFAULT;
+
+	cam->nreadbuffers = sp.parm.capture.readbuffers;
+
+	return 0;
+}
+
+
+static int zc0301_ioctl_v4l2(struct inode* inode, struct file* filp,
+                             unsigned int cmd, void __user * arg)
+{
+	struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+
+	switch (cmd) {
+
+	case VIDIOC_QUERYCAP:
+		return zc0301_vidioc_querycap(cam, arg);
+
+	case VIDIOC_ENUMINPUT:
+		return zc0301_vidioc_enuminput(cam, arg);
+
+	case VIDIOC_G_INPUT:
+		return zc0301_vidioc_g_input(cam, arg);
+
+	case VIDIOC_S_INPUT:
+		return zc0301_vidioc_s_input(cam, arg);
+
+	case VIDIOC_QUERYCTRL:
+		return zc0301_vidioc_query_ctrl(cam, arg);
+
+	case VIDIOC_G_CTRL:
+		return zc0301_vidioc_g_ctrl(cam, arg);
+
+	case VIDIOC_S_CTRL_OLD:
+	case VIDIOC_S_CTRL:
+		return zc0301_vidioc_s_ctrl(cam, arg);
+
+	case VIDIOC_CROPCAP_OLD:
+	case VIDIOC_CROPCAP:
+		return zc0301_vidioc_cropcap(cam, arg);
+
+	case VIDIOC_G_CROP:
+		return zc0301_vidioc_g_crop(cam, arg);
+
+	case VIDIOC_S_CROP:
+		return zc0301_vidioc_s_crop(cam, arg);
+
+	case VIDIOC_ENUM_FMT:
+		return zc0301_vidioc_enum_fmt(cam, arg);
+
+	case VIDIOC_G_FMT:
+		return zc0301_vidioc_g_fmt(cam, arg);
+
+	case VIDIOC_TRY_FMT:
+	case VIDIOC_S_FMT:
+		return zc0301_vidioc_try_s_fmt(cam, cmd, arg);
+
+	case VIDIOC_G_JPEGCOMP:
+		return zc0301_vidioc_g_jpegcomp(cam, arg);
+
+	case VIDIOC_S_JPEGCOMP:
+		return zc0301_vidioc_s_jpegcomp(cam, arg);
+
+	case VIDIOC_REQBUFS:
+		return zc0301_vidioc_reqbufs(cam, arg);
+
+	case VIDIOC_QUERYBUF:
+		return zc0301_vidioc_querybuf(cam, arg);
+
+	case VIDIOC_QBUF:
+		return zc0301_vidioc_qbuf(cam, arg);
+
+	case VIDIOC_DQBUF:
+		return zc0301_vidioc_dqbuf(cam, filp, arg);
+
+	case VIDIOC_STREAMON:
+		return zc0301_vidioc_streamon(cam, arg);
+
+	case VIDIOC_STREAMOFF:
+		return zc0301_vidioc_streamoff(cam, arg);
+
+	case VIDIOC_G_PARM:
+		return zc0301_vidioc_g_parm(cam, arg);
+
+	case VIDIOC_S_PARM_OLD:
+	case VIDIOC_S_PARM:
+		return zc0301_vidioc_s_parm(cam, arg);
+
+	case VIDIOC_G_STD:
+	case VIDIOC_S_STD:
+	case VIDIOC_QUERYSTD:
+	case VIDIOC_ENUMSTD:
+	case VIDIOC_QUERYMENU:
+		return -EINVAL;
+
+	default:
+		return -EINVAL;
+
+	}
+}
+
+
+static int zc0301_ioctl(struct inode* inode, struct file* filp,
+                        unsigned int cmd, unsigned long arg)
+{
+	struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+	int err = 0;
+
+	if (mutex_lock_interruptible(&cam->fileop_mutex))
+		return -ERESTARTSYS;
+
+	if (cam->state & DEV_DISCONNECTED) {
+		DBG(1, "Device not present");
+		mutex_unlock(&cam->fileop_mutex);
+		return -ENODEV;
+	}
+
+	if (cam->state & DEV_MISCONFIGURED) {
+		DBG(1, "The camera is misconfigured. Close and open it "
+		       "again.");
+		mutex_unlock(&cam->fileop_mutex);
+		return -EIO;
+	}
+
+	V4LDBG(3, "zc0301", cmd);
+
+	err = zc0301_ioctl_v4l2(inode, filp, cmd, (void __user *)arg);
+
+	mutex_unlock(&cam->fileop_mutex);
+
+	return err;
+}
+
+
+static struct file_operations zc0301_fops = {
+	.owner =   THIS_MODULE,
+	.open =    zc0301_open,
+	.release = zc0301_release,
+	.ioctl =   zc0301_ioctl,
+	.read =    zc0301_read,
+	.poll =    zc0301_poll,
+	.mmap =    zc0301_mmap,
+	.llseek =  no_llseek,
+};
+
+/*****************************************************************************/
+
+static int
+zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
+{
+	struct usb_device *udev = interface_to_usbdev(intf);
+	struct zc0301_device* cam;
+	static unsigned int dev_nr = 0;
+	unsigned int i;
+	int err = 0;
+
+	if (!(cam = kzalloc(sizeof(struct zc0301_device), GFP_KERNEL)))
+		return -ENOMEM;
+
+	cam->usbdev = udev;
+
+	if (!(cam->control_buffer = kzalloc(4, GFP_KERNEL))) {
+		DBG(1, "kmalloc() failed");
+		err = -ENOMEM;
+		goto fail;
+	}
+
+	if (!(cam->v4ldev = video_device_alloc())) {
+		DBG(1, "video_device_alloc() failed");
+		err = -ENOMEM;
+		goto fail;
+	}
+
+	mutex_init(&cam->dev_mutex);
+
+	DBG(2, "ZC0301 Image Processor and Control Chip detected "
+	       "(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct);
+
+	for  (i = 0; zc0301_sensor_table[i]; i++) {
+		err = zc0301_sensor_table[i](cam);
+		if (!err)
+			break;
+	}
+
+	if (!err)
+		DBG(2, "%s image sensor detected", cam->sensor.name);
+	else {
+		DBG(1, "No supported image sensor detected");
+		err = -ENODEV;
+		goto fail;
+	}
+
+	if (zc0301_init(cam)) {
+		DBG(1, "Initialization failed. I will retry on open().");
+		cam->state |= DEV_MISCONFIGURED;
+	}
+
+	strcpy(cam->v4ldev->name, "ZC0301 PC Camera");
+	cam->v4ldev->owner = THIS_MODULE;
+	cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
+	cam->v4ldev->hardware = 0;
+	cam->v4ldev->fops = &zc0301_fops;
+	cam->v4ldev->minor = video_nr[dev_nr];
+	cam->v4ldev->release = video_device_release;
+	video_set_drvdata(cam->v4ldev, cam);
+
+	mutex_lock(&cam->dev_mutex);
+
+	err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
+	                            video_nr[dev_nr]);
+	if (err) {
+		DBG(1, "V4L2 device registration failed");
+		if (err == -ENFILE && video_nr[dev_nr] == -1)
+			DBG(1, "Free /dev/videoX node not found");
+		video_nr[dev_nr] = -1;
+		dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
+		mutex_unlock(&cam->dev_mutex);
+		goto fail;
+	}
+
+	DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
+
+	cam->module_param.force_munmap = force_munmap[dev_nr];
+	cam->module_param.frame_timeout = frame_timeout[dev_nr];
+
+	dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
+
+	usb_set_intfdata(intf, cam);
+
+	mutex_unlock(&cam->dev_mutex);
+
+	return 0;
+
+fail:
+	if (cam) {
+		kfree(cam->control_buffer);
+		if (cam->v4ldev)
+			video_device_release(cam->v4ldev);
+		kfree(cam);
+	}
+	return err;
+}
+
+
+static void zc0301_usb_disconnect(struct usb_interface* intf)
+{
+	struct zc0301_device* cam = usb_get_intfdata(intf);
+
+	if (!cam)
+		return;
+
+	down_write(&zc0301_disconnect);
+
+	mutex_lock(&cam->dev_mutex);
+
+	DBG(2, "Disconnecting %s...", cam->v4ldev->name);
+
+	wake_up_interruptible_all(&cam->open);
+
+	if (cam->users) {
+		DBG(2, "Device /dev/video%d is open! Deregistration and "
+		       "memory deallocation are deferred on close.",
+		    cam->v4ldev->minor);
+		cam->state |= DEV_MISCONFIGURED;
+		zc0301_stop_transfer(cam);
+		cam->state |= DEV_DISCONNECTED;
+		wake_up_interruptible(&cam->wait_frame);
+		wake_up(&cam->wait_stream);
+		usb_get_dev(cam->usbdev);
+	} else {
+		cam->state |= DEV_DISCONNECTED;
+		zc0301_release_resources(cam);
+	}
+
+	mutex_unlock(&cam->dev_mutex);
+
+	if (!cam->users)
+		kfree(cam);
+
+	up_write(&zc0301_disconnect);
+}
+
+
+static struct usb_driver zc0301_usb_driver = {
+	.name =       "zc0301",
+	.id_table =   zc0301_id_table,
+	.probe =      zc0301_usb_probe,
+	.disconnect = zc0301_usb_disconnect,
+};
+
+/*****************************************************************************/
+
+static int __init zc0301_module_init(void)
+{
+	int err = 0;
+
+	KDBG(2, ZC0301_MODULE_NAME " v" ZC0301_MODULE_VERSION);
+	KDBG(3, ZC0301_MODULE_AUTHOR);
+
+	if ((err = usb_register(&zc0301_usb_driver)))
+		KDBG(1, "usb_register() failed");
+
+	return err;
+}
+
+
+static void __exit zc0301_module_exit(void)
+{
+	usb_deregister(&zc0301_usb_driver);
+}
+
+
+module_init(zc0301_module_init);
+module_exit(zc0301_module_exit);
diff --git a/drivers/usb/media/zc0301_pas202bcb.c b/drivers/usb/media/zc0301_pas202bcb.c
new file mode 100644
index 0000000..9d282a2
--- /dev/null
+++ b/drivers/usb/media/zc0301_pas202bcb.c
@@ -0,0 +1,361 @@
+/***************************************************************************
+ * Plug-in for PAS202BCB image sensor connected to the ZC030! Image        *
+ * Processor and Control Chip                                              *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * Initialization values of the ZC0301 have been taken from the SPCA5XX    *
+ * driver maintained by Michel Xhaard <mxhaard@magic.fr>                   *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+/*
+   NOTE: Sensor controls are disabled for now, becouse changing them while
+         streaming sometimes results in out-of-sync video frames. We'll use
+         the default initialization, until we know how to stop and start video
+         in the chip. However, the image quality still looks good under various
+         light conditions.
+*/
+
+#include <linux/delay.h>
+#include "zc0301_sensor.h"
+
+
+static struct zc0301_sensor pas202bcb;
+
+
+static int pas202bcb_init(struct zc0301_device* cam)
+{
+	int err = 0;
+
+	err += zc0301_write_reg(cam, 0x0002, 0x00);
+	err += zc0301_write_reg(cam, 0x0003, 0x02);
+	err += zc0301_write_reg(cam, 0x0004, 0x80);
+	err += zc0301_write_reg(cam, 0x0005, 0x01);
+	err += zc0301_write_reg(cam, 0x0006, 0xE0);
+	err += zc0301_write_reg(cam, 0x0098, 0x00);
+	err += zc0301_write_reg(cam, 0x009A, 0x03);
+	err += zc0301_write_reg(cam, 0x011A, 0x00);
+	err += zc0301_write_reg(cam, 0x011C, 0x03);
+	err += zc0301_write_reg(cam, 0x009B, 0x01);
+	err += zc0301_write_reg(cam, 0x009C, 0xE6);
+	err += zc0301_write_reg(cam, 0x009D, 0x02);
+	err += zc0301_write_reg(cam, 0x009E, 0x86);
+
+	err += zc0301_i2c_write(cam, 0x02, 0x02);
+	err += zc0301_i2c_write(cam, 0x0A, 0x01);
+	err += zc0301_i2c_write(cam, 0x0B, 0x01);
+	err += zc0301_i2c_write(cam, 0x0D, 0x00);
+	err += zc0301_i2c_write(cam, 0x12, 0x05);
+	err += zc0301_i2c_write(cam, 0x13, 0x63);
+	err += zc0301_i2c_write(cam, 0x15, 0x70);
+
+	err += zc0301_write_reg(cam, 0x0101, 0xB7);
+	err += zc0301_write_reg(cam, 0x0100, 0x0D);
+	err += zc0301_write_reg(cam, 0x0189, 0x06);
+	err += zc0301_write_reg(cam, 0x01AD, 0x00);
+	err += zc0301_write_reg(cam, 0x01C5, 0x03);
+	err += zc0301_write_reg(cam, 0x01CB, 0x13);
+	err += zc0301_write_reg(cam, 0x0250, 0x08);
+	err += zc0301_write_reg(cam, 0x0301, 0x08);
+	err += zc0301_write_reg(cam, 0x018D, 0x70);
+	err += zc0301_write_reg(cam, 0x0008, 0x03);
+	err += zc0301_write_reg(cam, 0x01C6, 0x04);
+	err += zc0301_write_reg(cam, 0x01CB, 0x07);
+	err += zc0301_write_reg(cam, 0x0120, 0x11);
+	err += zc0301_write_reg(cam, 0x0121, 0x37);
+	err += zc0301_write_reg(cam, 0x0122, 0x58);
+	err += zc0301_write_reg(cam, 0x0123, 0x79);
+	err += zc0301_write_reg(cam, 0x0124, 0x91);
+	err += zc0301_write_reg(cam, 0x0125, 0xA6);
+	err += zc0301_write_reg(cam, 0x0126, 0xB8);
+	err += zc0301_write_reg(cam, 0x0127, 0xC7);
+	err += zc0301_write_reg(cam, 0x0128, 0xD3);
+	err += zc0301_write_reg(cam, 0x0129, 0xDE);
+	err += zc0301_write_reg(cam, 0x012A, 0xE6);
+	err += zc0301_write_reg(cam, 0x012B, 0xED);
+	err += zc0301_write_reg(cam, 0x012C, 0xF3);
+	err += zc0301_write_reg(cam, 0x012D, 0xF8);
+	err += zc0301_write_reg(cam, 0x012E, 0xFB);
+	err += zc0301_write_reg(cam, 0x012F, 0xFF);
+	err += zc0301_write_reg(cam, 0x0130, 0x26);
+	err += zc0301_write_reg(cam, 0x0131, 0x23);
+	err += zc0301_write_reg(cam, 0x0132, 0x20);
+	err += zc0301_write_reg(cam, 0x0133, 0x1C);
+	err += zc0301_write_reg(cam, 0x0134, 0x16);
+	err += zc0301_write_reg(cam, 0x0135, 0x13);
+	err += zc0301_write_reg(cam, 0x0136, 0x10);
+	err += zc0301_write_reg(cam, 0x0137, 0x0D);
+	err += zc0301_write_reg(cam, 0x0138, 0x0B);
+	err += zc0301_write_reg(cam, 0x0139, 0x09);
+	err += zc0301_write_reg(cam, 0x013A, 0x07);
+	err += zc0301_write_reg(cam, 0x013B, 0x06);
+	err += zc0301_write_reg(cam, 0x013C, 0x05);
+	err += zc0301_write_reg(cam, 0x013D, 0x04);
+	err += zc0301_write_reg(cam, 0x013E, 0x03);
+	err += zc0301_write_reg(cam, 0x013F, 0x02);
+	err += zc0301_write_reg(cam, 0x010A, 0x4C);
+	err += zc0301_write_reg(cam, 0x010B, 0xF5);
+	err += zc0301_write_reg(cam, 0x010C, 0xFF);
+	err += zc0301_write_reg(cam, 0x010D, 0xF9);
+	err += zc0301_write_reg(cam, 0x010E, 0x51);
+	err += zc0301_write_reg(cam, 0x010F, 0xF5);
+	err += zc0301_write_reg(cam, 0x0110, 0xFB);
+	err += zc0301_write_reg(cam, 0x0111, 0xED);
+	err += zc0301_write_reg(cam, 0x0112, 0x5F);
+	err += zc0301_write_reg(cam, 0x0180, 0x00);
+	err += zc0301_write_reg(cam, 0x0019, 0x00);
+	err += zc0301_write_reg(cam, 0x0087, 0x20);
+	err += zc0301_write_reg(cam, 0x0088, 0x21);
+
+	err += zc0301_i2c_write(cam, 0x20, 0x02);
+	err += zc0301_i2c_write(cam, 0x21, 0x1B);
+	err += zc0301_i2c_write(cam, 0x03, 0x44);
+	err += zc0301_i2c_write(cam, 0x0E, 0x01);
+	err += zc0301_i2c_write(cam, 0x0F, 0x00);
+
+	err += zc0301_write_reg(cam, 0x01A9, 0x14);
+	err += zc0301_write_reg(cam, 0x01AA, 0x24);
+	err += zc0301_write_reg(cam, 0x0190, 0x00);
+	err += zc0301_write_reg(cam, 0x0191, 0x02);
+	err += zc0301_write_reg(cam, 0x0192, 0x1B);
+	err += zc0301_write_reg(cam, 0x0195, 0x00);
+	err += zc0301_write_reg(cam, 0x0196, 0x00);
+	err += zc0301_write_reg(cam, 0x0197, 0x4D);
+	err += zc0301_write_reg(cam, 0x018C, 0x10);
+	err += zc0301_write_reg(cam, 0x018F, 0x20);
+	err += zc0301_write_reg(cam, 0x001D, 0x44);
+	err += zc0301_write_reg(cam, 0x001E, 0x6F);
+	err += zc0301_write_reg(cam, 0x001F, 0xAD);
+	err += zc0301_write_reg(cam, 0x0020, 0xEB);
+	err += zc0301_write_reg(cam, 0x0087, 0x0F);
+	err += zc0301_write_reg(cam, 0x0088, 0x0E);
+	err += zc0301_write_reg(cam, 0x0180, 0x40);
+	err += zc0301_write_reg(cam, 0x0192, 0x1B);
+	err += zc0301_write_reg(cam, 0x0191, 0x02);
+	err += zc0301_write_reg(cam, 0x0190, 0x00);
+	err += zc0301_write_reg(cam, 0x0116, 0x1D);
+	err += zc0301_write_reg(cam, 0x0117, 0x40);
+	err += zc0301_write_reg(cam, 0x0118, 0x99);
+	err += zc0301_write_reg(cam, 0x0180, 0x42);
+	err += zc0301_write_reg(cam, 0x0116, 0x1D);
+	err += zc0301_write_reg(cam, 0x0117, 0x40);
+	err += zc0301_write_reg(cam, 0x0118, 0x99);
+	err += zc0301_write_reg(cam, 0x0007, 0x00);
+
+	err += zc0301_i2c_write(cam, 0x11, 0x01);
+
+	msleep(100);
+
+	return err;
+}
+
+
+static int pas202bcb_get_ctrl(struct zc0301_device* cam,
+                              struct v4l2_control* ctrl)
+{
+	switch (ctrl->id) {
+	case V4L2_CID_EXPOSURE:
+		{
+			int r1 = zc0301_i2c_read(cam, 0x04, 1),
+			    r2 = zc0301_i2c_read(cam, 0x05, 1);
+			if (r1 < 0 || r2 < 0)
+				return -EIO;
+			ctrl->value = (r1 << 6) | (r2 & 0x3f);
+		}
+		return 0;
+	case V4L2_CID_RED_BALANCE:
+		if ((ctrl->value = zc0301_i2c_read(cam, 0x09, 1)) < 0)
+			return -EIO;
+		ctrl->value &= 0x0f;
+		return 0;
+	case V4L2_CID_BLUE_BALANCE:
+		if ((ctrl->value = zc0301_i2c_read(cam, 0x07, 1)) < 0)
+			return -EIO;
+		ctrl->value &= 0x0f;
+		return 0;
+	case V4L2_CID_GAIN:
+		if ((ctrl->value = zc0301_i2c_read(cam, 0x10, 1)) < 0)
+			return -EIO;
+		ctrl->value &= 0x1f;
+		return 0;
+	case ZC0301_V4L2_CID_GREEN_BALANCE:
+		if ((ctrl->value = zc0301_i2c_read(cam, 0x08, 1)) < 0)
+			return -EIO;
+		ctrl->value &= 0x0f;
+		return 0;
+	case ZC0301_V4L2_CID_DAC_MAGNITUDE:
+		if ((ctrl->value = zc0301_i2c_read(cam, 0x0c, 1)) < 0)
+			return -EIO;
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+
+static int pas202bcb_set_ctrl(struct zc0301_device* cam,
+                              const struct v4l2_control* ctrl)
+{
+	int err = 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_EXPOSURE:
+		err += zc0301_i2c_write(cam, 0x04, ctrl->value >> 6);
+		err += zc0301_i2c_write(cam, 0x05, ctrl->value & 0x3f);
+		break;
+	case V4L2_CID_RED_BALANCE:
+		err += zc0301_i2c_write(cam, 0x09, ctrl->value);
+		break;
+	case V4L2_CID_BLUE_BALANCE:
+		err += zc0301_i2c_write(cam, 0x07, ctrl->value);
+		break;
+	case V4L2_CID_GAIN:
+		err += zc0301_i2c_write(cam, 0x10, ctrl->value);
+		break;
+	case ZC0301_V4L2_CID_GREEN_BALANCE:
+		err += zc0301_i2c_write(cam, 0x08, ctrl->value);
+		break;
+	case ZC0301_V4L2_CID_DAC_MAGNITUDE:
+		err += zc0301_i2c_write(cam, 0x0c, ctrl->value);
+		break;
+	default:
+		return -EINVAL;
+	}
+	err += zc0301_i2c_write(cam, 0x11, 0x01);
+
+	return err ? -EIO : 0;
+}
+
+
+static struct zc0301_sensor pas202bcb = {
+	.name = "PAS202BCB",
+	.init = &pas202bcb_init,
+	.qctrl = {
+		{
+			.id = V4L2_CID_EXPOSURE,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "exposure",
+			.minimum = 0x01e5,
+			.maximum = 0x3fff,
+			.step = 0x0001,
+			.default_value = 0x01e5,
+			.flags = V4L2_CTRL_FLAG_DISABLED,
+		},
+		{
+			.id = V4L2_CID_GAIN,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "global gain",
+			.minimum = 0x00,
+			.maximum = 0x1f,
+			.step = 0x01,
+			.default_value = 0x0c,
+			.flags = V4L2_CTRL_FLAG_DISABLED,
+		},
+		{
+			.id = ZC0301_V4L2_CID_DAC_MAGNITUDE,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "DAC magnitude",
+			.minimum = 0x00,
+			.maximum = 0xff,
+			.step = 0x01,
+			.default_value = 0x00,
+			.flags = V4L2_CTRL_FLAG_DISABLED,
+		},
+		{
+			.id = V4L2_CID_RED_BALANCE,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "red balance",
+			.minimum = 0x00,
+			.maximum = 0x0f,
+			.step = 0x01,
+			.default_value = 0x01,
+			.flags = V4L2_CTRL_FLAG_DISABLED,
+		},
+		{
+			.id = V4L2_CID_BLUE_BALANCE,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "blue balance",
+			.minimum = 0x00,
+			.maximum = 0x0f,
+			.step = 0x01,
+			.default_value = 0x05,
+			.flags = V4L2_CTRL_FLAG_DISABLED,
+		},
+		{
+			.id = ZC0301_V4L2_CID_GREEN_BALANCE,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "green balance",
+			.minimum = 0x00,
+			.maximum = 0x0f,
+			.step = 0x01,
+			.default_value = 0x00,
+			.flags = V4L2_CTRL_FLAG_DISABLED,
+		},
+	},
+	.get_ctrl = &pas202bcb_get_ctrl,
+	.set_ctrl = &pas202bcb_set_ctrl,
+	.cropcap = {
+		.bounds = {
+			.left = 0,
+			.top = 0,
+			.width = 640,
+			.height = 480,
+		},
+		.defrect = {
+			.left = 0,
+			.top = 0,
+			.width = 640,
+			.height = 480,
+		},
+	},
+	.pix_format = {
+		.width = 640,
+		.height = 480,
+		.pixelformat = V4L2_PIX_FMT_JPEG,
+		.priv = 8,
+	},
+};
+
+
+int zc0301_probe_pas202bcb(struct zc0301_device* cam)
+{
+	int r0 = 0, r1 = 0, err = 0;
+	unsigned int pid = 0;
+
+	err += zc0301_write_reg(cam, 0x0000, 0x01);
+	err += zc0301_write_reg(cam, 0x0010, 0x0e);
+	err += zc0301_write_reg(cam, 0x0001, 0x01);
+	err += zc0301_write_reg(cam, 0x0012, 0x03);
+	err += zc0301_write_reg(cam, 0x0012, 0x01);
+	err += zc0301_write_reg(cam, 0x008d, 0x08);
+
+	msleep(10);
+
+	r0 = zc0301_i2c_read(cam, 0x00, 1);
+	r1 = zc0301_i2c_read(cam, 0x01, 1);
+
+	if (r0 < 0 || r1 < 0 || err)
+		return -EIO;
+
+	pid = (r0 << 4) | ((r1 & 0xf0) >> 4);
+	if (pid != 0x017)
+		return -ENODEV;
+
+	zc0301_attach_sensor(cam, &pas202bcb);
+
+	return 0;
+}
diff --git a/drivers/usb/media/zc0301_sensor.h b/drivers/usb/media/zc0301_sensor.h
new file mode 100644
index 0000000..cf0965a
--- /dev/null
+++ b/drivers/usb/media/zc0301_sensor.h
@@ -0,0 +1,103 @@
+/***************************************************************************
+ * API for image sensors connected to the ZC030! Image Processor and       *
+ * Control Chip                                                            *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * 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 _ZC0301_SENSOR_H_
+#define _ZC0301_SENSOR_H_
+
+#include <linux/usb.h>
+#include <linux/videodev.h>
+#include <linux/device.h>
+#include <linux/stddef.h>
+#include <linux/errno.h>
+#include <asm/types.h>
+
+struct zc0301_device;
+struct zc0301_sensor;
+
+/*****************************************************************************/
+
+extern int zc0301_probe_pas202bcb(struct zc0301_device* cam);
+
+#define ZC0301_SENSOR_TABLE                                                   \
+/* Weak detections must go at the end of the list */                          \
+static int (*zc0301_sensor_table[])(struct zc0301_device*) = {                \
+	&zc0301_probe_pas202bcb,                                              \
+	NULL,                                                                 \
+};
+
+extern struct zc0301_device*
+zc0301_match_id(struct zc0301_device* cam, const struct usb_device_id *id);
+
+extern void
+zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor);
+
+#define ZC0301_USB_DEVICE(vend, prod, intclass)                               \
+	.match_flags = USB_DEVICE_ID_MATCH_DEVICE |                           \
+	               USB_DEVICE_ID_MATCH_INT_CLASS,                         \
+	.idVendor = (vend),                                                   \
+	.idProduct = (prod),                                                  \
+	.bInterfaceClass = (intclass)
+
+#define ZC0301_ID_TABLE                                                       \
+static const struct usb_device_id zc0301_id_table[] =  {                      \
+	{ ZC0301_USB_DEVICE(0x041e, 0x4017, 0xff), },                         \
+	{ ZC0301_USB_DEVICE(0x041e, 0x401c, 0xff), }, /* PAS106 */            \
+	{ ZC0301_USB_DEVICE(0x041e, 0x401e, 0xff), }, /* HV7131B */           \
+	{ ZC0301_USB_DEVICE(0x041e, 0x4034, 0xff), }, /* PAS106 */            \
+	{ ZC0301_USB_DEVICE(0x041e, 0x4035, 0xff), }, /* PAS106 */            \
+	{ ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202BCB */         \
+	{ ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), },                         \
+	{ ZC0301_USB_DEVICE(0x10fd, 0x8050, 0xff), }, /* TAS5130D */          \
+	{ }                                                                   \
+};
+
+/*****************************************************************************/
+
+extern int zc0301_write_reg(struct zc0301_device*, u16 index, u16 value);
+extern int zc0301_read_reg(struct zc0301_device*, u16 index);
+extern int zc0301_i2c_write(struct zc0301_device*, u16 address, u16 value);
+extern int zc0301_i2c_read(struct zc0301_device*, u16 address, u8 length);
+
+/*****************************************************************************/
+
+#define ZC0301_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10
+#define ZC0301_V4L2_CID_DAC_MAGNITUDE V4L2_CID_PRIVATE_BASE
+#define ZC0301_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1
+
+struct zc0301_sensor {
+	char name[32];
+
+	struct v4l2_queryctrl qctrl[ZC0301_MAX_CTRLS];
+	struct v4l2_cropcap cropcap;
+	struct v4l2_pix_format pix_format;
+
+	int (*init)(struct zc0301_device*);
+	int (*get_ctrl)(struct zc0301_device*, struct v4l2_control* ctrl);
+	int (*set_ctrl)(struct zc0301_device*,
+	                const struct v4l2_control* ctrl);
+	int (*set_crop)(struct zc0301_device*, const struct v4l2_rect* rect);
+
+	/* Private */
+	struct v4l2_queryctrl _qctrl[ZC0301_MAX_CTRLS];
+	struct v4l2_rect _rect;
+};
+
+#endif /* _ZC0301_SENSOR_H_ */
diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c
index ad2f4cc..1fef36e 100644
--- a/drivers/usb/misc/auerswald.c
+++ b/drivers/usb/misc/auerswald.c
@@ -570,10 +570,9 @@
 
         /* fill the list of free elements */
         for (;numElements; numElements--) {
-                acep = (pauerchainelement_t) kmalloc (sizeof (auerchainelement_t), GFP_KERNEL);
+                acep = kzalloc(sizeof(auerchainelement_t), GFP_KERNEL);
                 if (!acep)
 			goto ac_fail;
-		memset (acep, 0, sizeof (auerchainelement_t));
                 INIT_LIST_HEAD (&acep->list);
                 list_add_tail (&acep->list, &acp->free_list);
         }
@@ -761,10 +760,9 @@
 
         /* fill the list of free elements */
         for (;numElements; numElements--) {
-                bep = (pauerbuf_t) kmalloc (sizeof (auerbuf_t), GFP_KERNEL);
+                bep = kzalloc(sizeof(auerbuf_t), GFP_KERNEL);
                 if (!bep)
 			goto bl_fail;
-	        memset (bep, 0, sizeof (auerbuf_t));
                 bep->list = bcp;
                 INIT_LIST_HEAD (&bep->buff_list);
                 bep->bufp = kmalloc (bufsize, GFP_KERNEL);
diff --git a/drivers/usb/misc/cytherm.c b/drivers/usb/misc/cytherm.c
index 6671317..a042042 100644
--- a/drivers/usb/misc/cytherm.c
+++ b/drivers/usb/misc/cytherm.c
@@ -351,12 +351,11 @@
 	struct usb_cytherm *dev = NULL;
 	int retval = -ENOMEM;
 
-	dev = kmalloc (sizeof(struct usb_cytherm), GFP_KERNEL);
+	dev = kzalloc (sizeof(struct usb_cytherm), GFP_KERNEL);
 	if (dev == NULL) {
 		dev_err (&interface->dev, "Out of memory\n");
 		goto error;
 	}
-	memset (dev, 0x00, sizeof (*dev));
 
 	dev->udev = usb_get_dev(udev);
 
diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c
index d8cde10..d0b1672 100644
--- a/drivers/usb/misc/idmouse.c
+++ b/drivers/usb/misc/idmouse.c
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/smp_lock.h>
 #include <linux/completion.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include <linux/usb.h>
 
@@ -121,7 +122,7 @@
 };
 
 /* prevent races between open() and disconnect() */
-static DECLARE_MUTEX(disconnect_sem);
+static DEFINE_MUTEX(disconnect_mutex);
 
 static int idmouse_create_image(struct usb_idmouse *dev)
 {
@@ -213,18 +214,18 @@
 	int result = 0;
 
 	/* prevent disconnects */
-	down(&disconnect_sem);
+	mutex_lock(&disconnect_mutex);
 
 	/* get the interface from minor number and driver information */
 	interface = usb_find_interface (&idmouse_driver, iminor (inode));
 	if (!interface) {
-		up(&disconnect_sem);
+		mutex_unlock(&disconnect_mutex);
 		return -ENODEV;
 	}
 	/* get the device information block from the interface */
 	dev = usb_get_intfdata(interface);
 	if (!dev) {
-		up(&disconnect_sem);
+		mutex_unlock(&disconnect_mutex);
 		return -ENODEV;
 	}
 
@@ -258,7 +259,7 @@
 	up(&dev->sem);
 
 	/* unlock the disconnect semaphore */
-	up(&disconnect_sem);
+	mutex_unlock(&disconnect_mutex);
 	return result;
 }
 
@@ -267,12 +268,12 @@
 	struct usb_idmouse *dev;
 
 	/* prevent a race condition with open() */
-	down(&disconnect_sem);
+	mutex_lock(&disconnect_mutex);
 
 	dev = (struct usb_idmouse *) file->private_data;
 
 	if (dev == NULL) {
-		up(&disconnect_sem);
+		mutex_unlock(&disconnect_mutex);
 		return -ENODEV;
 	}
 
@@ -282,7 +283,7 @@
 	/* are we really open? */
 	if (dev->open <= 0) {
 		up(&dev->sem);
-		up(&disconnect_sem);
+		mutex_unlock(&disconnect_mutex);
 		return -ENODEV;
 	}
 
@@ -292,12 +293,12 @@
 		/* the device was unplugged before the file was released */
 		up(&dev->sem);
 		idmouse_delete(dev);
-		up(&disconnect_sem);
+		mutex_unlock(&disconnect_mutex);
 		return 0;
 	}
 
 	up(&dev->sem);
-	up(&disconnect_sem);
+	mutex_unlock(&disconnect_mutex);
 	return 0;
 }
 
@@ -340,10 +341,9 @@
 		return -ENODEV;
 
 	/* allocate memory for our device state and initialize it */
-	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (dev == NULL)
 		return -ENOMEM;
-	memset(dev, 0x00, sizeof(*dev));
 
 	init_MUTEX(&dev->sem);
 	dev->udev = udev;
@@ -400,7 +400,7 @@
 	struct usb_idmouse *dev;
 
 	/* prevent races with open() */
-	down(&disconnect_sem);
+	mutex_lock(&disconnect_mutex);
 
 	/* get device structure */
 	dev = usb_get_intfdata(interface);
@@ -422,7 +422,7 @@
 	if (!dev->open)
 		idmouse_delete(dev);
 
-	up(&disconnect_sem);
+	mutex_unlock(&disconnect_mutex);
 
 	info("%s disconnected", DRIVER_DESC);
 }
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index e2d1198..966acb4 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -33,6 +33,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 
 #include <asm/uaccess.h>
 #include <linux/input.h>
@@ -172,7 +173,7 @@
 };
 
 /* prevent races between open() and disconnect() */
-static DECLARE_MUTEX(disconnect_sem);
+static DEFINE_MUTEX(disconnect_mutex);
 
 static struct usb_driver ld_usb_driver;
 
@@ -293,7 +294,7 @@
 	nonseekable_open(inode, file);
 	subminor = iminor(inode);
 
-	down(&disconnect_sem);
+	mutex_lock(&disconnect_mutex);
 
 	interface = usb_find_interface(&ld_usb_driver, subminor);
 
@@ -355,7 +356,7 @@
 	up(&dev->sem);
 
 unlock_disconnect_exit:
-	up(&disconnect_sem);
+	mutex_unlock(&disconnect_mutex);
 
 	return retval;
 }
@@ -626,12 +627,11 @@
 
 	/* allocate memory for our device state and intialize it */
 
-	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (dev == NULL) {
 		dev_err(&intf->dev, "Out of memory\n");
 		goto exit;
 	}
-	memset(dev, 0x00, sizeof(*dev));
 	init_MUTEX(&dev->sem);
 	dev->intf = intf;
 	init_waitqueue_head(&dev->read_wait);
@@ -741,7 +741,7 @@
 	struct ld_usb *dev;
 	int minor;
 
-	down(&disconnect_sem);
+	mutex_lock(&disconnect_mutex);
 
 	dev = usb_get_intfdata(intf);
 	usb_set_intfdata(intf, NULL);
@@ -762,7 +762,7 @@
 		up(&dev->sem);
 	}
 
-	up(&disconnect_sem);
+	mutex_unlock(&disconnect_mutex);
 
 	dev_info(&intf->dev, "LD USB Device #%d now disconnected\n",
 		 (minor - USB_LD_MINOR_BASE));
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index 1336745..779bcf0 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -83,6 +83,7 @@
 #include <linux/module.h>
 #include <linux/smp_lock.h>
 #include <linux/completion.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include <linux/usb.h>
 #include <linux/poll.h>
@@ -256,7 +257,7 @@
 
 
 /* prevent races between open() and disconnect */
-static DECLARE_MUTEX (disconnect_sem);
+static DEFINE_MUTEX (disconnect_mutex);
 
 /* file operations needed when we register this driver */
 static struct file_operations tower_fops = {
@@ -349,7 +350,7 @@
 	nonseekable_open(inode, file);
 	subminor = iminor(inode);
 
-	down (&disconnect_sem);
+	mutex_lock (&disconnect_mutex);
 
 	interface = usb_find_interface (&tower_driver, subminor);
 
@@ -427,7 +428,7 @@
 	up (&dev->sem);
 
 unlock_disconnect_exit:
-	up (&disconnect_sem);
+	mutex_unlock (&disconnect_mutex);
 
 	dbg(2, "%s: leave, return value %d ", __FUNCTION__, retval);
 
@@ -1005,7 +1006,7 @@
 
 	dbg(2, "%s: enter", __FUNCTION__);
 
-	down (&disconnect_sem);
+	mutex_lock (&disconnect_mutex);
 
 	dev = usb_get_intfdata (interface);
 	usb_set_intfdata (interface, NULL);
@@ -1027,7 +1028,7 @@
 		up (&dev->sem);
 	}
 
-	up (&disconnect_sem);
+	mutex_unlock (&disconnect_mutex);
 
 	info("LEGO USB Tower #%d now disconnected", (minor - LEGO_USB_TOWER_MINOR_BASE));
 
diff --git a/drivers/usb/misc/phidgetkit.c b/drivers/usb/misc/phidgetkit.c
index 605a3c8..997db5d 100644
--- a/drivers/usb/misc/phidgetkit.c
+++ b/drivers/usb/misc/phidgetkit.c
@@ -88,7 +88,7 @@
 	int retval;
 	int n;
 
-	buffer = kmalloc(4, GFP_KERNEL);
+	buffer = kzalloc(4, GFP_KERNEL);
 	if (!buffer) {
 		dev_err(&kit->udev->dev, "%s - out of memory\n",
 			__FUNCTION__);
@@ -96,7 +96,6 @@
 	}
 
 	kit->outputs[output_num] = enable;
-	memset(buffer, 0, 4);
 	for (n=0; n<8; n++) {
 		if (kit->outputs[n]) {
 			buffer[0] |= 1 << n;
@@ -192,7 +191,7 @@
 	unsigned char *buffer;
 	int retval = -ENOMEM;
 	
-	buffer = kmalloc(8, GFP_KERNEL);
+	buffer = kzalloc(8, GFP_KERNEL);
 	if (!buffer) {
 		dev_err(&kit->udev->dev, "%s - out of memory\n", __FUNCTION__);
 		goto exit;
@@ -202,7 +201,6 @@
 		retval = -EINVAL;
 		goto exit;
 	}
-	memset(buffer, 0x00, 8);
 	if (enabled)
 		buffer[0] = 0x01;
 	buffer[7] = 0x11;
@@ -406,12 +404,11 @@
 	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
 	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
 	
-	kit = kmalloc(sizeof(*kit), GFP_KERNEL);
+	kit = kzalloc(sizeof(*kit), GFP_KERNEL);
 	if (kit  == NULL) {
 		dev_err(&intf->dev, "%s - out of memory\n", __FUNCTION__);
 		return -ENOMEM;
 	}
-	memset(kit, 0, sizeof(*kit));
 	kit->ifkit = ifkit;
 
 	kit->data = usb_buffer_alloc(dev, 8, SLAB_ATOMIC, &kit->data_dma);
diff --git a/drivers/usb/misc/phidgetservo.c b/drivers/usb/misc/phidgetservo.c
index b3418d2..5a040c2 100644
--- a/drivers/usb/misc/phidgetservo.c
+++ b/drivers/usb/misc/phidgetservo.c
@@ -252,12 +252,11 @@
 	struct usb_device *udev = interface_to_usbdev(interface);
 	struct phidget_servo *dev;
 
-	dev = kmalloc(sizeof (struct phidget_servo), GFP_KERNEL);
+	dev = kzalloc(sizeof (struct phidget_servo), GFP_KERNEL);
 	if (dev == NULL) {
 		dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__);
 		return -ENOMEM;
 	}
-	memset(dev, 0x00, sizeof (*dev));
 
 	dev->udev = usb_get_dev(udev);
 	dev->type = id->driver_info;
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index 3260d59..196c879 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -3188,7 +3188,7 @@
 			break;
 
 		default:
-			retval = -EINVAL;
+			retval = -ENOTTY;
 			break;
 	}
 
@@ -3251,12 +3251,11 @@
 		dev->devnum);
 
 	/* Allocate memory for our private */
-	if (!(sisusb = kmalloc(sizeof(*sisusb), GFP_KERNEL))) {
+	if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) {
 		printk(KERN_ERR
 			"sisusb: Failed to allocate memory for private data\n");
 		return -ENOMEM;
 	}
-	memset(sisusb, 0, sizeof(*sisusb));
 	kref_init(&sisusb->kref);
 
 	init_MUTEX(&(sisusb->lock));
diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h
index 1d7a77c..a716825 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.h
+++ b/drivers/usb/misc/sisusbvga/sisusb.h
@@ -37,24 +37,16 @@
 #ifndef _SISUSB_H_
 #define _SISUSB_H_
 
-#include <linux/version.h>
 #ifdef CONFIG_COMPAT
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,10)
-#include <linux/ioctl32.h>
-#define SISUSB_OLD_CONFIG_COMPAT
-#else
 #define SISUSB_NEW_CONFIG_COMPAT
 #endif
-#endif
 
 /* For older kernels, support for text consoles is by default
  * off. To ensable text console support, change the following:
  */
 #if 0
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
 #define CONFIG_USB_SISUSBVGA_CON
 #endif
-#endif
 
 /* Version Information */
 
diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c
index cc3dae3..c82c402 100644
--- a/drivers/usb/misc/usblcd.c
+++ b/drivers/usb/misc/usblcd.c
@@ -270,12 +270,11 @@
 	int retval = -ENOMEM;
 
 	/* allocate memory for our device state and initialize it */
-	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (dev == NULL) {
 		err("Out of memory");
 		goto error;
 	}
-	memset(dev, 0x00, sizeof(*dev));
 	kref_init(&dev->kref);
 
 	dev->udev = usb_get_dev(interface_to_usbdev(interface));
diff --git a/drivers/usb/misc/usbled.c b/drivers/usb/misc/usbled.c
index 877b081..f441964 100644
--- a/drivers/usb/misc/usbled.c
+++ b/drivers/usb/misc/usbled.c
@@ -106,12 +106,11 @@
 	struct usb_led *dev = NULL;
 	int retval = -ENOMEM;
 
-	dev = kmalloc(sizeof(struct usb_led), GFP_KERNEL);
+	dev = kzalloc(sizeof(struct usb_led), GFP_KERNEL);
 	if (dev == NULL) {
 		dev_err(&interface->dev, "Out of memory\n");
 		goto error;
 	}
-	memset (dev, 0x00, sizeof (*dev));
 
 	dev->udev = usb_get_dev(udev);
 
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index 84fa172..9d59b90 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -382,12 +382,11 @@
 	for (i = 0; i < nents; i++) {
 		char		*buf;
 
-		buf = kmalloc (size, SLAB_KERNEL);
+		buf = kzalloc (size, SLAB_KERNEL);
 		if (!buf) {
 			free_sglist (sg, i);
 			return NULL;
 		}
-		memset (buf, 0, size);
 
 		/* kmalloc pages are always physically contiguous! */
 		sg_init_one(&sg[i], buf, size);
@@ -842,10 +841,9 @@
 	 * as with bulk/intr sglists, sglen is the queue depth; it also
 	 * controls which subtests run (more tests than sglen) or rerun.
 	 */
-	urb = kmalloc (param->sglen * sizeof (struct urb *), SLAB_KERNEL);
+	urb = kcalloc(param->sglen, sizeof(struct urb *), SLAB_KERNEL);
 	if (!urb)
 		return -ENOMEM;
-	memset (urb, 0, param->sglen * sizeof (struct urb *));
 	for (i = 0; i < param->sglen; i++) {
 		int			pipe = usb_rcvctrlpipe (udev, 0);
 		unsigned		len;
@@ -1865,10 +1863,9 @@
 	}
 #endif
 
-	dev = kmalloc (sizeof *dev, SLAB_KERNEL);
+	dev = kzalloc(sizeof(*dev), SLAB_KERNEL);
 	if (!dev)
 		return -ENOMEM;
-	memset (dev, 0, sizeof *dev);
 	info = (struct usbtest_info *) id->driver_info;
 	dev->info = info;
 	init_MUTEX (&dev->sem);
diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c
index c34944c..6ecc273 100644
--- a/drivers/usb/mon/mon_main.c
+++ b/drivers/usb/mon/mon_main.c
@@ -12,6 +12,7 @@
 #include <linux/debugfs.h>
 #include <linux/smp_lock.h>
 #include <linux/notifier.h>
+#include <linux/mutex.h>
 
 #include "usb_mon.h"
 #include "../core/hcd.h"
@@ -23,7 +24,7 @@
 static void mon_bus_drop(struct kref *r);
 static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus);
 
-DECLARE_MUTEX(mon_lock);
+DEFINE_MUTEX(mon_lock);
 
 static struct dentry *mon_dir;		/* /dbg/usbmon */
 static LIST_HEAD(mon_buses);		/* All buses we know: struct mon_bus */
@@ -196,14 +197,14 @@
 {
 	struct mon_bus *mbus = ubus->mon_bus;
 
-	down(&mon_lock);
+	mutex_lock(&mon_lock);
 	list_del(&mbus->bus_link);
 	debugfs_remove(mbus->dent_t);
 	debugfs_remove(mbus->dent_s);
 
 	mon_dissolve(mbus, ubus);
 	kref_put(&mbus->ref, mon_bus_drop);
-	up(&mon_lock);
+	mutex_unlock(&mon_lock);
 }
 
 static int mon_notify(struct notifier_block *self, unsigned long action,
@@ -276,9 +277,8 @@
 	char name[NAMESZ];
 	int rc;
 
-	if ((mbus = kmalloc(sizeof(struct mon_bus), GFP_KERNEL)) == NULL)
+	if ((mbus = kzalloc(sizeof(struct mon_bus), GFP_KERNEL)) == NULL)
 		goto err_alloc;
-	memset(mbus, 0, sizeof(struct mon_bus));
 	kref_init(&mbus->ref);
 	spin_lock_init(&mbus->lock);
 	INIT_LIST_HEAD(&mbus->r_list);
@@ -307,9 +307,9 @@
 		goto err_create_s;
 	mbus->dent_s = d;
 
-	down(&mon_lock);
+	mutex_lock(&mon_lock);
 	list_add_tail(&mbus->bus_link, &mon_buses);
-	up(&mon_lock);
+	mutex_unlock(&mon_lock);
 	return;
 
 err_create_s:
@@ -347,11 +347,11 @@
 
 	usb_register_notify(&mon_nb);
 
-	down(&usb_bus_list_lock);
+	mutex_lock(&usb_bus_list_lock);
 	list_for_each_entry (ubus, &usb_bus_list, bus_list) {
 		mon_bus_init(mondir, ubus);
 	}
-	up(&usb_bus_list_lock);
+	mutex_unlock(&usb_bus_list_lock);
 	return 0;
 }
 
@@ -363,7 +363,7 @@
 	usb_unregister_notify(&mon_nb);
 	usb_mon_deregister();
 
-	down(&mon_lock);
+	mutex_lock(&mon_lock);
 	while (!list_empty(&mon_buses)) {
 		p = mon_buses.next;
 		mbus = list_entry(p, struct mon_bus, bus_link);
@@ -387,7 +387,7 @@
 		mon_dissolve(mbus, mbus->u_bus);
 		kref_put(&mbus->ref, mon_bus_drop);
 	}
-	up(&mon_lock);
+	mutex_unlock(&mon_lock);
 
 	debugfs_remove(mon_dir);
 }
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c
index 6116121..ac043ec 100644
--- a/drivers/usb/mon/mon_text.c
+++ b/drivers/usb/mon/mon_text.c
@@ -8,6 +8,7 @@
 #include <linux/list.h>
 #include <linux/usb.h>
 #include <linux/time.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 #include "usb_mon.h"
@@ -54,7 +55,7 @@
 	wait_queue_head_t wait;
 	int printf_size;
 	char *printf_buf;
-	struct semaphore printf_lock;
+	struct mutex printf_lock;
 
 	char slab_name[SLAB_NAME_SZ];
 };
@@ -208,19 +209,18 @@
 	struct mon_reader_text *rp;
 	int rc;
 
-	down(&mon_lock);
+	mutex_lock(&mon_lock);
 	mbus = inode->u.generic_ip;
 	ubus = mbus->u_bus;
 
-	rp = kmalloc(sizeof(struct mon_reader_text), GFP_KERNEL);
+	rp = kzalloc(sizeof(struct mon_reader_text), GFP_KERNEL);
 	if (rp == NULL) {
 		rc = -ENOMEM;
 		goto err_alloc;
 	}
-	memset(rp, 0, sizeof(struct mon_reader_text));
 	INIT_LIST_HEAD(&rp->e_list);
 	init_waitqueue_head(&rp->wait);
-	init_MUTEX(&rp->printf_lock);
+	mutex_init(&rp->printf_lock);
 
 	rp->printf_size = PRINTF_DFL;
 	rp->printf_buf = kmalloc(rp->printf_size, GFP_KERNEL);
@@ -247,7 +247,7 @@
 	mon_reader_add(mbus, &rp->r);
 
 	file->private_data = rp;
-	up(&mon_lock);
+	mutex_unlock(&mon_lock);
 	return 0;
 
 // err_busy:
@@ -257,7 +257,7 @@
 err_alloc_pr:
 	kfree(rp);
 err_alloc:
-	up(&mon_lock);
+	mutex_unlock(&mon_lock);
 	return rc;
 }
 
@@ -301,7 +301,7 @@
 	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&rp->wait, &waita);
 
-	down(&rp->printf_lock);
+	mutex_lock(&rp->printf_lock);
 	cnt = 0;
 	pbuf = rp->printf_buf;
 	limit = rp->printf_size;
@@ -358,7 +358,7 @@
 
 	if (copy_to_user(buf, rp->printf_buf, cnt))
 		cnt = -EFAULT;
-	up(&rp->printf_lock);
+	mutex_unlock(&rp->printf_lock);
 	kmem_cache_free(rp->e_slab, ep);
 	return cnt;
 }
@@ -371,12 +371,12 @@
 	struct list_head *p;
 	struct mon_event_text *ep;
 
-	down(&mon_lock);
+	mutex_lock(&mon_lock);
 	mbus = inode->u.generic_ip;
 
 	if (mbus->nreaders <= 0) {
 		printk(KERN_ERR TAG ": consistency error on close\n");
-		up(&mon_lock);
+		mutex_unlock(&mon_lock);
 		return 0;
 	}
 	mon_reader_del(mbus, &rp->r);
@@ -402,7 +402,7 @@
 	kfree(rp->printf_buf);
 	kfree(rp);
 
-	up(&mon_lock);
+	mutex_unlock(&mon_lock);
 	return 0;
 }
 
diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h
index 4be0f93..8e0613c 100644
--- a/drivers/usb/mon/usb_mon.h
+++ b/drivers/usb/mon/usb_mon.h
@@ -49,7 +49,7 @@
  */
 extern char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len);
 
-extern struct semaphore mon_lock;
+extern struct mutex mon_lock;
 
 extern struct file_operations mon_fops_text;
 extern struct file_operations mon_fops_stat;
diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c
index 156a2f1..5b66756 100644
--- a/drivers/usb/net/pegasus.c
+++ b/drivers/usb/net/pegasus.c
@@ -524,6 +524,7 @@
 	ret = set_registers(pegasus, EthCtrl0, 3, data);
 
 	if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||
+	    usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS2 ||
 	    usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) {
 		u16 auxmode;
 		read_mii_word(pegasus, 0, 0x1b, &auxmode);
diff --git a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h
index 9fbd59b..a54752c 100644
--- a/drivers/usb/net/pegasus.h
+++ b/drivers/usb/net/pegasus.h
@@ -25,7 +25,6 @@
 #define	PHY_READ		0x40
 #define	PHY_WRITE		0x20
 #define	DEFAULT_GPIO_RESET	0x24
-#define	LINKSYS_GPIO_RESET	0x24
 #define	DEFAULT_GPIO_SET	0x26
 
 #define	PEGASUS_PRESENT		0x00000001
@@ -140,6 +139,7 @@
 #define	VENDOR_KINGSTON		0x0951
 #define	VENDOR_LANEED		0x056e
 #define	VENDOR_LINKSYS		0x066b
+#define	VENDOR_LINKSYS2		0x077b
 #define	VENDOR_MELCO		0x0411
 #define	VENDOR_MICROSOFT	0x045e
 #define	VENDOR_MOBILITY		0x1342
@@ -218,15 +218,15 @@
 PEGASUS_DEV( "Corega FEter USB-TXS", VENDOR_COREGA, 0x000d,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4001,
-		LINKSYS_GPIO_RESET )
+		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4002,
-		LINKSYS_GPIO_RESET )
+		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4102,
-		LINKSYS_GPIO_RESET | PEGASUS_II )
+		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x400b,
-		LINKSYS_GPIO_RESET | PEGASUS_II )
+		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x200c,
-		LINKSYS_GPIO_RESET | PEGASUS_II )
+		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "D-Link DSB-650TX(PNA)", VENDOR_DLINK, 0x4003,
 		DEFAULT_GPIO_RESET | HAS_HOME_PNA )
 PEGASUS_DEV( "D-Link DSB-650", VENDOR_DLINK, 0xabc1,
@@ -260,17 +260,19 @@
 PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x200c,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "Linksys USB10TX", VENDOR_LINKSYS, 0x2202,
-		LINKSYS_GPIO_RESET )
+		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "Linksys USB100TX", VENDOR_LINKSYS, 0x2203,
-		LINKSYS_GPIO_RESET )
+		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "Linksys USB100TX", VENDOR_LINKSYS, 0x2204,
-		LINKSYS_GPIO_RESET | HAS_HOME_PNA )
+		DEFAULT_GPIO_RESET | HAS_HOME_PNA )
 PEGASUS_DEV( "Linksys USB10T Ethernet Adapter", VENDOR_LINKSYS, 0x2206,
-		LINKSYS_GPIO_RESET | PEGASUS_II)
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV( "Linksys USBVPN1", VENDOR_LINKSYS2, 0x08b4,
+		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "Linksys USB USB100TX", VENDOR_LINKSYS, 0x400b,
-		LINKSYS_GPIO_RESET | PEGASUS_II )
+		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "Linksys USB10TX", VENDOR_LINKSYS, 0x200c,
-		LINKSYS_GPIO_RESET | PEGASUS_II )	
+		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0001,
 		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0005,
diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c
index 8ca52be..1bbbae2 100644
--- a/drivers/usb/net/rtl8150.c
+++ b/drivers/usb/net/rtl8150.c
@@ -880,7 +880,6 @@
 	}
 	fill_skb_pool(dev);
 	set_ethernet_addr(dev);
-	info("%s: rtl8150 is detected", netdev->name);
 	
 	usb_set_intfdata(intf, dev);
 	SET_NETDEV_DEV(netdev, &intf->dev);
@@ -888,6 +887,9 @@
 		err("couldn't register the device");
 		goto out2;
 	}
+
+	info("%s: rtl8150 is detected", netdev->name);
+
 	return 0;
 
 out2:
diff --git a/drivers/usb/net/zd1201.c b/drivers/usb/net/zd1201.c
index f3a8e28..fe9b60c 100644
--- a/drivers/usb/net/zd1201.c
+++ b/drivers/usb/net/zd1201.c
@@ -621,10 +621,9 @@
 	__le16 zdmax;
 	unsigned char *buffer;
 	
-	buffer = kmalloc(ZD1201_RXSIZE, GFP_KERNEL);
+	buffer = kzalloc(ZD1201_RXSIZE, GFP_KERNEL);
 	if (!buffer)
 		return -ENOMEM;
-	memset(buffer, 0, ZD1201_RXSIZE);
 
 	usb_fill_bulk_urb(zd->rx_urb, zd->usb, 
 	    usb_rcvbulkpipe(zd->usb, zd->endp_in), buffer, ZD1201_RXSIZE,
@@ -1750,11 +1749,9 @@
 
 	usb = interface_to_usbdev(interface);
 
-	zd = kmalloc(sizeof(struct zd1201), GFP_KERNEL);
-	if (!zd) {
+	zd = kzalloc(sizeof(struct zd1201), GFP_KERNEL);
+	if (!zd)
 		return -ENOMEM;
-	}
-	memset(zd, 0, sizeof(struct zd1201));
 	zd->ap = ap;
 	zd->usb = usb;
 	zd->removed = 0;
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index be5dc80..5a8a2c9 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -403,6 +403,13 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called mct_u232.
 
+config USB_SERIAL_NAVMAN
+	tristate "USB Navman GPS device"
+	depends on USB_SERIAL
+	help
+	  To compile this driver as a module, choose M here: the
+	  module will be called navman.
+
 config USB_SERIAL_PL2303
 	tristate "USB Prolific 2303 Single Port Serial Driver"
 	depends on USB_SERIAL
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index f0b0442..f7fe417 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -32,6 +32,7 @@
 obj-$(CONFIG_USB_SERIAL_KLSI)			+= kl5kusb105.o
 obj-$(CONFIG_USB_SERIAL_KOBIL_SCT)		+= kobil_sct.o
 obj-$(CONFIG_USB_SERIAL_MCT_U232)		+= mct_u232.o
+obj-$(CONFIG_USB_SERIAL_NAVMAN)			+= navman.o
 obj-$(CONFIG_USB_SERIAL_OMNINET)		+= omninet.o
 obj-$(CONFIG_USB_SERIAL_OPTION)			+= option.o
 obj-$(CONFIG_USB_SERIAL_PL2303)			+= pl2303.o
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c
index dc7a069..e0c2acd 100644
--- a/drivers/usb/serial/cp2101.c
+++ b/drivers/usb/serial/cp2101.c
@@ -32,7 +32,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.06"
+#define DRIVER_VERSION "v0.07"
 #define DRIVER_DESC "Silicon Labs CP2101/CP2102 RS232 serial adaptor driver"
 
 /*
@@ -58,6 +58,7 @@
 	{ USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
 	{ USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
 	{ USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */
+	{ USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */
 	{ USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */
 	{ USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */
 	{ USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */
@@ -169,9 +170,7 @@
 	/* Number of integers required to contain the array */
 	length = (((size - 1) | 3) + 1)/4;
 
-	buf = kmalloc (length * sizeof(u32), GFP_KERNEL);
-	memset(buf, 0, length * sizeof(u32));
-
+	buf = kcalloc(length, sizeof(u32), GFP_KERNEL);
 	if (!buf) {
 		dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__);
 		return -ENOMEM;
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index 68067fe..7212fbe 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -98,10 +98,16 @@
 	{ }						/* Terminating entry */
 };
 
+static struct usb_device_id id_table_nokiaca42v2 [] = {
+	{ USB_DEVICE(VENDOR_ID_DAZZLE, PRODUCT_ID_CA42) },
+	{ }						/* Terminating entry */
+};
+
 static struct usb_device_id id_table_combined [] = {
 	{ USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) },
 	{ USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) },
 	{ USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) },
+	{ USB_DEVICE(VENDOR_ID_DAZZLE, PRODUCT_ID_CA42) },
 	{ }						/* Terminating entry */
 };
 
@@ -149,6 +155,7 @@
 /* function prototypes for the Cypress USB to serial device */
 static int  cypress_earthmate_startup	(struct usb_serial *serial);
 static int  cypress_hidcom_startup	(struct usb_serial *serial);
+static int  cypress_ca42v2_startup	(struct usb_serial *serial);
 static void cypress_shutdown		(struct usb_serial *serial);
 static int  cypress_open		(struct usb_serial_port *port, struct file *filp);
 static void cypress_close		(struct usb_serial_port *port, struct file *filp);
@@ -235,6 +242,34 @@
 	.write_int_callback =		cypress_write_int_callback,
 };
 
+static struct usb_serial_driver cypress_ca42v2_device = {
+	.driver = {
+		.owner =		THIS_MODULE,
+                .name =			"nokiaca42v2",
+	},
+	.description =			"Nokia CA-42 V2 Adapter",
+	.id_table =			id_table_nokiaca42v2,
+	.num_interrupt_in =		1,
+	.num_interrupt_out =		1,
+	.num_bulk_in =			NUM_DONT_CARE,
+	.num_bulk_out =			NUM_DONT_CARE,
+	.num_ports =			1,
+	.attach =			cypress_ca42v2_startup,
+	.shutdown =			cypress_shutdown,
+	.open =				cypress_open,
+	.close =			cypress_close,
+	.write =			cypress_write,
+	.write_room =			cypress_write_room,
+	.ioctl =			cypress_ioctl,
+	.set_termios =			cypress_set_termios,
+	.tiocmget =			cypress_tiocmget,
+	.tiocmset =			cypress_tiocmset,
+	.chars_in_buffer =		cypress_chars_in_buffer,
+	.throttle =			cypress_throttle,
+	.unthrottle =			cypress_unthrottle,
+	.read_int_callback =		cypress_read_int_callback,
+	.write_int_callback =		cypress_write_int_callback,
+};
 
 /*****************************************************************************
  * Cypress serial helper functions
@@ -286,6 +321,12 @@
 						    __FUNCTION__);
 						new_baudrate = priv->baud_rate;
 					}
+				} else if (priv->chiptype == CT_CA42V2) {
+					if ( (new_baudrate = mask_to_rate(baud_mask)) == -1) {
+						err("%s - failed setting baud rate, unsupported speed",
+						    __FUNCTION__);
+						new_baudrate = priv->baud_rate;
+					}
 				} else if (priv->chiptype == CT_GENERIC) {
 					if ( (new_baudrate = mask_to_rate(baud_mask)) == -1) {
 						err("%s - failed setting baud rate, unsupported speed",
@@ -435,11 +476,10 @@
 
 	dbg("%s - port %d", __FUNCTION__, serial->port[0]->number);
 
-	priv = kmalloc(sizeof (struct cypress_private), GFP_KERNEL);
+	priv = kzalloc(sizeof (struct cypress_private), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
 
-	memset(priv, 0x00, sizeof (struct cypress_private));
 	spin_lock_init(&priv->lock);
 	priv->buf = cypress_buf_alloc(CYPRESS_BUF_SIZE);
 	if (priv->buf == NULL) {
@@ -500,6 +540,25 @@
 } /* cypress_hidcom_startup */
 
 
+static int cypress_ca42v2_startup (struct usb_serial *serial)
+{
+	struct cypress_private *priv;
+
+	dbg("%s", __FUNCTION__);
+
+	if (generic_startup(serial)) {
+		dbg("%s - Failed setting up port %d", __FUNCTION__,
+				serial->port[0]->number);
+		return 1;
+	}
+
+	priv = usb_get_serial_port_data(serial->port[0]);
+	priv->chiptype = CT_CA42V2;
+
+	return 0;
+} /* cypress_ca42v2_startup */
+
+
 static void cypress_shutdown (struct usb_serial *serial)
 {
 	struct cypress_private *priv;
@@ -944,6 +1003,10 @@
 			*(tty->termios) = tty_std_termios;
 			tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL |
 				CLOCAL;
+		} else if (priv->chiptype == CT_CA42V2) {
+			*(tty->termios) = tty_std_termios;
+			tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL |
+				CLOCAL;
 		}
 		priv->termios_initialized = 1;
 	}
@@ -1542,6 +1605,9 @@
 	retval = usb_serial_register(&cypress_hidcom_device);
 	if (retval)
 		goto failed_hidcom_register;
+	retval = usb_serial_register(&cypress_ca42v2_device);
+	if (retval)
+		goto failed_ca42v2_register;
 	retval = usb_register(&cypress_driver);
 	if (retval)
 		goto failed_usb_register;
@@ -1550,6 +1616,8 @@
 	return 0;
 failed_usb_register:
 	usb_deregister(&cypress_driver);
+failed_ca42v2_register:
+	usb_serial_deregister(&cypress_ca42v2_device);
 failed_hidcom_register:
 	usb_serial_deregister(&cypress_hidcom_device);
 failed_em_register:
@@ -1566,6 +1634,7 @@
 	usb_deregister (&cypress_driver);
 	usb_serial_deregister (&cypress_earthmate_device);
 	usb_serial_deregister (&cypress_hidcom_device);
+	usb_serial_deregister (&cypress_ca42v2_device);
 }
 
 
diff --git a/drivers/usb/serial/cypress_m8.h b/drivers/usb/serial/cypress_m8.h
index 1fa119e..e1c7c27 100644
--- a/drivers/usb/serial/cypress_m8.h
+++ b/drivers/usb/serial/cypress_m8.h
@@ -18,6 +18,10 @@
 /* Cypress HID->COM RS232 Adapter */
 #define VENDOR_ID_CYPRESS		 0x04b4
 #define PRODUCT_ID_CYPHIDCOM		 0x5500
+
+/* Nokia CA-42 USB to serial cable */
+#define VENDOR_ID_DAZZLE		0x07d0
+#define PRODUCT_ID_CA42			0x4101
 /* End of device listing */
 
 /* Used for setting / requesting serial line settings */
@@ -34,6 +38,7 @@
 
 #define CT_EARTHMATE	0x01
 #define CT_CYPHIDCOM	0x02
+#define CT_CA42V2	0x03
 #define CT_GENERIC	0x0F
 /* End of chiptype definitions */
 
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index c145e1e..f3af81b 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -492,6 +492,7 @@
 	{ USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_777_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_8900F_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_PCDJ_DAC2_PID) },
+	{ USB_DEVICE(ICOM_ID1_VID, ICOM_ID1_PID) },
 	{ },					/* Optional parameter entry */
 	{ }					/* Terminating entry */
 };
@@ -1141,12 +1142,11 @@
 	
 	dbg("%s",__FUNCTION__);
 
-	priv = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL);
+	priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL);
 	if (!priv){
 		err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct ftdi_private));
 		return -ENOMEM;
 	}
-	memset(priv, 0, sizeof(*priv));
 
 	spin_lock_init(&priv->rx_lock);
         init_waitqueue_head(&priv->delta_msr_wait);
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index bdef3b8..8da773c 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -146,6 +146,13 @@
 #define KOBIL_CONV_KAAN_PID	0x2021	/* KOBIL_Konverter for KAAN */
 
 /*
+ * Icom ID-1 digital transceiver
+ */
+
+#define ICOM_ID1_VID            0x0C26
+#define ICOM_ID1_PID            0x0004
+
+/*
  * DSS-20 Sync Station for Sony Ericsson P800
  */
  
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index d6f55e9..5ec9bf5 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -1422,12 +1422,11 @@
 
 	dbg("%s", __FUNCTION__);
 
-	garmin_data_p = kmalloc (sizeof(struct garmin_data), GFP_KERNEL);
+	garmin_data_p = kzalloc(sizeof(struct garmin_data), GFP_KERNEL);
 	if (garmin_data_p == NULL) {
 		dev_err(&port->dev, "%s - Out of memory\n", __FUNCTION__);
 		return -ENOMEM;
 	}
-	memset (garmin_data_p, 0, sizeof(struct garmin_data));
 	init_timer(&garmin_data_p->timer);
 	spin_lock_init(&garmin_data_p->lock);
 	INIT_LIST_HEAD(&garmin_data_p->pktlist);
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 3f29e6b0..b606c59 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -2725,12 +2725,11 @@
 	dev = serial->dev;
 
 	/* create our private serial structure */
-	edge_serial = kmalloc (sizeof(struct edgeport_serial), GFP_KERNEL);
+	edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL);
 	if (edge_serial == NULL) {
 		dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__);
 		return -ENOMEM;
 	}
-	memset (edge_serial, 0, sizeof(struct edgeport_serial));
 	spin_lock_init(&edge_serial->es_lock);
 	edge_serial->serial = serial;
 	usb_set_serial_data(serial, edge_serial);
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index afc0f34..8e1e225 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -2727,12 +2727,11 @@
 	dev = serial->dev;
 
 	/* create our private serial structure */
-	edge_serial = kmalloc (sizeof(struct edgeport_serial), GFP_KERNEL);
+	edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL);
 	if (edge_serial == NULL) {
 		dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__);
 		return -ENOMEM;
 	}
-	memset (edge_serial, 0, sizeof(struct edgeport_serial));
 	sema_init(&edge_serial->es_sem, 1);
 	edge_serial->serial = serial;
 	usb_set_serial_data(serial, edge_serial);
@@ -2745,12 +2744,11 @@
 
 	/* set up our port private structures */
 	for (i = 0; i < serial->num_ports; ++i) {
-		edge_port = kmalloc (sizeof(struct edgeport_port), GFP_KERNEL);
+		edge_port = kzalloc(sizeof(struct edgeport_port), GFP_KERNEL);
 		if (edge_port == NULL) {
 			dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__);
 			goto cleanup;
 		}
-		memset (edge_port, 0, sizeof(struct edgeport_port));
 		spin_lock_init(&edge_port->ep_lock);
 		edge_port->ep_out_buf = edge_buf_alloc(EDGE_OUT_BUF_SIZE);
 		if (edge_port->ep_out_buf == NULL) {
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index a590104..426182d 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -184,10 +184,9 @@
 	struct irda_class_desc *desc;
 	int ret;
 		
-	desc = kmalloc(sizeof (struct irda_class_desc), GFP_KERNEL);
+	desc = kzalloc(sizeof (struct irda_class_desc), GFP_KERNEL);
 	if (desc == NULL) 
 		return NULL;
-	memset(desc, 0, sizeof(struct irda_class_desc));
 	
 	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev,0),
 			IU_REQ_GET_CLASS_DESC,
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 3b958e6..052b735 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -2250,12 +2250,11 @@
 	}
 
 	/* Setup private data for serial driver */
-	s_priv = kmalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
+	s_priv = kzalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
 	if (!s_priv) {
 		dbg("%s - kmalloc for keyspan_serial_private failed.", __FUNCTION__);
 		return -ENOMEM;
 	}
-	memset(s_priv, 0, sizeof(struct keyspan_serial_private));
 
 	s_priv->device_details = d_details;
 	usb_set_serial_data(serial, s_priv);
@@ -2263,12 +2262,11 @@
 	/* Now setup per port private data */
 	for (i = 0; i < serial->num_ports; i++) {
 		port = serial->port[i];
-		p_priv = kmalloc(sizeof(struct keyspan_port_private), GFP_KERNEL);
+		p_priv = kzalloc(sizeof(struct keyspan_port_private), GFP_KERNEL);
 		if (!p_priv) {
 			dbg("%s - kmalloc for keyspan_port_private (%d) failed!.", __FUNCTION__, i);
 			return (1);
 		}
-		memset(p_priv, 0, sizeof(struct keyspan_port_private));
 		p_priv->device_details = d_details;
 		usb_set_serial_port_data(port, p_priv);
 	}
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index b8b2131..87dfcd8 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -255,11 +255,9 @@
 	}
 	
 	// allocate memory for transfer buffer
-	transfer_buffer = (unsigned char *) kmalloc(transfer_buffer_length, GFP_KERNEL);  
+	transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
 	if (! transfer_buffer) {
 		return -ENOMEM;
-	} else {
-		memset(transfer_buffer, 0, transfer_buffer_length);
 	}
 	
 	// allocate write_urb
@@ -383,11 +381,10 @@
 		
 		// BEGIN DEBUG
 		/*
-		  dbg_data = (unsigned char *) kmalloc((3 *  purb->actual_length + 10) * sizeof(char), GFP_KERNEL);
+		  dbg_data = kzalloc((3 *  purb->actual_length + 10) * sizeof(char), GFP_KERNEL);
 		  if (! dbg_data) {
 		  return;
 		  }
-		  memset(dbg_data, 0, (3 *  purb->actual_length + 10));
 		  for (i = 0; i < purb->actual_length; i++) { 
 		  sprintf(dbg_data +3*i, "%02X ", data[i]); 
 		  }
@@ -518,11 +515,10 @@
 	}
 
 	// allocate memory for transfer buffer
-	transfer_buffer = (unsigned char *) kmalloc(transfer_buffer_length, GFP_KERNEL);  
+	transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
 	if (!transfer_buffer) {
 		return -ENOMEM;
 	}
-	memset(transfer_buffer, 0, transfer_buffer_length);
 
 	result = usb_control_msg( port->serial->dev, 
 				  usb_rcvctrlpipe(port->serial->dev, 0 ), 
@@ -564,11 +560,10 @@
 	}
 
 	// allocate memory for transfer buffer
-	transfer_buffer = (unsigned char *) kmalloc(transfer_buffer_length, GFP_KERNEL);
+	transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
 	if (! transfer_buffer) {
 		return -ENOMEM;
 	}
-	memset(transfer_buffer, 0, transfer_buffer_length);
 
 	if (set & TIOCM_RTS)
 		rts = 1;
@@ -655,11 +650,10 @@
 						   (struct termios __user *)arg))
 			return -EFAULT;
 		
-		settings = (unsigned char *) kmalloc(50, GFP_KERNEL);  
+		settings = kzalloc(50, GFP_KERNEL);
 		if (! settings) {
 			return -ENOBUFS;
 		}
-		memset(settings, 0, 50);
 
 		switch (priv->internal_termios.c_cflag & CBAUD) {
 		case B1200:
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index b6d6cab..35bd29b 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -348,10 +348,9 @@
 	struct mct_u232_private *priv;
 	struct usb_serial_port *port, *rport;
 
-	priv = kmalloc(sizeof(struct mct_u232_private), GFP_KERNEL);
+	priv = kzalloc(sizeof(struct mct_u232_private), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
-	memset(priv, 0, sizeof(struct mct_u232_private));
 	spin_lock_init(&priv->lock);
 	usb_set_serial_port_data(serial->port[0], priv);
 
diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c
new file mode 100644
index 0000000..7f54408
--- /dev/null
+++ b/drivers/usb/serial/navman.c
@@ -0,0 +1,157 @@
+/*
+ * Navman Serial USB driver
+ *
+ * Copyright (C) 2006 Greg Kroah-Hartman <gregkh@suse.de>
+ *
+ *	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/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include "usb-serial.h"
+
+static int debug;
+
+static struct usb_device_id id_table [] = {
+	{ USB_DEVICE(0x0a99, 0x0001) },	/* Talon Technology device */
+	{ },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static struct usb_driver navman_driver = {
+	.name =		"navman",
+	.probe =	usb_serial_probe,
+	.disconnect =	usb_serial_disconnect,
+	.id_table =	id_table,
+	.no_dynamic_id = 	1,
+};
+
+static void navman_read_int_callback(struct urb *urb, struct pt_regs *regs)
+{
+	struct usb_serial_port *port = urb->context;
+	unsigned char *data = urb->transfer_buffer;
+	struct tty_struct *tty;
+	int result;
+
+	switch (urb->status) {
+	case 0:
+		/* success */
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		/* this urb is terminated, clean up */
+		dbg("%s - urb shutting down with status: %d",
+		    __FUNCTION__, urb->status);
+		return;
+	default:
+		dbg("%s - nonzero urb status received: %d",
+		    __FUNCTION__, urb->status);
+		goto exit;
+	}
+
+	usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
+			      urb->actual_length, data);
+
+	tty = port->tty;
+	if (tty && urb->actual_length) {
+		tty_buffer_request_room(tty, urb->actual_length);
+		tty_insert_flip_string(tty, data, urb->actual_length);
+		tty_flip_buffer_push(tty);
+	}
+
+exit:
+	result = usb_submit_urb(urb, GFP_ATOMIC);
+	if (result)
+		dev_err(&urb->dev->dev,
+			"%s - Error %d submitting interrupt urb\n",
+			__FUNCTION__, result);
+}
+
+static int navman_open(struct usb_serial_port *port, struct file *filp)
+{
+	int result = 0;
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if (port->interrupt_in_urb) {
+		dbg("%s - adding interrupt input for treo", __FUNCTION__);
+		result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+		if (result)
+			dev_err(&port->dev,
+				"%s - failed submitting interrupt urb, error %d\n",
+				__FUNCTION__, result);
+	}
+	return result;
+}
+
+static void navman_close(struct usb_serial_port *port, struct file *filp)
+{
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if (port->interrupt_in_urb)
+		usb_kill_urb(port->interrupt_in_urb);
+}
+
+static int navman_write(struct usb_serial_port *port,
+			const unsigned char *buf, int count)
+{
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	/*
+	 * This device can't write any data, only read from the device
+	 * so we just silently eat all data sent to us and say it was
+	 * successfully sent.
+	 * Evil, I know, but do you have a better idea?
+	 */
+
+	return count;
+}
+
+static struct usb_serial_driver navman_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"navman",
+	},
+	.id_table =		id_table,
+	.num_interrupt_in =	NUM_DONT_CARE,
+	.num_bulk_in =		NUM_DONT_CARE,
+	.num_bulk_out =		NUM_DONT_CARE,
+	.num_ports =		1,
+	.open =			navman_open,
+	.close = 		navman_close,
+	.write = 		navman_write,
+	.read_int_callback =	navman_read_int_callback,
+};
+
+static int __init navman_init(void)
+{
+	int retval;
+
+	retval = usb_serial_register(&navman_device);
+	if (retval)
+		return retval;
+	retval = usb_register(&navman_driver);
+	if (retval)
+		usb_serial_deregister(&navman_device);
+	return retval;
+}
+
+static void __exit navman_exit(void)
+{
+	usb_deregister(&navman_driver);
+	usb_serial_deregister(&navman_device);
+}
+
+module_init(navman_init);
+module_exit(navman_exit);
+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 762d8ff..4d40704 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -204,7 +204,7 @@
 	int i;
 	int result;
 
-//	dbg("omninet_read_bulk_callback");
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	if (urb->status) {
 		dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
@@ -250,7 +250,7 @@
 
 	int			result;
 
-//	dbg("omninet_write port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	if (count == 0) {
 		dbg("%s - write request of 0 bytes", __FUNCTION__);
@@ -302,7 +302,7 @@
 	if (wport->write_urb_busy)
 		room = wport->bulk_out_size - OMNINET_HEADERLEN;
 
-//	dbg("omninet_write_room returns %d", room);
+	dbg("%s - returns %d", __FUNCTION__, room);
 
 	return (room);
 }
@@ -312,7 +312,7 @@
 /*	struct omninet_header	*header = (struct omninet_header  *) urb->transfer_buffer; */
 	struct usb_serial_port 	*port   = (struct usb_serial_port *) urb->context;
 
-//	dbg("omninet_write_bulk_callback, port %0x\n", port);
+	dbg("%s - port %0x\n", __FUNCTION__, port->number);
 
 	port->write_urb_busy = 0;
 	if (urb->status) {
@@ -321,8 +321,6 @@
 	}
 
 	schedule_work(&port->work);
-
-//	dbg("omninet_write_bulk_callback, tty %0x\n", tty);
 }
 
 
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 52bdf6f..a8455c9 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -631,13 +631,12 @@
 	/* Now setup per port private data */
 	for (i = 0; i < serial->num_ports; i++) {
 		port = serial->port[i];
-		portdata = kmalloc(sizeof(*portdata), GFP_KERNEL);
+		portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
 		if (!portdata) {
 			dbg("%s: kmalloc for option_port_private (%d) failed!.",
 					__FUNCTION__, i);
 			return (1);
 		}
-		memset(portdata, 0, sizeof(struct option_port_private));
 
 		usb_set_serial_port_data(port, portdata);
 
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 37c81c0..b3014fd 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -77,6 +77,7 @@
 	{ USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
 	{ USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
 	{ USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
+	{ USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
 	{ }					/* Terminating entry */
 };
 
@@ -218,10 +219,9 @@
 	dbg("device type: %d", type);
 
 	for (i = 0; i < serial->num_ports; ++i) {
-		priv = kmalloc (sizeof (struct pl2303_private), GFP_KERNEL);
+		priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
 		if (!priv)
 			goto cleanup;
-		memset (priv, 0x00, sizeof (struct pl2303_private));
 		spin_lock_init(&priv->lock);
 		priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
 		if (priv->buf == NULL) {
@@ -383,12 +383,11 @@
 		}
 	}
 
-	buf = kmalloc (7, GFP_KERNEL);
+	buf = kzalloc (7, GFP_KERNEL);
 	if (!buf) {
 		dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__);
 		return;
 	}
-	memset (buf, 0x00, 0x07);
 	
 	i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0),
 			     GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
@@ -828,6 +827,7 @@
 	spin_lock_irqsave(&priv->lock, flags);
 	priv->line_status = data[status_idx];
 	spin_unlock_irqrestore(&priv->lock, flags);
+	wake_up_interruptible (&priv->delta_msr_wait);
 
 exit:
 	return;
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
index 9bc4755..77901d1 100644
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -75,3 +75,7 @@
 /* Leadtek GPS 9531 (ID 0413:2101) */
 #define LEADTEK_VENDOR_ID	0x0413
 #define LEADTEK_9531_PRODUCT_ID	0x2101
+
+/* USB GSM cable from Speed Dragon Multimedia, Ltd */
+#define SPEEDDRAGON_VENDOR_ID	0x0e55
+#define SPEEDDRAGON_PRODUCT_ID	0x110b
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index c18db32..c3a2071 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -416,12 +416,11 @@
 	    dev->actconfig->desc.bConfigurationValue);
 
 	/* create device structure */
-	tdev = kmalloc(sizeof(struct ti_device), GFP_KERNEL);
+	tdev = kzalloc(sizeof(struct ti_device), GFP_KERNEL);
 	if (tdev == NULL) {
 		dev_err(&dev->dev, "%s - out of memory\n", __FUNCTION__);
 		return -ENOMEM;
 	}
-	memset(tdev, 0, sizeof(struct ti_device));
 	sema_init(&tdev->td_open_close_sem, 1);
 	tdev->td_serial = serial;
 	usb_set_serial_data(serial, tdev);
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index b5c96e7..097f4e8 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -564,12 +564,11 @@
 {
 	struct usb_serial *serial;
 
-	serial = kmalloc (sizeof (*serial), GFP_KERNEL);
+	serial = kzalloc(sizeof(*serial), GFP_KERNEL);
 	if (!serial) {
 		dev_err(&dev->dev, "%s - out of memory\n", __FUNCTION__);
 		return NULL;
 	}
-	memset (serial, 0, sizeof(*serial));
 	serial->dev = usb_get_dev(dev);
 	serial->type = driver;
 	serial->interface = interface;
@@ -778,10 +777,9 @@
 	serial->num_port_pointers = max_endpoints;
 	dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints);
 	for (i = 0; i < max_endpoints; ++i) {
-		port = kmalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
+		port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
 		if (!port)
 			goto probe_error;
-		memset(port, 0x00, sizeof(struct usb_serial_port));
 		port->number = i + serial->minor;
 		port->serial = serial;
 		spin_lock_init(&port->lock);
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 11a48d8..f5c3841 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -763,10 +763,9 @@
 	int i;
 
 	for (i = 0; i < serial->num_ports; ++i) {
-		priv = kmalloc (sizeof(*priv), GFP_KERNEL);
+		priv = kzalloc (sizeof(*priv), GFP_KERNEL);
 		if (!priv)
 			return -ENOMEM;
-		memset (priv, 0x00, sizeof(*priv));
 		spin_lock_init(&priv->lock);
 		usb_set_serial_port_data(serial->port[i], priv);
 	}
diff --git a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c
index 54e3e6c7ec..01d8971 100644
--- a/drivers/usb/storage/datafab.c
+++ b/drivers/usb/storage/datafab.c
@@ -512,13 +512,12 @@
 	};
 
 	if (!us->extra) {
-		us->extra = kmalloc(sizeof(struct datafab_info), GFP_NOIO);
+		us->extra = kzalloc(sizeof(struct datafab_info), GFP_NOIO);
 		if (!us->extra) {
 			US_DEBUGP("datafab_transport:  Gah! "
 				  "Can't allocate storage for Datafab info struct!\n");
 			return USB_STOR_TRANSPORT_ERROR;
 		}
-		memset(us->extra, 0, sizeof(struct datafab_info));
 		us->extra_destructor = datafab_info_destructor;
   		((struct datafab_info *)us->extra)->lun = -1;
 	}
diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c
index ecb328a..6831dca 100644
--- a/drivers/usb/storage/isd200.c
+++ b/drivers/usb/storage/isd200.c
@@ -1361,21 +1361,19 @@
 	struct isd200_info *info;
 
 	info = (struct isd200_info *)
-			kmalloc(sizeof(struct isd200_info), GFP_KERNEL);
+			kzalloc(sizeof(struct isd200_info), GFP_KERNEL);
 	if (!info)
 		retStatus = ISD200_ERROR;
 	else {
-		memset(info, 0, sizeof(struct isd200_info));
 		info->id = (struct hd_driveid *)
-				kmalloc(sizeof(struct hd_driveid), GFP_KERNEL);
+				kzalloc(sizeof(struct hd_driveid), GFP_KERNEL);
 		info->RegsBuf = (unsigned char *)
 				kmalloc(sizeof(info->ATARegs), GFP_KERNEL);
 		if (!info->id || !info->RegsBuf) {
 			isd200_free_info_ptrs(info);
 			kfree(info);
 			retStatus = ISD200_ERROR;
-		} else
-			memset(info->id, 0, sizeof(struct hd_driveid));
+		}
 	}
 
 	if (retStatus == ISD200_GOOD) {
@@ -1384,7 +1382,7 @@
 	} else
 		US_DEBUGP("ERROR - kmalloc failure\n");
 
-	return(retStatus);
+	return retStatus;
 }
 
 /**************************************************************************
diff --git a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c
index aff9d51..5031aa9 100644
--- a/drivers/usb/storage/jumpshot.c
+++ b/drivers/usb/storage/jumpshot.c
@@ -441,12 +441,11 @@
 	};
 
 	if (!us->extra) {
-		us->extra = kmalloc(sizeof(struct jumpshot_info), GFP_NOIO);
+		us->extra = kzalloc(sizeof(struct jumpshot_info), GFP_NOIO);
 		if (!us->extra) {
 			US_DEBUGP("jumpshot_transport:  Gah! Can't allocate storage for jumpshot info struct!\n");
 			return USB_STOR_TRANSPORT_ERROR;
 		}
-		memset(us->extra, 0, sizeof(struct jumpshot_info));
 		us->extra_destructor = jumpshot_info_destructor;
 	}
 
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index 4ef5527..5f11e19 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -47,6 +47,7 @@
 
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -271,9 +272,9 @@
 	US_DEBUGP("%s called\n", __FUNCTION__);
 
 	/* lock the device pointers and do the reset */
-	down(&(us->dev_semaphore));
+	mutex_lock(&(us->dev_mutex));
 	result = us->transport_reset(us);
-	up(&(us->dev_semaphore));
+	mutex_unlock(&us->dev_mutex);
 
 	return result < 0 ? FAILED : SUCCESS;
 }
@@ -286,9 +287,9 @@
 
 	US_DEBUGP("%s called\n", __FUNCTION__);
 
-	down(&(us->dev_semaphore));
+	mutex_lock(&(us->dev_mutex));
 	result = usb_stor_port_reset(us);
-	up(&(us->dev_semaphore));
+	mutex_unlock(&us->dev_mutex);
 
 	return result < 0 ? FAILED : SUCCESS;
 }
diff --git a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c
index 8451779..0b1b5b5 100644
--- a/drivers/usb/storage/sddr55.c
+++ b/drivers/usb/storage/sddr55.c
@@ -751,11 +751,10 @@
 	struct sddr55_card_info *info;
 
 	if (!us->extra) {
-		us->extra = kmalloc(
+		us->extra = kzalloc(
 			sizeof(struct sddr55_card_info), GFP_NOIO);
 		if (!us->extra)
 			return USB_STOR_TRANSPORT_ERROR;
-		memset(us->extra, 0, sizeof(struct sddr55_card_info));
 		us->extra_destructor = sddr55_card_info_destructor;
 	}
 
diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c
index fea176d..f2bc5c9 100644
--- a/drivers/usb/storage/shuttle_usbat.c
+++ b/drivers/usb/storage/shuttle_usbat.c
@@ -1318,12 +1318,11 @@
 	unsigned char subcountL = USBAT_ATA_LBA_ME;
 	unsigned char *status = us->iobuf;
 
-	us->extra = kmalloc(sizeof(struct usbat_info), GFP_NOIO);
+	us->extra = kzalloc(sizeof(struct usbat_info), GFP_NOIO);
 	if (!us->extra) {
 		US_DEBUGP("init_usbat: Gah! Can't allocate storage for usbat info struct!\n");
 		return 1;
 	}
-	memset(us->extra, 0, sizeof(struct usbat_info));
 	info = (struct usbat_info *) (us->extra);
 
 	/* Enable peripheral control signals */
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 31ca920..c4a9dcf 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -62,6 +62,13 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_SINGLE_LUN ),
 
+/* Reported by Rodolfo Quesada <rquesada@roqz.net> */
+UNUSUAL_DEV(  0x03ee, 0x6906, 0x0003, 0x0003,
+		"VIA Technologies Inc.",
+		"Mitsumi multi cardreader",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
 UNUSUAL_DEV(  0x03f0, 0x0107, 0x0200, 0x0200, 
 		"HP",
 		"CD-Writer+",
@@ -120,6 +127,12 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_IGNORE_RESIDUE ),
 
+/* Reported by Pete Zaitcev <zaitcev@redhat.com>, bz#176584 */
+UNUSUAL_DEV(  0x0420, 0x0001, 0x0100, 0x0100,
+		"GENERIC", "MP3 PLAYER", /* MyMusix PD-205 on the outside. */
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
 /* Reported by Olaf Hering <olh@suse.de> from novell bug #105878 */
 UNUSUAL_DEV(  0x0424, 0x0fdc, 0x0210, 0x0210,
 		"SMSC",
@@ -760,12 +773,19 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_FIX_CAPACITY ),
 
-UNUSUAL_DEV(  0x0781, 0x0001, 0x0200, 0x0200, 
+/* Submitted by Roman Hodek <roman@hodek.net> */
+UNUSUAL_DEV(  0x0781, 0x0001, 0x0200, 0x0200,
 		"Sandisk",
 		"ImageMate SDDR-05a",
 		US_SC_SCSI, US_PR_CB, NULL,
 		US_FL_SINGLE_LUN ),
 
+UNUSUAL_DEV(  0x0781, 0x0002, 0x0009, 0x0009,
+		"SanDisk Corporation",
+		"ImageMate CompactFlash USB",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY ),
+
 #ifdef CONFIG_USB_STORAGE_USBAT
 UNUSUAL_DEV(  0x0781, 0x0005, 0x0005, 0x0005,
 		"Sandisk",
@@ -1073,6 +1093,16 @@
 			0),
 #endif
 
+/*
+ * Pete Zaitcev <zaitcev@yahoo.com>, bz#164688.
+ * The device blatantly ignores LUN and returns 1 in GetMaxLUN.
+ */
+UNUSUAL_DEV( 0x0c45, 0x1060, 0x0100, 0x0100,
+		"Unknown",
+		"Unknown",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_SINGLE_LUN ),
+
 /* Submitted by Joris Struyve <joris@struyve.be> */
 UNUSUAL_DEV( 0x0d96, 0x410a, 0x0001, 0xffff,
 		"Medion",
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index dbcf239..dd108634 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -55,6 +55,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/kthread.h>
+#include <linux/mutex.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -188,7 +189,7 @@
 	struct us_data *us = usb_get_intfdata(iface);
 
 	/* Wait until no command is running */
-	down(&us->dev_semaphore);
+	mutex_lock(&us->dev_mutex);
 
 	US_DEBUGP("%s\n", __FUNCTION__);
 	if (us->suspend_resume_hook)
@@ -198,7 +199,7 @@
 	/* When runtime PM is working, we'll set a flag to indicate
 	 * whether we should autoresume when a SCSI request arrives. */
 
-	up(&us->dev_semaphore);
+	mutex_unlock(&us->dev_mutex);
 	return 0;
 }
 
@@ -206,14 +207,14 @@
 {
 	struct us_data *us = usb_get_intfdata(iface);
 
-	down(&us->dev_semaphore);
+	mutex_lock(&us->dev_mutex);
 
 	US_DEBUGP("%s\n", __FUNCTION__);
 	if (us->suspend_resume_hook)
 		(us->suspend_resume_hook)(us, US_RESUME);
 	iface->dev.power.power_state.event = PM_EVENT_ON;
 
-	up(&us->dev_semaphore);
+	mutex_unlock(&us->dev_mutex);
 	return 0;
 }
 
@@ -276,12 +277,12 @@
 		US_DEBUGP("*** thread awakened.\n");
 
 		/* lock the device pointers */
-		down(&(us->dev_semaphore));
+		mutex_lock(&(us->dev_mutex));
 
 		/* if the device has disconnected, we are free to exit */
 		if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
 			US_DEBUGP("-- exiting\n");
-			up(&(us->dev_semaphore));
+			mutex_unlock(&us->dev_mutex);
 			break;
 		}
 
@@ -370,7 +371,7 @@
 		scsi_unlock(host);
 
 		/* unlock the device pointers */
-		up(&(us->dev_semaphore));
+		mutex_unlock(&us->dev_mutex);
 	} /* for (;;) */
 
 	scsi_host_put(host);
@@ -815,8 +816,8 @@
 	 * The thread will exit when it sees the DISCONNECTING flag. */
 
 	/* Wait for the current command to finish, then remove the host */
-	down(&us->dev_semaphore);
-	up(&us->dev_semaphore);
+	mutex_lock(&us->dev_mutex);
+	mutex_unlock(&us->dev_mutex);
 
 	/* queuecommand won't accept any new commands and the control
 	 * thread won't execute a previously-queued command.  If there
@@ -870,9 +871,9 @@
 		/* For bulk-only devices, determine the max LUN value */
 		if (us->protocol == US_PR_BULK &&
 				!(us->flags & US_FL_SINGLE_LUN)) {
-			down(&us->dev_semaphore);
+			mutex_lock(&us->dev_mutex);
 			us->max_lun = usb_stor_Bulk_max_lun(us);
-			up(&us->dev_semaphore);
+			mutex_unlock(&us->dev_mutex);
 		}
 		scsi_scan_host(us_to_host(us));
 		printk(KERN_DEBUG "usb-storage: device scan complete\n");
@@ -912,7 +913,7 @@
 
 	us = host_to_us(host);
 	memset(us, 0, sizeof(struct us_data));
-	init_MUTEX(&(us->dev_semaphore));
+	mutex_init(&(us->dev_mutex));
 	init_MUTEX_LOCKED(&(us->sema));
 	init_completion(&(us->notify));
 	init_waitqueue_head(&us->delay_wait);
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
index 7259fd1..009fb095 100644
--- a/drivers/usb/storage/usb.h
+++ b/drivers/usb/storage/usb.h
@@ -49,6 +49,7 @@
 #include <linux/blkdev.h>
 #include <linux/smp_lock.h>
 #include <linux/completion.h>
+#include <linux/mutex.h>
 #include <scsi/scsi_host.h>
 
 struct us_data;
@@ -103,9 +104,9 @@
 struct us_data {
 	/* The device we're working with
 	 * It's important to note:
-	 *    (o) you must hold dev_semaphore to change pusb_dev
+	 *    (o) you must hold dev_mutex to change pusb_dev
 	 */
-	struct semaphore	dev_semaphore;	 /* protect pusb_dev */
+	struct mutex		dev_mutex;	 /* protect pusb_dev */
 	struct usb_device	*pusb_dev;	 /* this usb_device */
 	struct usb_interface	*pusb_intf;	 /* this interface */
 	struct us_unusual_dev   *unusual_dev;	 /* device-filter entry     */
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index f5079c7..fdebd60 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -899,8 +899,6 @@
 	  Choose this option if you want to use an ATI Radeon graphics card as
 	  a framebuffer device.  There are both PCI and AGP versions.  You
 	  don't need to choose this to run the Radeon in plain VGA mode.
-	  There is a product page at
-	  <http://www.ati.com/na/pages/products/pc/radeon32/index.html>.
 
 config FB_RADEON
 	tristate "ATI Radeon display support"
diff --git a/drivers/video/epson1355fb.c b/drivers/video/epson1355fb.c
index 3b0e713..0827594 100644
--- a/drivers/video/epson1355fb.c
+++ b/drivers/video/epson1355fb.c
@@ -607,6 +607,7 @@
 
 static void epson1355fb_platform_release(struct device *device)
 {
+	dev_err(device, "This driver is broken, please bug the authors so they will fix it.\n");
 }
 
 static int epson1355fb_remove(struct platform_device *dev)
diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
index 8a893ce..d9831fd 100644
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -1457,7 +1457,7 @@
 	int ret, irq;
 
 	irq = platform_get_irq(pdev, 0);
-	if (irq <= 0)
+	if (irq < 0)
 		return -EINVAL;
 
 	if (!request_mem_region(0xb0100000, 0x10000, "LCD"))
diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c
index 53208cb..77eed1f 100644
--- a/drivers/video/vfb.c
+++ b/drivers/video/vfb.c
@@ -401,6 +401,7 @@
 static void vfb_platform_release(struct device *device)
 {
 	// This is called when the reference count goes to zero.
+	dev_err(device, "This driver is broken, please bug the authors so they will fix it.\n");
 }
 
 static int __init vfb_probe(struct platform_device *dev)
diff --git a/fs/char_dev.c b/fs/char_dev.c
index 21195c4..5c36345 100644
--- a/fs/char_dev.c
+++ b/fs/char_dev.c
@@ -19,6 +19,7 @@
 #include <linux/kobject.h>
 #include <linux/kobj_map.h>
 #include <linux/cdev.h>
+#include <linux/mutex.h>
 
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
@@ -28,7 +29,7 @@
 
 #define MAX_PROBE_HASH 255	/* random */
 
-static DECLARE_MUTEX(chrdevs_lock);
+static DEFINE_MUTEX(chrdevs_lock);
 
 static struct char_device_struct {
 	struct char_device_struct *next;
@@ -88,13 +89,13 @@
 
 void *acquire_chrdev_list(void)
 {
-	down(&chrdevs_lock);
+	mutex_lock(&chrdevs_lock);
 	return get_next_chrdev(NULL);
 }
 
 void release_chrdev_list(void *dev)
 {
-	up(&chrdevs_lock);
+	mutex_unlock(&chrdevs_lock);
 	kfree(dev);
 }
 
@@ -151,7 +152,7 @@
 
 	memset(cd, 0, sizeof(struct char_device_struct));
 
-	down(&chrdevs_lock);
+	mutex_lock(&chrdevs_lock);
 
 	/* temporary */
 	if (major == 0) {
@@ -186,10 +187,10 @@
 	}
 	cd->next = *cp;
 	*cp = cd;
-	up(&chrdevs_lock);
+	mutex_unlock(&chrdevs_lock);
 	return cd;
 out:
-	up(&chrdevs_lock);
+	mutex_unlock(&chrdevs_lock);
 	kfree(cd);
 	return ERR_PTR(ret);
 }
@@ -200,7 +201,7 @@
 	struct char_device_struct *cd = NULL, **cp;
 	int i = major_to_index(major);
 
-	down(&chrdevs_lock);
+	mutex_lock(&chrdevs_lock);
 	for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
 		if ((*cp)->major == major &&
 		    (*cp)->baseminor == baseminor &&
@@ -210,7 +211,7 @@
 		cd = *cp;
 		*cp = cd->next;
 	}
-	up(&chrdevs_lock);
+	mutex_unlock(&chrdevs_lock);
 	return cd;
 }
 
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c
index d575452..40c4fc9 100644
--- a/fs/debugfs/file.c
+++ b/fs/debugfs/file.c
@@ -251,3 +251,49 @@
 }
 EXPORT_SYMBOL_GPL(debugfs_create_bool);
 
+static ssize_t read_file_blob(struct file *file, char __user *user_buf,
+			      size_t count, loff_t *ppos)
+{
+	struct debugfs_blob_wrapper *blob = file->private_data;
+	return simple_read_from_buffer(user_buf, count, ppos, blob->data,
+			blob->size);
+}
+
+static struct file_operations fops_blob = {
+	.read =		read_file_blob,
+	.open =		default_open,
+};
+
+/**
+ * debugfs_create_blob - create a file in the debugfs filesystem that is
+ * used to read and write a binary blob.
+ *
+ * @name: a pointer to a string containing the name of the file to create.
+ * @mode: the permission that the file should have
+ * @parent: a pointer to the parent dentry for this file.  This should be a
+ *          directory dentry if set.  If this paramater is NULL, then the
+ *          file will be created in the root of the debugfs filesystem.
+ * @blob: a pointer to a struct debugfs_blob_wrapper which contains a pointer
+ *        to the blob data and the size of the data.
+ *
+ * This function creates a file in debugfs with the given name that exports
+ * @blob->data as a binary blob. If the @mode variable is so set it can be
+ * read from. Writing is not supported.
+ *
+ * This function will return a pointer to a dentry if it succeeds.  This
+ * pointer must be passed to the debugfs_remove() function when the file is
+ * to be removed (no automatic cleanup happens if your module is unloaded,
+ * you are responsible here.)  If an error occurs, NULL will be returned.
+ *
+ * If debugfs is not enabled in the kernel, the value -ENODEV will be
+ * returned.  It is not wise to check for this value, but rather, check for
+ * NULL or !NULL instead as to eliminate the need for #ifdef in the calling
+ * code.
+ */
+struct dentry *debugfs_create_blob(const char *name, mode_t mode,
+				   struct dentry *parent,
+				   struct debugfs_blob_wrapper *blob)
+{
+	return debugfs_create_file(name, mode, parent, blob, &fops_blob);
+}
+EXPORT_SYMBOL_GPL(debugfs_create_blob);
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 49bd219..9ee9568 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -50,6 +50,32 @@
 	return sd;
 }
 
+/**
+ *
+ * Return -EEXIST if there is already a sysfs element with the same name for
+ * the same parent.
+ *
+ * called with parent inode's i_mutex held
+ */
+int sysfs_dirent_exist(struct sysfs_dirent *parent_sd,
+			  const unsigned char *new)
+{
+	struct sysfs_dirent * sd;
+
+	list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
+		if (sd->s_element) {
+			const unsigned char *existing = sysfs_get_name(sd);
+			if (strcmp(existing, new))
+				continue;
+			else
+				return -EEXIST;
+		}
+	}
+
+	return 0;
+}
+
+
 int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry,
 			void * element, umode_t mode, int type)
 {
@@ -102,7 +128,11 @@
 	mutex_lock(&p->d_inode->i_mutex);
 	*d = lookup_one_len(n, p, strlen(n));
 	if (!IS_ERR(*d)) {
-		error = sysfs_make_dirent(p->d_fsdata, *d, k, mode, SYSFS_DIR);
+ 		if (sysfs_dirent_exist(p->d_fsdata, n))
+  			error = -EEXIST;
+  		else
+			error = sysfs_make_dirent(p->d_fsdata, *d, k, mode,
+								SYSFS_DIR);
 		if (!error) {
 			error = sysfs_create(*d, mode, init_dir);
 			if (!error) {
@@ -302,6 +332,7 @@
 	 * Drop reference from dget() on entrance.
 	 */
 	dput(dentry);
+	kobj->dentry = NULL;
 }
 
 int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
@@ -479,7 +510,3 @@
 	.read		= generic_read_dir,
 	.readdir	= sysfs_readdir,
 };
-
-EXPORT_SYMBOL_GPL(sysfs_create_dir);
-EXPORT_SYMBOL_GPL(sysfs_remove_dir);
-EXPORT_SYMBOL_GPL(sysfs_rename_dir);
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index d0e3d84..5e83e72 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -301,9 +301,8 @@
 	/* No error? Great, allocate a buffer for the file, and store it
 	 * it in file->private_data for easy access.
 	 */
-	buffer = kmalloc(sizeof(struct sysfs_buffer),GFP_KERNEL);
+	buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL);
 	if (buffer) {
-		memset(buffer,0,sizeof(struct sysfs_buffer));
 		init_MUTEX(&buffer->sem);
 		buffer->needs_read_fill = 1;
 		buffer->ops = ops;
@@ -362,10 +361,12 @@
 {
 	struct sysfs_dirent * parent_sd = dir->d_fsdata;
 	umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG;
-	int error = 0;
+	int error = -EEXIST;
 
 	mutex_lock(&dir->d_inode->i_mutex);
-	error = sysfs_make_dirent(parent_sd, NULL, (void *) attr, mode, type);
+	if (!sysfs_dirent_exist(parent_sd, attr->name))
+		error = sysfs_make_dirent(parent_sd, NULL, (void *)attr,
+					  mode, type);
 	mutex_unlock(&dir->d_inode->i_mutex);
 
 	return error;
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index 689f7bc..4c29ac4 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -54,11 +54,10 @@
 
 	if (!sd_iattr) {
 		/* setting attributes for the first time, allocate now */
-		sd_iattr = kmalloc(sizeof(struct iattr), GFP_KERNEL);
+		sd_iattr = kzalloc(sizeof(struct iattr), GFP_KERNEL);
 		if (!sd_iattr)
 			return -ENOMEM;
 		/* assign default attributes */
-		memset(sd_iattr, 0, sizeof(struct iattr));
 		sd_iattr->ia_mode = sd->s_mode;
 		sd_iattr->ia_uid = 0;
 		sd_iattr->ia_gid = 0;
@@ -227,12 +226,16 @@
 void sysfs_hash_and_remove(struct dentry * dir, const char * name)
 {
 	struct sysfs_dirent * sd;
-	struct sysfs_dirent * parent_sd = dir->d_fsdata;
+	struct sysfs_dirent * parent_sd;
+
+	if (!dir)
+		return;
 
 	if (dir->d_inode == NULL)
 		/* no inode means this hasn't been made visible yet */
 		return;
 
+	parent_sd = dir->d_fsdata;
 	mutex_lock(&dir->d_inode->i_mutex);
 	list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
 		if (!sd->s_element)
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c
index e38d633..d2eac3c 100644
--- a/fs/sysfs/symlink.c
+++ b/fs/sysfs/symlink.c
@@ -66,6 +66,7 @@
 	if (!error)
 		return 0;
 
+	kobject_put(target);
 	kfree(sl->link_name);
 exit2:
 	kfree(sl);
@@ -82,12 +83,13 @@
 int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * name)
 {
 	struct dentry * dentry = kobj->dentry;
-	int error = 0;
+	int error = -EEXIST;
 
 	BUG_ON(!kobj || !kobj->dentry || !name);
 
 	mutex_lock(&dentry->d_inode->i_mutex);
-	error = sysfs_add_link(dentry, name, target);
+	if (!sysfs_dirent_exist(dentry->d_fsdata, name))
+		error = sysfs_add_link(dentry, name, target);
 	mutex_unlock(&dentry->d_inode->i_mutex);
 	return error;
 }
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index 3f8953e..cf11d5b 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -5,6 +5,7 @@
 extern struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent *);
 extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *));
 
+extern int sysfs_dirent_exist(struct sysfs_dirent *, const unsigned char *);
 extern int sysfs_make_dirent(struct sysfs_dirent *, struct dentry *, void *,
 				umode_t, int);
 
diff --git a/include/asm-arm/irq.h b/include/asm-arm/irq.h
index 7772432..60b5105 100644
--- a/include/asm-arm/irq.h
+++ b/include/asm-arm/irq.h
@@ -27,7 +27,7 @@
 
 /*
  * These correspond with the SA_TRIGGER_* defines, and therefore the
- * IRQRESOURCE_IRQ_* defines.
+ * IORESOURCE_IRQ_* defines.
  */
 #define __IRQT_RISEDGE	(1 << 0)
 #define __IRQT_FALEDGE	(1 << 1)
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 35de20c..9d11550 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -58,6 +58,13 @@
 		VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .;		\
 	}								\
 									\
+	/* Kernel symbol table: GPL-future-only symbols */		\
+	__ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \
+		VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .;	\
+		*(__ksymtab_gpl_future)					\
+		VMLINUX_SYMBOL(__stop___ksymtab_gpl_future) = .;	\
+	}								\
+									\
 	/* Kernel symbol table: Normal symbols */			\
 	__kcrctab         : AT(ADDR(__kcrctab) - LOAD_OFFSET) {		\
 		VMLINUX_SYMBOL(__start___kcrctab) = .;			\
@@ -72,6 +79,13 @@
 		VMLINUX_SYMBOL(__stop___kcrctab_gpl) = .;		\
 	}								\
 									\
+	/* Kernel symbol table: GPL-future-only symbols */		\
+	__kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \
+		VMLINUX_SYMBOL(__start___kcrctab_gpl_future) = .;	\
+		*(__kcrctab_gpl_future)					\
+		VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .;	\
+	}								\
+									\
 	/* Kernel symbol table: strings */				\
         __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) {	\
 		*(__ksymtab_strings)					\
diff --git a/include/asm-mips/byteorder.h b/include/asm-mips/byteorder.h
index 584f812..aefc02f 100644
--- a/include/asm-mips/byteorder.h
+++ b/include/asm-mips/byteorder.h
@@ -39,6 +39,24 @@
 }
 #define __arch__swab32(x)	___arch__swab32(x)
 
+#ifdef CONFIG_CPU_MIPS64_R2
+
+static __inline__ __attribute_const__ __u64 ___arch__swab64(__u64 x)
+{
+	__asm__(
+	"	dsbh	%0, %1			\n"
+	"	dshd	%0, %0			\n"
+	"	drotr	%0, %0, 32		\n"
+	: "=r" (x)
+	: "r" (x));
+
+	return x;
+}
+
+#define __arch__swab64(x)	___arch__swab64(x)
+
+#endif /* CONFIG_CPU_MIPS64_R2 */
+
 #endif /* CONFIG_CPU_MIPSR2 */
 
 #if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
diff --git a/include/asm-mips/compat.h b/include/asm-mips/compat.h
index 35d2604..0012bd8 100644
--- a/include/asm-mips/compat.h
+++ b/include/asm-mips/compat.h
@@ -128,17 +128,17 @@
  */
 typedef u32		compat_uptr_t;
 
-static inline void *compat_ptr(compat_uptr_t uptr)
+static inline void __user *compat_ptr(compat_uptr_t uptr)
 {
-	return (void *)(long)uptr;
+	return (void __user *)(long)uptr;
 }
 
-static inline void *compat_alloc_user_space(long len)
+static inline void __user *compat_alloc_user_space(long len)
 {
 	struct pt_regs *regs = (struct pt_regs *)
 		((unsigned long) current_thread_info() + THREAD_SIZE - 32) - 1;
 
-	return (void *) (regs->regs[29] - len);
+	return (void __user *) (regs->regs[29] - len);
 }
 #if defined (__MIPSEL__)
 #define __COMPAT_ENDIAN_SWAP__ 	1
diff --git a/include/asm-mips/io.h b/include/asm-mips/io.h
index ba1d7bb..546a17e5 100644
--- a/include/asm-mips/io.h
+++ b/include/asm-mips/io.h
@@ -40,56 +40,13 @@
  * hardware.  An example use would be for flash memory that's used for
  * execute in place.
  */
-# define __raw_ioswabb(x)	(x)
-# define __raw_ioswabw(x)	(x)
-# define __raw_ioswabl(x)	(x)
-# define __raw_ioswabq(x)	(x)
-# define ____raw_ioswabq(x)	(x)
+# define __raw_ioswabb(a,x)	(x)
+# define __raw_ioswabw(a,x)	(x)
+# define __raw_ioswabl(a,x)	(x)
+# define __raw_ioswabq(a,x)	(x)
+# define ____raw_ioswabq(a,x)	(x)
 
-/*
- * Sane hardware offers swapping of PCI/ISA I/O space accesses in hardware;
- * less sane hardware forces software to fiddle with this...
- *
- * Regardless, if the host bus endianness mismatches that of PCI/ISA, then
- * you can't have the numerical value of data and byte addresses within
- * multibyte quantities both preserved at the same time.  Hence two
- * variations of functions: non-prefixed ones that preserve the value
- * and prefixed ones that preserve byte addresses.  The latters are
- * typically used for moving raw data between a peripheral and memory (cf.
- * string I/O functions), hence the "__mem_" prefix.
- */
-#if defined(CONFIG_SWAP_IO_SPACE)
-
-# define ioswabb(x)		(x)
-# define __mem_ioswabb(x)	(x)
-# ifdef CONFIG_SGI_IP22
-/*
- * IP22 seems braindead enough to swap 16bits values in hardware, but
- * not 32bits.  Go figure... Can't tell without documentation.
- */
-#  define ioswabw(x)		(x)
-#  define __mem_ioswabw(x)	le16_to_cpu(x)
-# else
-#  define ioswabw(x)		le16_to_cpu(x)
-#  define __mem_ioswabw(x)	(x)
-# endif
-# define ioswabl(x)		le32_to_cpu(x)
-# define __mem_ioswabl(x)	(x)
-# define ioswabq(x)		le64_to_cpu(x)
-# define __mem_ioswabq(x)	(x)
-
-#else
-
-# define ioswabb(x)		(x)
-# define __mem_ioswabb(x)	(x)
-# define ioswabw(x)		(x)
-# define __mem_ioswabw(x)	cpu_to_le16(x)
-# define ioswabl(x)		(x)
-# define __mem_ioswabl(x)	cpu_to_le32(x)
-# define ioswabq(x)		(x)
-# define __mem_ioswabq(x)	cpu_to_le32(x)
-
-#endif
+/* ioswab[bwlq], __mem_ioswab[bwlq] are defined in mangle-port.h */
 
 #define IO_SPACE_LIMIT 0xffff
 
@@ -346,7 +303,7 @@
 									\
 	__mem = (void *)__swizzle_addr_##bwlq((unsigned long)(mem));	\
 									\
-	__val = pfx##ioswab##bwlq(val);					\
+	__val = pfx##ioswab##bwlq(__mem, val);				\
 									\
 	if (sizeof(type) != sizeof(u64) || sizeof(u64) == sizeof(long))	\
 		*__mem = __val;						\
@@ -401,7 +358,7 @@
 		BUG();							\
 	}								\
 									\
-	return pfx##ioswab##bwlq(__val);				\
+	return pfx##ioswab##bwlq(__mem, __val);				\
 }
 
 #define __BUILD_IOPORT_SINGLE(pfx, bwlq, type, p, slow)			\
@@ -411,10 +368,9 @@
 	volatile type *__addr;						\
 	type __val;							\
 									\
-	port = __swizzle_addr_##bwlq(port);				\
-	__addr = (void *)(mips_io_port_base + port);			\
+	__addr = (void *)__swizzle_addr_##bwlq(mips_io_port_base + port); \
 									\
-	__val = pfx##ioswab##bwlq(val);					\
+	__val = pfx##ioswab##bwlq(__addr, val);				\
 									\
 	/* Really, we want this to be atomic */				\
 	BUILD_BUG_ON(sizeof(type) > sizeof(unsigned long));		\
@@ -428,15 +384,14 @@
 	volatile type *__addr;						\
 	type __val;							\
 									\
-	port = __swizzle_addr_##bwlq(port);				\
-	__addr = (void *)(mips_io_port_base + port);			\
+	__addr = (void *)__swizzle_addr_##bwlq(mips_io_port_base + port); \
 									\
 	BUILD_BUG_ON(sizeof(type) > sizeof(unsigned long));		\
 									\
 	__val = *__addr;						\
 	slow;								\
 									\
-	return pfx##ioswab##bwlq(__val);				\
+	return pfx##ioswab##bwlq(__addr, __val);			\
 }
 
 #define __BUILD_MEMORY_PFX(bus, bwlq, type)				\
diff --git a/include/asm-mips/mach-cobalt/cobalt.h b/include/asm-mips/mach-cobalt/cobalt.h
index 78e1df2..b3c5ecb 100644
--- a/include/asm-mips/mach-cobalt/cobalt.h
+++ b/include/asm-mips/mach-cobalt/cobalt.h
@@ -113,4 +113,6 @@
 # define COBALT_KEY_SELECT	(1 << 7)
 # define COBALT_KEY_MASK	0xfe
 
+#define COBALT_UART		((volatile unsigned char *) CKSEG1ADDR(0x1c800000))
+
 #endif /* __ASM_COBALT_H */
diff --git a/include/asm-mips/mach-generic/mangle-port.h b/include/asm-mips/mach-generic/mangle-port.h
index 4a98d83..6e1b0c0 100644
--- a/include/asm-mips/mach-generic/mangle-port.h
+++ b/include/asm-mips/mach-generic/mangle-port.h
@@ -13,4 +13,40 @@
 #define __swizzle_addr_l(port)	(port)
 #define __swizzle_addr_q(port)	(port)
 
+/*
+ * Sane hardware offers swapping of PCI/ISA I/O space accesses in hardware;
+ * less sane hardware forces software to fiddle with this...
+ *
+ * Regardless, if the host bus endianness mismatches that of PCI/ISA, then
+ * you can't have the numerical value of data and byte addresses within
+ * multibyte quantities both preserved at the same time.  Hence two
+ * variations of functions: non-prefixed ones that preserve the value
+ * and prefixed ones that preserve byte addresses.  The latters are
+ * typically used for moving raw data between a peripheral and memory (cf.
+ * string I/O functions), hence the "__mem_" prefix.
+ */
+#if defined(CONFIG_SWAP_IO_SPACE)
+
+# define ioswabb(a,x)		(x)
+# define __mem_ioswabb(a,x)	(x)
+# define ioswabw(a,x)		le16_to_cpu(x)
+# define __mem_ioswabw(a,x)	(x)
+# define ioswabl(a,x)		le32_to_cpu(x)
+# define __mem_ioswabl(a,x)	(x)
+# define ioswabq(a,x)		le64_to_cpu(x)
+# define __mem_ioswabq(a,x)	(x)
+
+#else
+
+# define ioswabb(a,x)		(x)
+# define __mem_ioswabb(a,x)	(x)
+# define ioswabw(a,x)		(x)
+# define __mem_ioswabw(a,x)	cpu_to_le16(x)
+# define ioswabl(a,x)		(x)
+# define __mem_ioswabl(a,x)	cpu_to_le32(x)
+# define ioswabq(a,x)		(x)
+# define __mem_ioswabq(a,x)	cpu_to_le32(x)
+
+#endif
+
 #endif /* __ASM_MACH_GENERIC_MANGLE_PORT_H */
diff --git a/include/asm-mips/mach-ip27/mangle-port.h b/include/asm-mips/mach-ip27/mangle-port.h
index f76c448..d615312 100644
--- a/include/asm-mips/mach-ip27/mangle-port.h
+++ b/include/asm-mips/mach-ip27/mangle-port.h
@@ -13,4 +13,13 @@
 #define __swizzle_addr_l(port)	(port)
 #define __swizzle_addr_q(port)	(port)
 
+# define ioswabb(a,x)		(x)
+# define __mem_ioswabb(a,x)	(x)
+# define ioswabw(a,x)		(x)
+# define __mem_ioswabw(a,x)	cpu_to_le16(x)
+# define ioswabl(a,x)		(x)
+# define __mem_ioswabl(a,x)	cpu_to_le32(x)
+# define ioswabq(a,x)		(x)
+# define __mem_ioswabq(a,x)	cpu_to_le32(x)
+
 #endif /* __ASM_MACH_IP27_MANGLE_PORT_H */
diff --git a/include/asm-mips/mach-ip32/mangle-port.h b/include/asm-mips/mach-ip32/mangle-port.h
index 6e25b52..81320eb 100644
--- a/include/asm-mips/mach-ip32/mangle-port.h
+++ b/include/asm-mips/mach-ip32/mangle-port.h
@@ -14,4 +14,13 @@
 #define __swizzle_addr_l(port)	(port)
 #define __swizzle_addr_q(port)	(port)
 
+# define ioswabb(a,x)		(x)
+# define __mem_ioswabb(a,x)	(x)
+# define ioswabw(a,x)		(x)
+# define __mem_ioswabw(a,x)	cpu_to_le16(x)
+# define ioswabl(a,x)		(x)
+# define __mem_ioswabl(a,x)	cpu_to_le32(x)
+# define ioswabq(a,x)		(x)
+# define __mem_ioswabq(a,x)	cpu_to_le32(x)
+
 #endif /* __ASM_MACH_IP32_MANGLE_PORT_H */
diff --git a/include/asm-mips/mach-mips/cpu-feature-overrides.h b/include/asm-mips/mach-mips/cpu-feature-overrides.h
index 9f92aed..e06af6c 100644
--- a/include/asm-mips/mach-mips/cpu-feature-overrides.h
+++ b/include/asm-mips/mach-mips/cpu-feature-overrides.h
@@ -29,7 +29,11 @@
 /* #define cpu_has_prefetch	? */
 #define cpu_has_mcheck		1
 /* #define cpu_has_ejtag	? */
+#ifdef CONFIG_CPU_HAS_LLSC
 #define cpu_has_llsc		1
+#else
+#define cpu_has_llsc		0
+#endif
 /* #define cpu_has_vtag_icache	? */
 /* #define cpu_has_dc_aliases	? */
 /* #define cpu_has_ic_fills_f_dc ? */
diff --git a/include/asm-mips/mmu_context.h b/include/asm-mips/mmu_context.h
index 19cdf76..61cf225 100644
--- a/include/asm-mips/mmu_context.h
+++ b/include/asm-mips/mmu_context.h
@@ -33,12 +33,7 @@
 	write_c0_context((unsigned long) smp_processor_id() << 25);	\
 	TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir)
 #endif
-#if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64)
-#define TLBMISS_HANDLER_SETUP()						\
-	write_c0_context((unsigned long) &pgd_current[smp_processor_id()] << 23); \
-	TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir)
-#endif
-#if defined(CONFIG_64BIT) && defined(CONFIG_BUILD_ELF64)
+#ifdef CONFIG_64BIT
 #define TLBMISS_HANDLER_SETUP()						\
 	write_c0_context((unsigned long) smp_processor_id() << 26);	\
 	TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir)
diff --git a/include/asm-mips/pgtable-32.h b/include/asm-mips/pgtable-32.h
index 0cff64c..4d6bc45 100644
--- a/include/asm-mips/pgtable-32.h
+++ b/include/asm-mips/pgtable-32.h
@@ -206,7 +206,7 @@
 	/* fixme */
 #define pte_to_pgoff(_pte) (((_pte).pte_high >> 6) + ((_pte).pte_high & 0x3f))
 #define pgoff_to_pte(off) \
- 	((pte_t){(((off) & 0x3f) + ((off) << 6) + _PAGE_FILE)})
+	((pte_t){(((off) & 0x3f) + ((off) << 6) + _PAGE_FILE)})
 
 #else
 #define pte_to_pgoff(_pte) \
diff --git a/include/asm-mips/r4kcache.h b/include/asm-mips/r4kcache.h
index 0bcb79a..90c3747 100644
--- a/include/asm-mips/r4kcache.h
+++ b/include/asm-mips/r4kcache.h
@@ -303,5 +303,6 @@
 __BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, )
 /* blast_inv_dcache_range */
 __BUILD_BLAST_CACHE_RANGE(inv_d, dcache, Hit_Invalidate_D, )
+__BUILD_BLAST_CACHE_RANGE(inv_s, scache, Hit_Invalidate_SD, )
 
 #endif /* _ASM_R4KCACHE_H */
diff --git a/include/asm-mips/signal.h b/include/asm-mips/signal.h
index 6fe903e..d8349e4 100644
--- a/include/asm-mips/signal.h
+++ b/include/asm-mips/signal.h
@@ -147,16 +147,34 @@
 
 /* IRIX compatible stack_t  */
 typedef struct sigaltstack {
-	void *ss_sp;
+	void __user *ss_sp;
 	size_t ss_size;
 	int ss_flags;
 } stack_t;
 
 #ifdef __KERNEL__
 #include <asm/sigcontext.h>
+#include <asm/siginfo.h>
 
 #define ptrace_signal_deliver(regs, cookie) do { } while (0)
 
+struct pt_regs;
+extern void do_signal(struct pt_regs *regs);
+extern void do_signal32(struct pt_regs *regs);
+
+extern int setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
+        int signr, sigset_t *set);
+extern int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
+        int signr, sigset_t *set, siginfo_t *info);
+
+extern int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
+        int signr, sigset_t *set);
+extern int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
+        int signr, sigset_t *set, siginfo_t *info);
+
+extern int setup_rt_frame_n32(struct k_sigaction * ka, struct pt_regs *regs,
+        int signr, sigset_t *set, siginfo_t *info);
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_SIGNAL_H */
diff --git a/include/asm-mips/sn/klconfig.h b/include/asm-mips/sn/klconfig.h
index d028e28..9709ff7 100644
--- a/include/asm-mips/sn/klconfig.h
+++ b/include/asm-mips/sn/klconfig.h
@@ -99,7 +99,7 @@
 #define ENABLE_BOARD 		0x01
 #define FAILED_BOARD  		0x02
 #define DUPLICATE_BOARD 	0x04    /* Boards like midplanes/routers which
-                                   	   are discovered twice. Use one of them */
+					   are discovered twice. Use one of them */
 #define VISITED_BOARD		0x08	/* Used for compact hub numbering. */
 #define LOCAL_MASTER_IO6	0x10 	/* master io6 for that node */
 #define GLOBAL_MASTER_IO6	0x20
diff --git a/include/asm-mips/sn/mapped_kernel.h b/include/asm-mips/sn/mapped_kernel.h
index 3a17846d..59edb20 100644
--- a/include/asm-mips/sn/mapped_kernel.h
+++ b/include/asm-mips/sn/mapped_kernel.h
@@ -23,11 +23,7 @@
 #include <linux/config.h>
 #include <asm/addrspace.h>
 
-#ifdef CONFIG_BUILD_ELF64
 #define REP_BASE	CAC_BASE
-#else
-#define REP_BASE	CKSEG0
-#endif
 
 #ifdef CONFIG_MAPPED_KERNEL
 
diff --git a/include/asm-mips/sn/sn0/hubio.h b/include/asm-mips/sn/sn0/hubio.h
index 80cf6a5..f314da2 100644
--- a/include/asm-mips/sn/sn0/hubio.h
+++ b/include/asm-mips/sn/sn0/hubio.h
@@ -229,7 +229,7 @@
                         icsr_llp_en:	 1,	/* LLP enable bit */
                  	icsr_rsvd2:	 1,     /* reserver */
                         icsr_wrm_reset:	 1,	/* Warm reset bit */
-    			icsr_rsvd1:	 2,	/* Data ready offset */
+			icsr_rsvd1:	 2,	/* Data ready offset */
                         icsr_null_to:	 6;	/* Null timeout   */
 
         } icsr_fields_s;
@@ -274,9 +274,9 @@
 	u64 perf_sel_reg;
 	struct {
 		u64 	perf_rsvd  : 48,
-		        perf_icct  :  8,
-		        perf_ippr1 :  4,
-  		        perf_ippr0 :  4;
+			perf_icct  :  8,
+		 	perf_ippr1 :  4,
+			perf_ippr0 :  4;
 	} perf_sel_bits;
 } io_perf_sel_t;
 
@@ -287,8 +287,8 @@
 	u64	perf_cnt;
 	struct {
 		u64	perf_rsvd1 : 32,
-  			        perf_rsvd2 : 12,
-  			        perf_cnt   : 20;
+			perf_rsvd2 : 12,
+			perf_cnt   : 20;
 	} perf_cnt_bits;
 } io_perf_cnt_t;
 
diff --git a/include/asm-mips/stackframe.h b/include/asm-mips/stackframe.h
index a8919dc..2acf3e8 100644
--- a/include/asm-mips/stackframe.h
+++ b/include/asm-mips/stackframe.h
@@ -63,17 +63,7 @@
 		addu	k1, k0
 		LONG_L	k1, %lo(kernelsp)(k1)
 #endif
-#if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64)
-		MFC0	k1, CP0_CONTEXT
-		dsra	k1, 23
-		lui	k0, %hi(pgd_current)
-		addiu	k0, %lo(pgd_current)
-		dsubu	k1, k0
-		lui	k0, %hi(kernelsp)
-		daddu	k1, k0
-		LONG_L	k1, %lo(kernelsp)(k1)
-#endif
-#if defined(CONFIG_64BIT) && defined(CONFIG_BUILD_ELF64)
+#ifdef CONFIG_64BIT
 		MFC0	k1, CP0_CONTEXT
 		lui	k0, %highest(kernelsp)
 		dsrl	k1, 23
@@ -91,11 +81,7 @@
 		mfc0	\temp, CP0_CONTEXT
 		srl	\temp, 23
 #endif
-#if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64)
-		lw	\temp, TI_CPU(gp)
-		dsll	\temp, 3
-#endif
-#if defined(CONFIG_64BIT) && defined(CONFIG_BUILD_ELF64)
+#ifdef CONFIG_64BIT
 		MFC0	\temp, CP0_CONTEXT
 		dsrl	\temp, 23
 #endif
@@ -103,7 +89,7 @@
 		.endm
 #else
 		.macro	get_saved_sp	/* Uniprocessor variation */
-#if defined(CONFIG_64BIT) && defined(CONFIG_BUILD_ELF64)
+#ifdef CONFIG_64BIT
 		lui	k1, %highest(kernelsp)
 		daddiu	k1, %higher(kernelsp)
 		dsll	k1, k1, 16
diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h
index ddae9ba..4097fac 100644
--- a/include/asm-mips/system.h
+++ b/include/asm-mips/system.h
@@ -286,10 +286,10 @@
 static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
 {
 	switch (size) {
-		case 4:
-			return __xchg_u32(ptr, x);
-		case 8:
-			return __xchg_u64(ptr, x);
+	case 4:
+		return __xchg_u32(ptr, x);
+	case 8:
+		return __xchg_u64(ptr, x);
 	}
 	__xchg_called_with_bad_pointer();
 	return x;
diff --git a/include/asm-mips/thread_info.h b/include/asm-mips/thread_info.h
index fa193f8..f8d97da 100644
--- a/include/asm-mips/thread_info.h
+++ b/include/asm-mips/thread_info.h
@@ -31,7 +31,7 @@
 	int			preempt_count;	/* 0 => preemptable, <0 => BUG */
 
 	mm_segment_t		addr_limit;	/* thread address space:
-					 	   0-0xBFFFFFFF for user-thead
+						   0-0xBFFFFFFF for user-thead
 						   0-0xFFFFFFFF for kernel-thread
 						*/
 	struct restart_block	restart_block;
diff --git a/include/linux/amba/clcd.h b/include/linux/amba/clcd.h
index 6b8d73d..9cf64b1 100644
--- a/include/linux/amba/clcd.h
+++ b/include/linux/amba/clcd.h
@@ -54,6 +54,7 @@
 #define CNTL_LCDBPP4		(2 << 1)
 #define CNTL_LCDBPP8		(3 << 1)
 #define CNTL_LCDBPP16		(4 << 1)
+#define CNTL_LCDBPP16_565	(6 << 1)
 #define CNTL_LCDBPP24		(5 << 1)
 #define CNTL_LCDBW		(1 << 4)
 #define CNTL_LCDTFT		(1 << 5)
@@ -209,7 +210,16 @@
 		val |= CNTL_LCDBPP8;
 		break;
 	case 16:
-		val |= CNTL_LCDBPP16;
+		/*
+		 * PL110 cannot choose between 5551 and 565 modes in
+		 * its control register
+		 */
+		if ((fb->dev->periphid & 0x000fffff) == 0x00041110)
+			val |= CNTL_LCDBPP16;
+		else if (fb->fb.var.green.length == 5)
+			val |= CNTL_LCDBPP16;
+		else
+			val |= CNTL_LCDBPP16_565;
 		break;
 	case 32:
 		val |= CNTL_LCDBPP24;
diff --git a/include/linux/ata.h b/include/linux/ata.h
index 94f77cc..b02a16c 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -267,6 +267,16 @@
 	  ((u64) (id)[(n) + 1] << 16) |	\
 	  ((u64) (id)[(n) + 0]) )
 
+static inline unsigned int ata_id_major_version(const u16 *id)
+{
+	unsigned int mver;
+
+	for (mver = 14; mver >= 1; mver--)
+		if (id[ATA_ID_MAJOR_VER] & (1 << mver))
+			break;
+	return mver;
+}
+
 static inline int ata_id_current_chs_valid(const u16 *id)
 {
 	/* For ATA-1 devices, if the INITIALIZE DEVICE PARAMETERS command 
@@ -302,4 +312,16 @@
 			== ATA_DRDY);
 }
 
+static inline int lba_28_ok(u64 block, u32 n_block)
+{
+	/* check the ending block number */
+	return ((block + n_block - 1) < ((u64)1 << 28)) && (n_block <= 256);
+}
+
+static inline int lba_48_ok(u64 block, u32 n_block)
+{
+	/* check the ending block number */
+	return ((block + n_block - 1) < ((u64)1 << 48)) && (n_block <= 65536);
+}
+
 #endif /* __LINUX_ATA_H__ */
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index 0ed1d48..d612b89 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -32,7 +32,7 @@
 };
 
 extern int register_cpu(struct cpu *, int, struct node *);
-extern struct sys_device *get_cpu_sysdev(int cpu);
+extern struct sys_device *get_cpu_sysdev(unsigned cpu);
 #ifdef CONFIG_HOTPLUG_CPU
 extern void unregister_cpu(struct cpu *, struct node *);
 #endif
diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h
index a5fa6a6..4b0428e 100644
--- a/include/linux/debugfs.h
+++ b/include/linux/debugfs.h
@@ -21,6 +21,11 @@
 
 struct file_operations;
 
+struct debugfs_blob_wrapper {
+	void *data;
+	unsigned long size;
+};
+
 #if defined(CONFIG_DEBUG_FS)
 struct dentry *debugfs_create_file(const char *name, mode_t mode,
 				   struct dentry *parent, void *data,
@@ -39,6 +44,9 @@
 struct dentry *debugfs_create_bool(const char *name, mode_t mode,
 				  struct dentry *parent, u32 *value);
 
+struct dentry *debugfs_create_blob(const char *name, mode_t mode,
+				  struct dentry *parent,
+				  struct debugfs_blob_wrapper *blob);
 #else
 
 #include <linux/err.h>
@@ -94,6 +102,13 @@
 	return ERR_PTR(-ENODEV);
 }
 
+static inline struct dentry *debugfs_create_blob(const char *name, mode_t mode,
+				  struct dentry *parent,
+				  struct debugfs_blob_wrapper *blob)
+{
+	return ERR_PTR(-ENODEV);
+}
+
 #endif
 
 #endif
diff --git a/include/linux/device.h b/include/linux/device.h
index 58df18d..5b595fd 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -424,6 +424,8 @@
 	dev_printk(KERN_INFO , dev , format , ## arg)
 #define dev_warn(dev, format, arg...)		\
 	dev_printk(KERN_WARNING , dev , format , ## arg)
+#define dev_notice(dev, format, arg...)		\
+	dev_printk(KERN_NOTICE , dev , format , ## arg)
 
 /* Create alias, so I can be autoloaded. */
 #define MODULE_ALIAS_CHARDEV(major,minor) \
diff --git a/include/linux/dvb/audio.h b/include/linux/dvb/audio.h
index 2b87970..0874a67 100644
--- a/include/linux/dvb/audio.h
+++ b/include/linux/dvb/audio.h
@@ -121,4 +121,17 @@
 #define AUDIO_SET_ATTRIBUTES       _IOW('o', 17, audio_attributes_t)
 #define AUDIO_SET_KARAOKE          _IOW('o', 18, audio_karaoke_t)
 
+/**
+ * AUDIO_GET_PTS
+ *
+ * Read the 33 bit presentation time stamp as defined
+ * in ITU T-REC-H.222.0 / ISO/IEC 13818-1.
+ *
+ * The PTS should belong to the currently played
+ * frame if possible, but may also be a value close to it
+ * like the PTS of the last decoded frame or the last PTS
+ * extracted by the PES parser.
+ */
+#define AUDIO_GET_PTS              _IOR('o', 19, __u64)
+
 #endif /* _DVBAUDIO_H_ */
diff --git a/include/linux/dvb/video.h b/include/linux/dvb/video.h
index b81e58b..faebfda 100644
--- a/include/linux/dvb/video.h
+++ b/include/linux/dvb/video.h
@@ -200,4 +200,17 @@
 #define VIDEO_GET_SIZE             _IOR('o', 55, video_size_t)
 #define VIDEO_GET_FRAME_RATE       _IOR('o', 56, unsigned int)
 
+/**
+ * VIDEO_GET_PTS
+ *
+ * Read the 33 bit presentation time stamp as defined
+ * in ITU T-REC-H.222.0 / ISO/IEC 13818-1.
+ *
+ * The PTS should belong to the currently played
+ * frame if possible, but may also be a value close to it
+ * like the PTS of the last decoded frame or the last PTS
+ * extracted by the PES parser.
+ */
+#define VIDEO_GET_PTS              _IOR('o', 57, __u64)
+
 #endif /*_DVBVIDEO_H_*/
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index a9f1cfd..a3a0e07 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -83,5 +83,32 @@
 #define FSL_I2C_DEV_SEPARATE_DFSRR	0x00000001
 #define FSL_I2C_DEV_CLOCK_5200		0x00000002
 
+
+enum fsl_usb2_operating_modes {
+	FSL_USB2_MPH_HOST,
+	FSL_USB2_DR_HOST,
+	FSL_USB2_DR_DEVICE,
+	FSL_USB2_DR_OTG,
+};
+
+enum fsl_usb2_phy_modes {
+	FSL_USB2_PHY_NONE,
+	FSL_USB2_PHY_ULPI,
+	FSL_USB2_PHY_UTMI,
+	FSL_USB2_PHY_UTMI_WIDE,
+	FSL_USB2_PHY_SERIAL,
+};
+
+struct fsl_usb2_platform_data {
+	/* board specific information */
+	enum fsl_usb2_operating_modes operating_mode;
+	enum fsl_usb2_phy_modes phy_mode;
+	unsigned int port_enables;
+};
+
+/* Flags in fsl_usb2_mph_platform_data */
+#define FSL_USB2_PORT0_ENABLED	0x00000001
+#define FSL_USB2_PORT1_ENABLED	0x00000002
+
 #endif				/* _FSL_DEVICE_H_ */
 #endif				/* __KERNEL__ */
diff --git a/include/linux/kobj_map.h b/include/linux/kobj_map.h
index cbe7d80..bafe178 100644
--- a/include/linux/kobj_map.h
+++ b/include/linux/kobj_map.h
@@ -1,6 +1,6 @@
 #ifdef __KERNEL__
 
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 typedef struct kobject *kobj_probe_t(dev_t, int *, void *);
 struct kobj_map;
@@ -9,6 +9,6 @@
 	     kobj_probe_t *, int (*)(dev_t, void *), void *);
 void kobj_unmap(struct kobj_map *, dev_t, unsigned long);
 struct kobject *kobj_lookup(struct kobj_map *, dev_t, int *);
-struct kobj_map *kobj_map_init(kobj_probe_t *, struct semaphore *);
+struct kobj_map *kobj_map_init(kobj_probe_t *, struct mutex *);
 
 #endif
diff --git a/include/linux/kobject.h b/include/linux/kobject.h
index c374b5f..4cb1214 100644
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -80,6 +80,8 @@
 extern struct kobject * kobject_get(struct kobject *);
 extern void kobject_put(struct kobject *);
 
+extern struct kobject *kobject_add_dir(struct kobject *, const char *);
+
 extern char * kobject_get_path(struct kobject *, gfp_t);
 
 struct kobj_type {
@@ -255,7 +257,7 @@
 extern int subsys_create_file(struct subsystem * , struct subsys_attribute *);
 extern void subsys_remove_file(struct subsystem * , struct subsys_attribute *);
 
-#if defined(CONFIG_HOTPLUG) & defined(CONFIG_NET)
+#if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET)
 void kobject_uevent(struct kobject *kobj, enum kobject_action action);
 
 int add_uevent_var(char **envp, int num_envp, int *cur_index,
diff --git a/include/linux/libata.h b/include/linux/libata.h
index c91be5e..239408e 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -35,7 +35,8 @@
 #include <linux/workqueue.h>
 
 /*
- * compile-time options
+ * compile-time options: to be removed as soon as all the drivers are
+ * converted to the new debugging mechanism
  */
 #undef ATA_DEBUG		/* debugging output */
 #undef ATA_VERBOSE_DEBUG	/* yet more debugging output */
@@ -61,15 +62,37 @@
 
 #define BPRINTK(fmt, args...) if (ap->flags & ATA_FLAG_DEBUGMSG) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args)
 
-#ifdef ATA_NDEBUG
-#define assert(expr)
-#else
-#define assert(expr) \
-        if(unlikely(!(expr))) {                                   \
-        printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \
-        #expr,__FILE__,__FUNCTION__,__LINE__);          \
-        }
-#endif
+/* NEW: debug levels */
+#define HAVE_LIBATA_MSG 1
+
+enum {
+	ATA_MSG_DRV	= 0x0001,
+	ATA_MSG_INFO	= 0x0002,
+	ATA_MSG_PROBE	= 0x0004,
+	ATA_MSG_WARN	= 0x0008,
+	ATA_MSG_MALLOC	= 0x0010,
+	ATA_MSG_CTL	= 0x0020,
+	ATA_MSG_INTR	= 0x0040,
+	ATA_MSG_ERR	= 0x0080,
+};
+
+#define ata_msg_drv(p)    ((p)->msg_enable & ATA_MSG_DRV)
+#define ata_msg_info(p)   ((p)->msg_enable & ATA_MSG_INFO)
+#define ata_msg_probe(p)  ((p)->msg_enable & ATA_MSG_PROBE)
+#define ata_msg_warn(p)   ((p)->msg_enable & ATA_MSG_WARN)
+#define ata_msg_malloc(p) ((p)->msg_enable & ATA_MSG_MALLOC)
+#define ata_msg_ctl(p)    ((p)->msg_enable & ATA_MSG_CTL)
+#define ata_msg_intr(p)   ((p)->msg_enable & ATA_MSG_INTR)
+#define ata_msg_err(p)    ((p)->msg_enable & ATA_MSG_ERR)
+
+static inline u32 ata_msg_init(int dval, int default_msg_enable_bits)
+{
+	if (dval < 0 || dval >= (sizeof(u32) * 8))
+		return default_msg_enable_bits; /* should be 0x1 - only driver info msgs */
+	if (!dval)
+		return 0;
+	return (1 << dval) - 1;
+}
 
 /* defines only for the constants which don't work well as enums */
 #define ATA_TAG_POISON		0xfafbfcfdU
@@ -99,8 +122,7 @@
 	/* struct ata_device stuff */
 	ATA_DFLAG_LBA48		= (1 << 0), /* device supports LBA48 */
 	ATA_DFLAG_PIO		= (1 << 1), /* device currently in PIO mode */
-	ATA_DFLAG_LOCK_SECTORS	= (1 << 2), /* don't adjust max_sectors */
-	ATA_DFLAG_LBA		= (1 << 3), /* device supports LBA */
+	ATA_DFLAG_LBA		= (1 << 2), /* device supports LBA */
 
 	ATA_DEV_UNKNOWN		= 0,	/* unknown device */
 	ATA_DEV_ATA		= 1,	/* ATA device */
@@ -115,9 +137,9 @@
 	ATA_FLAG_PORT_DISABLED	= (1 << 2), /* port is disabled, ignore it */
 	ATA_FLAG_SATA		= (1 << 3),
 	ATA_FLAG_NO_LEGACY	= (1 << 4), /* no legacy mode check */
-	ATA_FLAG_SRST		= (1 << 5), /* use ATA SRST, not E.D.D. */
+	ATA_FLAG_SRST		= (1 << 5), /* (obsolete) use ATA SRST, not E.D.D. */
 	ATA_FLAG_MMIO		= (1 << 6), /* use MMIO, not PIO */
-	ATA_FLAG_SATA_RESET	= (1 << 7), /* use COMRESET */
+	ATA_FLAG_SATA_RESET	= (1 << 7), /* (obsolete) use COMRESET */
 	ATA_FLAG_PIO_DMA	= (1 << 8), /* PIO cmds via DMA */
 	ATA_FLAG_NOINTR		= (1 << 9), /* FIXME: Remove this once
 					     * proper HSM is in place. */
@@ -129,10 +151,14 @@
 	ATA_FLAG_PIO_LBA48	= (1 << 13), /* Host DMA engine is LBA28 only */
 	ATA_FLAG_IRQ_MASK	= (1 << 14), /* Mask IRQ in PIO xfers */
 
+	ATA_FLAG_FLUSH_PORT_TASK = (1 << 15), /* Flush port task */
+	ATA_FLAG_IN_EH		= (1 << 16), /* EH in progress */
+
 	ATA_QCFLAG_ACTIVE	= (1 << 1), /* cmd not yet ack'd to scsi lyer */
 	ATA_QCFLAG_SG		= (1 << 3), /* have s/g table? */
 	ATA_QCFLAG_SINGLE	= (1 << 4), /* no s/g, just a single buffer */
 	ATA_QCFLAG_DMAMAP	= ATA_QCFLAG_SG | ATA_QCFLAG_SINGLE,
+	ATA_QCFLAG_EH_SCHEDULED = (1 << 5), /* EH scheduled */
 
 	/* various lengths of time */
 	ATA_TMOUT_EDD		= 5 * HZ,	/* heuristic */
@@ -162,11 +188,19 @@
 	PORT_DISABLED		= 2,
 
 	/* encoding various smaller bitmaps into a single
-	 * unsigned long bitmap
+	 * unsigned int bitmap
 	 */
-	ATA_SHIFT_UDMA		= 0,
-	ATA_SHIFT_MWDMA		= 8,
-	ATA_SHIFT_PIO		= 11,
+	ATA_BITS_PIO		= 5,
+	ATA_BITS_MWDMA		= 3,
+	ATA_BITS_UDMA		= 8,
+
+	ATA_SHIFT_PIO		= 0,
+	ATA_SHIFT_MWDMA		= ATA_SHIFT_PIO + ATA_BITS_PIO,
+	ATA_SHIFT_UDMA		= ATA_SHIFT_MWDMA + ATA_BITS_MWDMA,
+
+	ATA_MASK_PIO		= ((1 << ATA_BITS_PIO) - 1) << ATA_SHIFT_PIO,
+	ATA_MASK_MWDMA		= ((1 << ATA_BITS_MWDMA) - 1) << ATA_SHIFT_MWDMA,
+	ATA_MASK_UDMA		= ((1 << ATA_BITS_UDMA) - 1) << ATA_SHIFT_UDMA,
 
 	/* size of buffer to pad xfers ending on unaligned boundaries */
 	ATA_DMA_PAD_SZ		= 4,
@@ -189,10 +223,15 @@
 };
 
 enum ata_completion_errors {
-	AC_ERR_OTHER		= (1 << 0),
-	AC_ERR_DEV		= (1 << 1),
-	AC_ERR_ATA_BUS		= (1 << 2),
-	AC_ERR_HOST_BUS		= (1 << 3),
+	AC_ERR_DEV		= (1 << 0), /* device reported error */
+	AC_ERR_HSM		= (1 << 1), /* host state machine violation */
+	AC_ERR_TIMEOUT		= (1 << 2), /* timeout */
+	AC_ERR_MEDIA		= (1 << 3), /* media error */
+	AC_ERR_ATA_BUS		= (1 << 4), /* ATA bus error */
+	AC_ERR_HOST_BUS		= (1 << 5), /* host bus error */
+	AC_ERR_SYSTEM		= (1 << 6), /* system error */
+	AC_ERR_INVALID		= (1 << 7), /* invalid argument */
+	AC_ERR_OTHER		= (1 << 8), /* unknown */
 };
 
 /* forward declarations */
@@ -202,7 +241,10 @@
 struct ata_queued_cmd;
 
 /* typedefs */
-typedef int (*ata_qc_cb_t) (struct ata_queued_cmd *qc);
+typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc);
+typedef void (*ata_probeinit_fn_t)(struct ata_port *);
+typedef int (*ata_reset_fn_t)(struct ata_port *, int, unsigned int *);
+typedef void (*ata_postreset_fn_t)(struct ata_port *ap, unsigned int *);
 
 struct ata_ioports {
 	unsigned long		cmd_addr;
@@ -305,7 +347,7 @@
 	unsigned long		flags;		/* ATA_DFLAG_xxx */
 	unsigned int		class;		/* ATA_DEV_xxx */
 	unsigned int		devno;		/* 0 or 1 */
-	u16			id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */
+	u16			*id;		/* IDENTIFY xxx DEVICE data */
 	u8			pio_mode;
 	u8			dma_mode;
 	u8			xfer_mode;
@@ -313,6 +355,8 @@
 
 	unsigned int		multi_count;	/* sectors count for
 						   READ/WRITE MULTIPLE */
+	unsigned int		max_sectors;	/* per-device max sectors */
+	unsigned int		cdb_len;
 
 	/* for CHS addressing */
 	u16			cylinders;	/* Number of cylinders */
@@ -342,7 +386,6 @@
 	unsigned int		mwdma_mask;
 	unsigned int		udma_mask;
 	unsigned int		cbl;	/* cable type; ATA_CBL_xxx */
-	unsigned int		cdb_len;
 
 	struct ata_device	device[ATA_MAX_DEVICES];
 
@@ -353,12 +396,14 @@
 	struct ata_host_stats	stats;
 	struct ata_host_set	*host_set;
 
-	struct work_struct	packet_task;
+	struct work_struct	port_task;
 
-	struct work_struct	pio_task;
 	unsigned int		hsm_task_state;
 	unsigned long		pio_task_timeout;
 
+	u32			msg_enable;
+	struct list_head	eh_done_q;
+
 	void			*private_data;
 };
 
@@ -378,7 +423,9 @@
 	u8   (*check_altstatus)(struct ata_port *ap);
 	void (*dev_select)(struct ata_port *ap, unsigned int device);
 
-	void (*phy_reset) (struct ata_port *ap);
+	void (*phy_reset) (struct ata_port *ap); /* obsolete */
+	int (*probe_reset) (struct ata_port *ap, unsigned int *classes);
+
 	void (*post_set_mode) (struct ata_port *ap);
 
 	int (*check_atapi_dma) (struct ata_queued_cmd *qc);
@@ -387,7 +434,7 @@
 	void (*bmdma_start) (struct ata_queued_cmd *qc);
 
 	void (*qc_prep) (struct ata_queued_cmd *qc);
-	int (*qc_issue) (struct ata_queued_cmd *qc);
+	unsigned int (*qc_issue) (struct ata_queued_cmd *qc);
 
 	void (*eng_timeout) (struct ata_port *ap);
 
@@ -435,6 +482,18 @@
 extern void __sata_phy_reset(struct ata_port *ap);
 extern void sata_phy_reset(struct ata_port *ap);
 extern void ata_bus_reset(struct ata_port *ap);
+extern int ata_drive_probe_reset(struct ata_port *ap,
+			ata_probeinit_fn_t probeinit,
+			ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+			ata_postreset_fn_t postreset, unsigned int *classes);
+extern void ata_std_probeinit(struct ata_port *ap);
+extern int ata_std_softreset(struct ata_port *ap, int verbose,
+			     unsigned int *classes);
+extern int sata_std_hardreset(struct ata_port *ap, int verbose,
+			      unsigned int *class);
+extern void ata_std_postreset(struct ata_port *ap, unsigned int *classes);
+extern int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev,
+			      int post_reset);
 extern void ata_port_disable(struct ata_port *);
 extern void ata_std_ports(struct ata_ioports *ioaddr);
 #ifdef CONFIG_PCI
@@ -449,7 +508,10 @@
 extern int ata_scsi_detect(struct scsi_host_template *sht);
 extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg);
 extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *));
+extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
 extern int ata_scsi_error(struct Scsi_Host *host);
+extern void ata_eh_qc_complete(struct ata_queued_cmd *qc);
+extern void ata_eh_qc_retry(struct ata_queued_cmd *qc);
 extern int ata_scsi_release(struct Scsi_Host *host);
 extern unsigned int ata_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc);
 extern int ata_scsi_device_resume(struct scsi_device *);
@@ -457,6 +519,11 @@
 extern int ata_device_resume(struct ata_port *, struct ata_device *);
 extern int ata_device_suspend(struct ata_port *, struct ata_device *);
 extern int ata_ratelimit(void);
+extern unsigned int ata_busy_sleep(struct ata_port *ap,
+				   unsigned long timeout_pat,
+				   unsigned long timeout);
+extern void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *),
+				void *data, unsigned long delay);
 
 /*
  * Default driver ops implementations
@@ -470,26 +537,28 @@
 extern u8 ata_check_status(struct ata_port *ap);
 extern u8 ata_altstatus(struct ata_port *ap);
 extern void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf);
+extern int ata_std_probe_reset(struct ata_port *ap, unsigned int *classes);
 extern int ata_port_start (struct ata_port *ap);
 extern void ata_port_stop (struct ata_port *ap);
 extern void ata_host_stop (struct ata_host_set *host_set);
 extern irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
 extern void ata_qc_prep(struct ata_queued_cmd *qc);
-extern int ata_qc_issue_prot(struct ata_queued_cmd *qc);
+extern unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc);
 extern void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf,
 		unsigned int buflen);
 extern void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
 		 unsigned int n_elem);
 extern unsigned int ata_dev_classify(const struct ata_taskfile *tf);
-extern void ata_dev_id_string(const u16 *id, unsigned char *s,
-			      unsigned int ofs, unsigned int len);
-extern void ata_dev_config(struct ata_port *ap, unsigned int i);
+extern void ata_id_string(const u16 *id, unsigned char *s,
+			  unsigned int ofs, unsigned int len);
+extern void ata_id_c_string(const u16 *id, unsigned char *s,
+			    unsigned int ofs, unsigned int len);
 extern void ata_bmdma_setup (struct ata_queued_cmd *qc);
 extern void ata_bmdma_start (struct ata_queued_cmd *qc);
 extern void ata_bmdma_stop(struct ata_queued_cmd *qc);
 extern u8   ata_bmdma_status(struct ata_port *ap);
 extern void ata_bmdma_irq_clear(struct ata_port *ap);
-extern void ata_qc_complete(struct ata_queued_cmd *qc);
+extern void __ata_qc_complete(struct ata_queued_cmd *qc);
 extern void ata_eng_timeout(struct ata_port *ap);
 extern void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev,
 			      struct scsi_cmnd *cmd,
@@ -586,10 +655,14 @@
 	return (tag < ATA_MAX_QUEUE) ? 1 : 0;
 }
 
+static inline unsigned int ata_class_present(unsigned int class)
+{
+	return class == ATA_DEV_ATA || class == ATA_DEV_ATAPI;
+}
+
 static inline unsigned int ata_dev_present(const struct ata_device *dev)
 {
-	return ((dev->class == ATA_DEV_ATA) ||
-		(dev->class == ATA_DEV_ATAPI));
+	return ata_class_present(dev->class);
 }
 
 static inline u8 ata_chk_status(struct ata_port *ap)
@@ -657,9 +730,9 @@
 
 	if (status & (ATA_BUSY | ATA_DRQ)) {
 		unsigned long l = ap->ioaddr.status_addr;
-		printk(KERN_WARNING
-		       "ATA: abnormal status 0x%X on port 0x%lX\n",
-		       status, l);
+		if (ata_msg_warn(ap))
+			printk(KERN_WARNING "ATA: abnormal status 0x%X on port 0x%lX\n",
+				status, l);
 	}
 
 	return status;
@@ -701,6 +774,24 @@
 	ata_tf_init(qc->ap, &qc->tf, qc->dev->devno);
 }
 
+/**
+ *	ata_qc_complete - Complete an active ATA command
+ *	@qc: Command to complete
+ *	@err_mask: ATA Status register contents
+ *
+ *	Indicate to the mid and upper layers that an ATA
+ *	command has completed, with either an ok or not-ok status.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+static inline void ata_qc_complete(struct ata_queued_cmd *qc)
+{
+	if (unlikely(qc->flags & ATA_QCFLAG_EH_SCHEDULED))
+		return;
+
+	__ata_qc_complete(qc);
+}
 
 /**
  *	ata_irq_on - Enable interrupts on a port.
@@ -751,7 +842,8 @@
 
 	status = ata_busy_wait(ap, bits, 1000);
 	if (status & bits)
-		DPRINTK("abnormal status 0x%X\n", status);
+		if (ata_msg_err(ap))
+			printk(KERN_ERR "abnormal status 0x%X\n", status);
 
 	/* get controller status; clear intr, err bits */
 	if (ap->flags & ATA_FLAG_MMIO) {
@@ -769,8 +861,10 @@
 		post_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
 	}
 
-	VPRINTK("irq ack: host_stat 0x%X, new host_stat 0x%X, drv_stat 0x%X\n",
-		host_stat, post_stat, status);
+	if (ata_msg_intr(ap))
+		printk(KERN_INFO "%s: irq ack: host_stat 0x%X, new host_stat 0x%X, drv_stat 0x%X\n",
+			__FUNCTION__,
+			host_stat, post_stat, status);
 
 	return status;
 }
@@ -807,7 +901,7 @@
 static inline unsigned int ac_err_mask(u8 status)
 {
 	if (status & ATA_BUSY)
-		return AC_ERR_ATA_BUS;
+		return AC_ERR_HSM;
 	if (status & (ATA_ERR | ATA_DF))
 		return AC_ERR_DEV;
 	return 0;
diff --git a/include/linux/module.h b/include/linux/module.h
index 84d75f3..70bd843 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -198,6 +198,9 @@
 #define EXPORT_SYMBOL_GPL(sym)					\
 	__EXPORT_SYMBOL(sym, "_gpl")
 
+#define EXPORT_SYMBOL_GPL_FUTURE(sym)				\
+	__EXPORT_SYMBOL(sym, "_gpl_future")
+
 #endif
 
 struct module_ref
@@ -242,6 +245,7 @@
 	/* Sysfs stuff. */
 	struct module_kobject mkobj;
 	struct module_param_attrs *param_attrs;
+	struct module_attribute *modinfo_attrs;
 	const char *version;
 	const char *srcversion;
 
@@ -255,6 +259,11 @@
 	unsigned int num_gpl_syms;
 	const unsigned long *gpl_crcs;
 
+	/* symbols that will be GPL-only in the near future. */
+	const struct kernel_symbol *gpl_future_syms;
+	unsigned int num_gpl_future_syms;
+	const unsigned long *gpl_future_crcs;
+
 	/* Exception table */
 	unsigned int num_exentries;
 	const struct exception_table_entry *extable;
@@ -441,6 +450,7 @@
 #else /* !CONFIG_MODULES... */
 #define EXPORT_SYMBOL(sym)
 #define EXPORT_SYMBOL_GPL(sym)
+#define EXPORT_SYMBOL_GPL_FUTURE(sym)
 
 /* Given an address, look for it in the exception tables. */
 static inline const struct exception_table_entry *
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 827cc6d..130d125 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -1018,8 +1018,6 @@
 	unsigned char descindex, void *buf, int size);
 extern int usb_get_status(struct usb_device *dev,
 	int type, int target, void *data);
-extern int usb_get_string(struct usb_device *dev,
-	unsigned short langid, unsigned char index, void *buf, int size);
 extern int usb_string(struct usb_device *dev, int index,
 	char *buf, size_t size);
 
diff --git a/include/linux/usb_gadget.h b/include/linux/usb_gadget.h
index ff81117..1d78870 100644
--- a/include/linux/usb_gadget.h
+++ b/include/linux/usb_gadget.h
@@ -801,7 +801,9 @@
  * Call this in your gadget driver's module initialization function,
  * to tell the underlying usb controller driver about your driver.
  * The driver's bind() function will be called to bind it to a
- * gadget.  This function must be called in a context that can sleep.
+ * gadget before this registration call returns.  It's expected that
+ * the bind() functions will be in init sections.
+ * This function must be called in a context that can sleep.
  */
 int usb_gadget_register_driver (struct usb_gadget_driver *driver);
 
@@ -814,7 +816,8 @@
  * going away.  If the controller is connected to a USB host,
  * it will first disconnect().  The driver is also requested
  * to unbind() and clean up any device state, before this procedure
- * finally returns.
+ * finally returns.  It's expected that the unbind() functions
+ * will in in exit sections, so may not be linked in some kernels.
  * This function must be called in a context that can sleep.
  */
 int usb_gadget_unregister_driver (struct usb_gadget_driver *driver);
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 5208b12d..724cfbf 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -17,11 +17,12 @@
 #include <linux/time.h> /* need struct timeval */
 #include <linux/poll.h>
 #include <linux/device.h>
+#include <linux/mutex.h>
 #endif
 #include <linux/compiler.h> /* need __user */
 
 
-#define OBSOLETE_OWNER 1 /* It will be removed for 2.6.15 */
+#define OBSOLETE_OWNER 1 /* It will be removed for 2.6.17 */
 #define HAVE_V4L2 1
 
 /*
@@ -48,6 +49,16 @@
 
 #ifdef __KERNEL__
 
+/* Minor device allocation */
+#define MINOR_VFL_TYPE_GRABBER_MIN   0
+#define MINOR_VFL_TYPE_GRABBER_MAX  63
+#define MINOR_VFL_TYPE_RADIO_MIN    64
+#define MINOR_VFL_TYPE_RADIO_MAX   127
+#define MINOR_VFL_TYPE_VTX_MIN     192
+#define MINOR_VFL_TYPE_VTX_MAX     223
+#define MINOR_VFL_TYPE_VBI_MIN     224
+#define MINOR_VFL_TYPE_VBI_MAX     255
+
 #define VFL_TYPE_GRABBER	0
 #define VFL_TYPE_VBI		1
 #define VFL_TYPE_RADIO		2
@@ -80,7 +91,7 @@
 
 	/* for videodev.c intenal usage -- please don't touch */
 	int users;                     /* video_exclusive_{open|close} ... */
-	struct semaphore lock;         /* ... helper function uses these   */
+	struct mutex lock;             /* ... helper function uses these   */
 	char devfs_name[64];           /* devfs */
 	struct class_device class_dev; /* sysfs */
 };
@@ -952,13 +963,68 @@
 	__u32   reserved[2];            /* must be zero */
 };
 
-#define V4L2_SLICED_TELETEXT_B          (0x0001)
-#define V4L2_SLICED_VPS                 (0x0400)
-#define V4L2_SLICED_CAPTION_525         (0x1000)
-#define V4L2_SLICED_WSS_625             (0x4000)
+/* Teletext World System Teletext
+   (WST), defined on ITU-R BT.653-2 */
+#define V4L2_SLICED_TELETEXT_PAL_B      (0x000001)
+#define V4L2_SLICED_TELETEXT_PAL_C      (0x000002)
+#define V4L2_SLICED_TELETEXT_NTSC_B     (0x000010)
+#define V4L2_SLICED_TELETEXT_SECAM      (0x000020)
 
-#define V4L2_SLICED_VBI_525             (V4L2_SLICED_CAPTION_525)
-#define V4L2_SLICED_VBI_625             (V4L2_SLICED_TELETEXT_B | V4L2_SLICED_VPS | V4L2_SLICED_WSS_625)
+/* Teletext North American Broadcast Teletext Specification
+   (NABTS), defined on ITU-R BT.653-2 */
+#define V4L2_SLICED_TELETEXT_NTSC_C     (0x000040)
+#define V4L2_SLICED_TELETEXT_NTSC_D     (0x000080)
+
+/* Video Program System, defined on ETS 300 231*/
+#define V4L2_SLICED_VPS                 (0x000400)
+
+/* Closed Caption, defined on EIA-608 */
+#define V4L2_SLICED_CAPTION_525         (0x001000)
+#define V4L2_SLICED_CAPTION_625         (0x002000)
+
+/* Wide Screen System, defined on ITU-R BT1119.1 */
+#define V4L2_SLICED_WSS_625             (0x004000)
+
+/* Wide Screen System, defined on IEC 61880 */
+#define V4L2_SLICED_WSS_525             (0x008000)
+
+/* Vertical Interval Timecode (VITC), defined on SMPTE 12M */
+#define V4l2_SLICED_VITC_625		(0x010000)
+#define V4l2_SLICED_VITC_525		(0x020000)
+
+#define V4L2_SLICED_TELETEXT_B		(V4L2_SLICED_TELETEXT_PAL_B  |\
+					 V4L2_SLICED_TELETEXT_NTSC_B)
+
+#define V4L2_SLICED_TELETEXT		(V4L2_SLICED_TELETEXT_PAL_B  |\
+					 V4L2_SLICED_TELETEXT_PAL_C  |\
+					 V4L2_SLICED_TELETEXT_SECAM  |\
+					 V4L2_SLICED_TELETEXT_NTSC_B |\
+					 V4L2_SLICED_TELETEXT_NTSC_C |\
+					 V4L2_SLICED_TELETEXT_NTSC_D)
+
+#define V4L2_SLICED_CAPTION		(V4L2_SLICED_CAPTION_525     |\
+					 V4L2_SLICED_CAPTION_625)
+
+#define V4L2_SLICED_WSS			(V4L2_SLICED_WSS_525         |\
+					 V4L2_SLICED_WSS_625)
+
+#define V4L2_SLICED_VITC		(V4L2_SLICED_VITC_525        |\
+					 V4L2_SLICED_VITC_625)
+
+#define V4L2_SLICED_VBI_525             (V4L2_SLICED_TELETEXT_NTSC_B |\
+					 V4L2_SLICED_TELETEXT_NTSC_C |\
+					 V4L2_SLICED_TELETEXT_NTSC_D |\
+					 V4L2_SLICED_CAPTION_525     |\
+					 V4L2_SLICED_WSS_525         |\
+					 V4l2_SLICED_VITC_525)
+
+#define V4L2_SLICED_VBI_625             (V4L2_SLICED_TELETEXT_PAL_B  |\
+					 V4L2_SLICED_TELETEXT_PAL_C  |\
+					 V4L2_SLICED_TELETEXT_SECAM  |\
+					 V4L2_SLICED_VPS             |\
+					 V4L2_SLICED_CAPTION_625     |\
+					 V4L2_SLICED_WSS_625         |\
+					 V4l2_SLICED_VITC_625)
 
 struct v4l2_sliced_vbi_cap
 {
diff --git a/include/media/ir-common.h b/include/media/ir-common.h
index ad3e9bb..302d5b3 100644
--- a/include/media/ir-common.h
+++ b/include/media/ir-common.h
@@ -47,13 +47,6 @@
 	int                keypressed;  /* current state */
 };
 
-extern IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE];
-
 void ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
 		   int ir_type, IR_KEYTAB_TYPE *ir_codes);
 void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir);
@@ -64,6 +57,39 @@
 int  ir_decode_biphase(u32 *samples, int count, int low, int high);
 int  ir_decode_pulsedistance(u32 *samples, int count, int low, int high);
 
+/* Keymaps to be used by other modules */
+
+extern IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_avermedia[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_avermedia_dvbt[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_nebula[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_dntv_live_dvb_t[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_iodata_bctv7e[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_adstech_dvb_t_pci[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_msi_tvanywhere[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_cinergy_1400[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_avertv_303[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_dntv_live_dvbt_pro[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_em_terratec[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_em_pinnacle_usb[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_flyvideo[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_flydvb[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_cinergy[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_eztv[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_avermedia[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_videomate_tv_pvr[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_manli[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_gotview7135[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_pctv_sedna[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE];
+
 #endif
 
 /*
diff --git a/include/media/saa7146.h b/include/media/saa7146.h
index 2bc634f..fee579f 100644
--- a/include/media/saa7146.h
+++ b/include/media/saa7146.h
@@ -11,6 +11,8 @@
 #include <linux/i2c.h>		/* for i2c subsystem */
 #include <asm/io.h>		/* for accessing devices */
 #include <linux/stringify.h>
+#include <linux/mutex.h>
+
 #include <linux/vmalloc.h>	/* for vmalloc() */
 #include <linux/mm.h>		/* for vmalloc_to_page() */
 
@@ -112,7 +114,7 @@
 
 	/* different device locks */
 	spinlock_t			slock;
-	struct semaphore		lock;
+	struct mutex			lock;
 
 	unsigned char			__iomem *mem;		/* pointer to mapped IO memory */
 	int				revision;	/* chip revision; needed for bug-workarounds*/
@@ -133,15 +135,16 @@
 	void (*vv_callback)(struct saa7146_dev *dev, unsigned long status);
 
 	/* i2c-stuff */
-	struct semaphore	i2c_lock;
-	u32			i2c_bitrate;
-	struct saa7146_dma	d_i2c;	/* pointer to i2c memory */
-	wait_queue_head_t	i2c_wq;
-	int			i2c_op;
+	struct mutex			i2c_lock;
+
+	u32				i2c_bitrate;
+	struct saa7146_dma		d_i2c;	/* pointer to i2c memory */
+	wait_queue_head_t		i2c_wq;
+	int				i2c_op;
 
 	/* memories */
-	struct saa7146_dma	d_rps0;
-	struct saa7146_dma	d_rps1;
+	struct saa7146_dma		d_rps0;
+	struct saa7146_dma		d_rps1;
 };
 
 /* from saa7146_i2c.c */
@@ -150,7 +153,7 @@
 
 /* from saa7146_core.c */
 extern struct list_head saa7146_devices;
-extern struct semaphore saa7146_devices_lock;
+extern struct mutex saa7146_devices_lock;
 int saa7146_register_extension(struct saa7146_extension*);
 int saa7146_unregister_extension(struct saa7146_extension*);
 struct saa7146_format* format_by_fourcc(struct saa7146_dev *dev, int fourcc);
diff --git a/include/media/tuner-types.h b/include/media/tuner-types.h
index 15821ab..ad9c171 100644
--- a/include/media/tuner-types.h
+++ b/include/media/tuner-types.h
@@ -14,6 +14,7 @@
 
 struct tuner_range {
 	unsigned short limit;
+	unsigned char config;
 	unsigned char cb;
 };
 
@@ -38,7 +39,6 @@
 	 * static unless the control byte was sent first.
 	 */
 	unsigned int cb_first_if_lower_freq:1;
-	unsigned char config; /* to be moved into struct tuner_range for dvb-pll merge */
 
 	unsigned int count;
 	struct tuner_range *ranges;
@@ -46,6 +46,7 @@
 
 struct tunertype {
 	char *name;
+	unsigned int count;
 	struct tuner_params *params;
 };
 
diff --git a/include/media/tuner.h b/include/media/tuner.h
index a5beeac..017fed7 100644
--- a/include/media/tuner.h
+++ b/include/media/tuner.h
@@ -110,12 +110,15 @@
 
 #define TUNER_LG_TDVS_H062F		64	/* DViCO FusionHDTV 5 */
 #define TUNER_YMEC_TVF66T5_B_DFF	65	/* Acorp Y878F */
-#define TUNER_LG_NTSC_TALN_MINI		66
+#define TUNER_LG_TALN			66
 #define TUNER_PHILIPS_TD1316		67
 
 #define TUNER_PHILIPS_TUV1236D		68	/* ATI HDTV Wonder */
 #define TUNER_TNF_5335MF                69	/* Sabrent Bt848   */
 #define TUNER_SAMSUNG_TCPN_2121P30A     70 	/* Hauppauge PVR-500MCE NTSC */
+#define TUNER_XCEIVE_XC3028		71
+
+#define TUNER_THOMSON_FE6600		72	/* DViCO FusionHDTV DVB-T Hybrid */
 
 /* tv card specific */
 #define TDA9887_PRESENT 		(1<<0)
@@ -209,6 +212,7 @@
 extern unsigned const int tuner_count;
 
 extern int microtune_init(struct i2c_client *c);
+extern int xc3028_init(struct i2c_client *c);
 extern int tda8290_init(struct i2c_client *c);
 extern int tda8290_probe(struct i2c_client *c);
 extern int tea5767_tuner_init(struct i2c_client *c);
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index d4030a7..2360453 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -58,6 +58,9 @@
 /* Prints the ioctl in a human-readable format */
 extern void v4l_printk_ioctl(unsigned int cmd);
 
+/* Prints the ioctl and arg in a human-readable format */
+extern void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg);
+
 /* Use this macro for non-I2C drivers. Pass the driver name as the first arg. */
 #define v4l_print_ioctl(name, cmd)  		 \
 	do {  					 \
@@ -100,6 +103,7 @@
 	V4L2_IDENT_UNKNOWN = 0,
 
 	/* module saa7115: reserved range 100-149 */
+	V4L2_IDENT_SAA7113 = 103,
 	V4L2_IDENT_SAA7114 = 104,
 	V4L2_IDENT_SAA7115 = 105,
 
@@ -115,12 +119,15 @@
 };
 
 /* audio ioctls */
-/* v4l device was opened in Radio mode */
+
+/* v4l device was opened in Radio mode, to be replaced by VIDIOC_INT_S_TUNER_MODE */
 #define AUDC_SET_RADIO        _IO('d',88)
-/* select from TV,radio,extern,MUTE */
+
+/* select from TV,radio,extern,MUTE, to be replaced with VIDIOC_INT_S_AUDIO_ROUTING */
 #define AUDC_SET_INPUT        _IOW('d',89,int)
 
-/* msp3400 ioctl: will be removed in the near future */
+/* msp3400 ioctl: will be removed in the near future, to be replaced by
+   VIDIOC_INT_S_AUDIO_ROUTING. */
 struct msp_matrix {
   int input;
   int output;
@@ -128,12 +135,25 @@
 #define MSP_SET_MATRIX     _IOW('m',17,struct msp_matrix)
 
 /* tuner ioctls */
+
 /* Sets tuner type and its I2C addr */
-#define TUNER_SET_TYPE_ADDR          _IOW('d',90,int)
-/* Puts tuner on powersaving state, disabling it, except for i2c */
-#define TUNER_SET_STANDBY            _IOW('d',91,int)
+#define TUNER_SET_TYPE_ADDR          _IOW('d', 90, int)
+
+/* Puts tuner on powersaving state, disabling it, except for i2c. To be replaced
+   by VIDIOC_INT_S_STANDBY. */
+#define TUNER_SET_STANDBY            _IOW('d', 91, int)
+
 /* Sets tda9887 specific stuff, like port1, port2 and qss */
-#define TDA9887_SET_CONFIG           _IOW('d',92,int)
+#define TDA9887_SET_CONFIG           _IOW('d', 92, int)
+
+/* Switch the tuner to a specific tuner mode. Replacement of AUDC_SET_RADIO */
+#define VIDIOC_INT_S_TUNER_MODE	     _IOW('d', 93, enum v4l2_tuner_type)
+
+/* Generic standby command. Passing -1 (all bits set to 1) will put the whole
+   chip into standby mode, value 0 will make the chip fully active. Specific
+   bits can be used by certain chips to enable/disable specific subsystems.
+   Replacement of TUNER_SET_STANDBY. */
+#define VIDIOC_INT_S_STANDBY 	     _IOW('d', 94, u32)
 
 /* only implemented if CONFIG_VIDEO_ADV_DEBUG is defined */
 #define	VIDIOC_INT_S_REGISTER 		_IOR ('d', 100, struct v4l2_register)
@@ -160,7 +180,8 @@
 
 /* Used to generate VBI signals on a video signal. v4l2_sliced_vbi_data is
    filled with the data packets that should be output. Note that if you set
-   the line field to 0, then that VBI signal is disabled. */
+   the line field to 0, then that VBI signal is disabled. If no
+   valid VBI data was found, then the type field is set to 0 on return. */
 #define VIDIOC_INT_S_VBI_DATA 		_IOW ('d', 105, struct v4l2_sliced_vbi_data)
 
 /* Used to obtain the sliced VBI packet from a readback register. Not all
@@ -168,11 +189,11 @@
    register contains invalid or erroneous data -EIO is returned. Note that
    you must fill in the 'id' member and the 'field' member (to determine
    whether CC data from the first or second field should be obtained). */
-#define VIDIOC_INT_G_VBI_DATA 		_IOWR('d', 106, struct v4l2_sliced_vbi_data *)
+#define VIDIOC_INT_G_VBI_DATA 		_IOWR('d', 106, struct v4l2_sliced_vbi_data)
 
 /* Returns the chip identifier or V4L2_IDENT_UNKNOWN if no identification can
    be made. */
-#define VIDIOC_INT_G_CHIP_IDENT		_IOR ('d', 107, enum v4l2_chip_ident *)
+#define VIDIOC_INT_G_CHIP_IDENT		_IOR ('d', 107, enum v4l2_chip_ident)
 
 /* Sets I2S speed in bps. This is used to provide a standard way to select I2S
    clock used by driving digital audio streams at some board designs.
@@ -180,4 +201,25 @@
    If the frequency is not supported, then -EINVAL is returned. */
 #define VIDIOC_INT_I2S_CLOCK_FREQ 	_IOW ('d', 108, u32)
 
+/* Routing definition, device dependent. It specifies which inputs (if any)
+   should be routed to which outputs (if any). */
+struct v4l2_routing {
+	u32 input;
+	u32 output;
+};
+
+/* These internal commands should be used to define the inputs and outputs
+   of an audio/video chip. They will replace AUDC_SET_INPUT.
+   The v4l2 API commands VIDIOC_S/G_INPUT, VIDIOC_S/G_OUTPUT,
+   VIDIOC_S/G_AUDIO and VIDIOC_S/G_AUDOUT are meant to be used by the
+   user. Internally these commands should be used to switch inputs/outputs
+   because only the driver knows how to map a 'Television' input to the precise
+   input/output routing of an A/D converter, or a DSP, or a video digitizer.
+   These four commands should only be sent directly to an i2c device, they
+   should not be broadcast as the routing is very device specific. */
+#define	VIDIOC_INT_S_AUDIO_ROUTING	_IOW ('d', 109, struct v4l2_routing)
+#define	VIDIOC_INT_G_AUDIO_ROUTING	_IOR ('d', 110, struct v4l2_routing)
+#define	VIDIOC_INT_S_VIDEO_ROUTING	_IOW ('d', 111, struct v4l2_routing)
+#define	VIDIOC_INT_G_VIDEO_ROUTING	_IOR ('d', 112, struct v4l2_routing)
+
 #endif /* V4L2_COMMON_H_ */
diff --git a/include/media/video-buf-dvb.h b/include/media/video-buf-dvb.h
index ad0a07a..b78d90f 100644
--- a/include/media/video-buf-dvb.h
+++ b/include/media/video-buf-dvb.h
@@ -11,7 +11,7 @@
 	struct videobuf_queue      dvbq;
 
 	/* video-buf-dvb state info */
-	struct semaphore           lock;
+	struct mutex               lock;
 	struct task_struct         *thread;
 	int                        nfeeds;
 
diff --git a/include/media/video-buf.h b/include/media/video-buf.h
index 8ecfd78..d90dec5 100644
--- a/include/media/video-buf.h
+++ b/include/media/video-buf.h
@@ -177,7 +177,7 @@
 };
 
 struct videobuf_queue {
-	struct semaphore           lock;
+	struct mutex               lock;
 	spinlock_t                 *irqlock;
 	struct pci_dev             *pci;
 
diff --git a/include/rdma/ib_fmr_pool.h b/include/rdma/ib_fmr_pool.h
index 86b7e93..4ace54c 100644
--- a/include/rdma/ib_fmr_pool.h
+++ b/include/rdma/ib_fmr_pool.h
@@ -43,6 +43,7 @@
 /**
  * struct ib_fmr_pool_param - Parameters for creating FMR pool
  * @max_pages_per_fmr:Maximum number of pages per map request.
+ * @page_shift: Log2 of sizeof "pages" mapped by this fmr
  * @access:Access flags for FMRs in pool.
  * @pool_size:Number of FMRs to allocate for pool.
  * @dirty_watermark:Flush is triggered when @dirty_watermark dirty
@@ -55,6 +56,7 @@
  */
 struct ib_fmr_pool_param {
 	int                     max_pages_per_fmr;
+	int                     page_shift;
 	enum ib_access_flags    access;
 	int                     pool_size;
 	int                     dirty_watermark;
diff --git a/include/rdma/ib_mad.h b/include/rdma/ib_mad.h
index 2c13350..51ab8ed 100644
--- a/include/rdma/ib_mad.h
+++ b/include/rdma/ib_mad.h
@@ -33,7 +33,7 @@
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  *
- * $Id: ib_mad.h 2775 2005-07-02 13:42:12Z halr $
+ * $Id: ib_mad.h 5596 2006-03-03 01:00:07Z sean.hefty $
  */
 
 #if !defined( IB_MAD_H )
@@ -208,15 +208,23 @@
 /**
  * ib_mad_send_buf - MAD data buffer and work request for sends.
  * @next: A pointer used to chain together MADs for posting.
- * @mad: References an allocated MAD data buffer.
+ * @mad: References an allocated MAD data buffer for MADs that do not have
+ *   RMPP active.  For MADs using RMPP, references the common and management
+ *   class specific headers.
  * @mad_agent: MAD agent that allocated the buffer.
  * @ah: The address handle to use when sending the MAD.
  * @context: User-controlled context fields.
+ * @hdr_len: Indicates the size of the data header of the MAD.  This length
+ *   includes the common MAD, RMPP, and class specific headers.
+ * @data_len: Indicates the total size of user-transferred data.
+ * @seg_count: The number of RMPP segments allocated for this send.
+ * @seg_size: Size of each RMPP segment.
  * @timeout_ms: Time to wait for a response.
  * @retries: Number of times to retry a request for a response.
  *
  * Users are responsible for initializing the MAD buffer itself, with the
- * exception of specifying the payload length field in any RMPP MAD.
+ * exception of any RMPP header.  Additional segment buffer space allocated
+ * beyond data_len is padding.
  */
 struct ib_mad_send_buf {
 	struct ib_mad_send_buf	*next;
@@ -224,6 +232,10 @@
 	struct ib_mad_agent	*mad_agent;
 	struct ib_ah		*ah;
 	void			*context[2];
+	int			hdr_len;
+	int			data_len;
+	int			seg_count;
+	int			seg_size;
 	int			timeout_ms;
 	int			retries;
 };
@@ -299,7 +311,7 @@
  * @mad_recv_wc: Received work completion information on the received MAD.
  *
  * MADs received in response to a send request operation will be handed to
- * the user after the send operation completes.  All data buffers given
+ * the user before the send operation completes.  All data buffers given
  * to registered agents through this routine are owned by the receiving
  * client, except for snooping agents.  Clients snooping MADs should not
  * modify the data referenced by @mad_recv_wc.
@@ -485,17 +497,6 @@
 int ib_post_send_mad(struct ib_mad_send_buf *send_buf,
 		     struct ib_mad_send_buf **bad_send_buf);
 
-/**
- * ib_coalesce_recv_mad - Coalesces received MAD data into a single buffer.
- * @mad_recv_wc: Work completion information for a received MAD.
- * @buf: User-provided data buffer to receive the coalesced buffers.  The
- *   referenced buffer should be at least the size of the mad_len specified
- *   by @mad_recv_wc.
- *
- * This call copies a chain of received MAD segments into a single data buffer,
- * removing duplicated headers.
- */
-void ib_coalesce_recv_mad(struct ib_mad_recv_wc *mad_recv_wc, void *buf);
 
 /**
  * ib_free_recv_mad - Returns data buffers used to receive a MAD.
@@ -590,9 +591,10 @@
  * with an initialized work request structure.  Users may modify the returned
  * MAD data buffer before posting the send.
  *
- * The returned data buffer will be cleared.  Users are responsible for
- * initializing the common MAD and any class specific headers.  If @rmpp_active
- * is set, the RMPP header will be initialized for sending.
+ * The returned MAD header, class specific headers, and any padding will be
+ * cleared.  Users are responsible for initializing the common MAD header,
+ * any class specific header, and MAD data area.
+ * If @rmpp_active is set, the RMPP header will be initialized for sending.
  */
 struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent,
 					    u32 remote_qpn, u16 pkey_index,
@@ -601,6 +603,16 @@
 					    gfp_t gfp_mask);
 
 /**
+ * ib_get_rmpp_segment - returns the data buffer for a given RMPP segment.
+ * @send_buf: Previously allocated send data buffer.
+ * @seg_num: number of segment to return
+ *
+ * This routine returns a pointer to the data buffer of an RMPP MAD.
+ * Users must provide synchronization to @send_buf around this call.
+ */
+void *ib_get_rmpp_segment(struct ib_mad_send_buf *send_buf, int seg_num);
+
+/**
  * ib_free_send_mad - Returns data buffers used to send a MAD.
  * @send_buf: Previously allocated send data buffer.
  */
diff --git a/include/rdma/ib_user_verbs.h b/include/rdma/ib_user_verbs.h
index 5ff1490..338ed43 100644
--- a/include/rdma/ib_user_verbs.h
+++ b/include/rdma/ib_user_verbs.h
@@ -1,7 +1,8 @@
 /*
  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  * Copyright (c) 2005 PathScale, Inc.  All rights reserved.
+ * Copyright (c) 2006 Mellanox Technologies.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -43,7 +44,7 @@
  * Increment this value if any changes that break userspace ABI
  * compatibility are made.
  */
-#define IB_USER_VERBS_ABI_VERSION	4
+#define IB_USER_VERBS_ABI_VERSION	6
 
 enum {
 	IB_USER_VERBS_CMD_GET_CONTEXT,
@@ -265,6 +266,17 @@
 	__u32 cqe;
 };
 
+struct ib_uverbs_resize_cq {
+	__u64 response;
+	__u32 cq_handle;
+	__u32 cqe;
+	__u64 driver_data[0];
+};
+
+struct ib_uverbs_resize_cq_resp {
+	__u32 cqe;
+};
+
 struct ib_uverbs_poll_cq {
 	__u64 response;
 	__u32 cq_handle;
@@ -338,6 +350,7 @@
 	__u32 max_send_sge;
 	__u32 max_recv_sge;
 	__u32 max_inline_data;
+	__u32 reserved;
 };
 
 /*
@@ -359,6 +372,47 @@
 	__u8  port_num;
 };
 
+struct ib_uverbs_query_qp {
+	__u64 response;
+	__u32 qp_handle;
+	__u32 attr_mask;
+	__u64 driver_data[0];
+};
+
+struct ib_uverbs_query_qp_resp {
+	struct ib_uverbs_qp_dest dest;
+	struct ib_uverbs_qp_dest alt_dest;
+	__u32 max_send_wr;
+	__u32 max_recv_wr;
+	__u32 max_send_sge;
+	__u32 max_recv_sge;
+	__u32 max_inline_data;
+	__u32 qkey;
+	__u32 rq_psn;
+	__u32 sq_psn;
+	__u32 dest_qp_num;
+	__u32 qp_access_flags;
+	__u16 pkey_index;
+	__u16 alt_pkey_index;
+	__u8  qp_state;
+	__u8  cur_qp_state;
+	__u8  path_mtu;
+	__u8  path_mig_state;
+	__u8  en_sqd_async_notify;
+	__u8  max_rd_atomic;
+	__u8  max_dest_rd_atomic;
+	__u8  min_rnr_timer;
+	__u8  port_num;
+	__u8  timeout;
+	__u8  retry_cnt;
+	__u8  rnr_retry;
+	__u8  alt_port_num;
+	__u8  alt_timeout;
+	__u8  sq_sig_all;
+	__u8  reserved[5];
+	__u64 driver_data[0];
+};
+
 struct ib_uverbs_modify_qp {
 	struct ib_uverbs_qp_dest dest;
 	struct ib_uverbs_qp_dest alt_dest;
@@ -415,7 +469,7 @@
 };
 
 struct ib_uverbs_send_wr {
-	__u64 wr_id; 
+	__u64 wr_id;
 	__u32 num_sge;
 	__u32 opcode;
 	__u32 send_flags;
@@ -489,7 +543,7 @@
 
 struct ib_uverbs_global_route {
 	__u8  dgid[16];
-	__u32 flow_label;    
+	__u32 flow_label;
 	__u8  sgid_index;
 	__u8  hop_limit;
 	__u8  traffic_class;
@@ -551,6 +605,9 @@
 
 struct ib_uverbs_create_srq_resp {
 	__u32 srq_handle;
+	__u32 max_wr;
+	__u32 max_sge;
+	__u32 reserved;
 };
 
 struct ib_uverbs_modify_srq {
@@ -561,6 +618,20 @@
 	__u64 driver_data[0];
 };
 
+struct ib_uverbs_query_srq {
+	__u64 response;
+	__u32 srq_handle;
+	__u32 reserved;
+	__u64 driver_data[0];
+};
+
+struct ib_uverbs_query_srq_resp {
+	__u32 max_wr;
+	__u32 max_sge;
+	__u32 srq_limit;
+	__u32 reserved;
+};
+
 struct ib_uverbs_destroy_srq {
 	__u64 response;
 	__u32 srq_handle;
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index 22fc886..c1ad627 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -5,7 +5,7 @@
  * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
  * Copyright (c) 2004 Voltaire Corporation.  All rights reserved.
  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -222,11 +222,13 @@
 };
 
 enum ib_device_modify_flags {
-	IB_DEVICE_MODIFY_SYS_IMAGE_GUID	= 1
+	IB_DEVICE_MODIFY_SYS_IMAGE_GUID	= 1 << 0,
+	IB_DEVICE_MODIFY_NODE_DESC	= 1 << 1
 };
 
 struct ib_device_modify {
 	u64	sys_image_guid;
+	char	node_desc[64];
 };
 
 enum ib_port_modify_flags {
@@ -649,7 +651,7 @@
 struct ib_fmr_attr {
 	int	max_pages;
 	int	max_maps;
-	u8	page_size;
+	u8	page_shift;
 };
 
 struct ib_ucontext {
@@ -880,7 +882,8 @@
 						struct ib_ucontext *context,
 						struct ib_udata *udata);
 	int                        (*destroy_cq)(struct ib_cq *cq);
-	int                        (*resize_cq)(struct ib_cq *cq, int cqe);
+	int                        (*resize_cq)(struct ib_cq *cq, int cqe,
+						struct ib_udata *udata);
 	int                        (*poll_cq)(struct ib_cq *cq, int num_entries,
 					      struct ib_wc *wc);
 	int                        (*peek_cq)(struct ib_cq *cq, int wc_cnt);
@@ -950,6 +953,7 @@
 	u64			     uverbs_cmd_mask;
 	int			     uverbs_abi_ver;
 
+	char			     node_desc[64];
 	__be64			     node_guid;
 	u8                           node_type;
 	u8                           phys_port_cnt;
@@ -986,6 +990,24 @@
 	return copy_to_user(udata->outbuf, src, len) ? -EFAULT : 0;
 }
 
+/**
+ * ib_modify_qp_is_ok - Check that the supplied attribute mask
+ * contains all required attributes and no attributes not allowed for
+ * the given QP state transition.
+ * @cur_state: Current QP state
+ * @next_state: Next QP state
+ * @type: QP type
+ * @mask: Mask of supplied QP attributes
+ *
+ * This function is a helper function that a low-level driver's
+ * modify_qp method can use to validate the consumer's input.  It
+ * checks that cur_state and next_state are valid QP states, that a
+ * transition from cur_state to next_state is allowed by the IB spec,
+ * and that the attribute mask supplied is allowed for the transition.
+ */
+int ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state,
+		       enum ib_qp_type type, enum ib_qp_attr_mask mask);
+
 int ib_register_event_handler  (struct ib_event_handler *event_handler);
 int ib_unregister_event_handler(struct ib_event_handler *event_handler);
 void ib_dispatch_event(struct ib_event *event);
@@ -1078,7 +1100,9 @@
  * ib_create_srq - Creates a SRQ associated with the specified protection
  *   domain.
  * @pd: The protection domain associated with the SRQ.
- * @srq_init_attr: A list of initial attributes required to create the SRQ.
+ * @srq_init_attr: A list of initial attributes required to create the
+ *   SRQ.  If SRQ creation succeeds, then the attributes are updated to
+ *   the actual capabilities of the created SRQ.
  *
  * srq_attr->max_wr and srq_attr->max_sge are read the determine the
  * requested size of the SRQ, and set to the actual values allocated
@@ -1137,7 +1161,9 @@
  * ib_create_qp - Creates a QP associated with the specified protection
  *   domain.
  * @pd: The protection domain associated with the QP.
- * @qp_init_attr: A list of initial attributes required to create the QP.
+ * @qp_init_attr: A list of initial attributes required to create the
+ *   QP.  If QP creation succeeds, then the attributes are updated to
+ *   the actual capabilities of the created QP.
  */
 struct ib_qp *ib_create_qp(struct ib_pd *pd,
 			   struct ib_qp_init_attr *qp_init_attr);
diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h
index fabd879..d160880 100644
--- a/include/scsi/scsi_eh.h
+++ b/include/scsi/scsi_eh.h
@@ -35,6 +35,9 @@
 }
 
 
+extern void scsi_eh_finish_cmd(struct scsi_cmnd *scmd,
+			       struct list_head *done_q);
+extern void scsi_eh_flush_done_q(struct list_head *done_q);
 extern void scsi_report_bus_reset(struct Scsi_Host *, int);
 extern void scsi_report_device_reset(struct Scsi_Host *, int, int);
 extern int scsi_block_when_processing_errors(struct scsi_device *);
diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c
index d5eeae0..f2690ed 100644
--- a/kernel/ksysfs.c
+++ b/kernel/ksysfs.c
@@ -15,9 +15,6 @@
 #include <linux/module.h>
 #include <linux/init.h>
 
-u64 uevent_seqnum;
-char uevent_helper[UEVENT_HELPER_PATH_LEN] = "/sbin/hotplug";
-
 #define KERNEL_ATTR_RO(_name) \
 static struct subsys_attribute _name##_attr = __ATTR_RO(_name)
 
diff --git a/kernel/module.c b/kernel/module.c
index 5aad477..77764f2 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -126,8 +126,11 @@
 extern const struct kernel_symbol __stop___ksymtab[];
 extern const struct kernel_symbol __start___ksymtab_gpl[];
 extern const struct kernel_symbol __stop___ksymtab_gpl[];
+extern const struct kernel_symbol __start___ksymtab_gpl_future[];
+extern const struct kernel_symbol __stop___ksymtab_gpl_future[];
 extern const unsigned long __start___kcrctab[];
 extern const unsigned long __start___kcrctab_gpl[];
+extern const unsigned long __start___kcrctab_gpl_future[];
 
 #ifndef CONFIG_MODVERSIONS
 #define symversion(base, idx) NULL
@@ -135,6 +138,18 @@
 #define symversion(base, idx) ((base) ? ((base) + (idx)) : NULL)
 #endif
 
+/* lookup symbol in given range of kernel_symbols */
+static const struct kernel_symbol *lookup_symbol(const char *name,
+	const struct kernel_symbol *start,
+	const struct kernel_symbol *stop)
+{
+	const struct kernel_symbol *ks = start;
+	for (; ks < stop; ks++)
+		if (strcmp(ks->name, name) == 0)
+			return ks;
+	return NULL;
+}
+
 /* Find a symbol, return value, crc and module which owns it */
 static unsigned long __find_symbol(const char *name,
 				   struct module **owner,
@@ -142,41 +157,76 @@
 				   int gplok)
 {
 	struct module *mod;
-	unsigned int i;
+	const struct kernel_symbol *ks;
 
 	/* Core kernel first. */ 
 	*owner = NULL;
-	for (i = 0; __start___ksymtab+i < __stop___ksymtab; i++) {
-		if (strcmp(__start___ksymtab[i].name, name) == 0) {
-			*crc = symversion(__start___kcrctab, i);
-			return __start___ksymtab[i].value;
-		}
+	ks = lookup_symbol(name, __start___ksymtab, __stop___ksymtab);
+	if (ks) {
+		*crc = symversion(__start___kcrctab, (ks - __start___ksymtab));
+		return ks->value;
 	}
 	if (gplok) {
-		for (i = 0; __start___ksymtab_gpl+i<__stop___ksymtab_gpl; i++)
-			if (strcmp(__start___ksymtab_gpl[i].name, name) == 0) {
-				*crc = symversion(__start___kcrctab_gpl, i);
-				return __start___ksymtab_gpl[i].value;
-			}
+		ks = lookup_symbol(name, __start___ksymtab_gpl,
+					 __stop___ksymtab_gpl);
+		if (ks) {
+			*crc = symversion(__start___kcrctab_gpl,
+					  (ks - __start___ksymtab_gpl));
+			return ks->value;
+		}
+	}
+	ks = lookup_symbol(name, __start___ksymtab_gpl_future,
+				 __stop___ksymtab_gpl_future);
+	if (ks) {
+		if (!gplok) {
+			printk(KERN_WARNING "Symbol %s is being used "
+			       "by a non-GPL module, which will not "
+			       "be allowed in the future\n", name);
+			printk(KERN_WARNING "Please see the file "
+			       "Documentation/feature-removal-schedule.txt "
+			       "in the kernel source tree for more "
+			       "details.\n");
+		}
+		*crc = symversion(__start___kcrctab_gpl_future,
+				  (ks - __start___ksymtab_gpl_future));
+		return ks->value;
 	}
 
 	/* Now try modules. */ 
 	list_for_each_entry(mod, &modules, list) {
 		*owner = mod;
-		for (i = 0; i < mod->num_syms; i++)
-			if (strcmp(mod->syms[i].name, name) == 0) {
-				*crc = symversion(mod->crcs, i);
-				return mod->syms[i].value;
-			}
+		ks = lookup_symbol(name, mod->syms, mod->syms + mod->num_syms);
+		if (ks) {
+			*crc = symversion(mod->crcs, (ks - mod->syms));
+			return ks->value;
+		}
 
 		if (gplok) {
-			for (i = 0; i < mod->num_gpl_syms; i++) {
-				if (strcmp(mod->gpl_syms[i].name, name) == 0) {
-					*crc = symversion(mod->gpl_crcs, i);
-					return mod->gpl_syms[i].value;
-				}
+			ks = lookup_symbol(name, mod->gpl_syms,
+					   mod->gpl_syms + mod->num_gpl_syms);
+			if (ks) {
+				*crc = symversion(mod->gpl_crcs,
+						  (ks - mod->gpl_syms));
+				return ks->value;
 			}
 		}
+		ks = lookup_symbol(name, mod->gpl_future_syms,
+				   (mod->gpl_future_syms +
+				    mod->num_gpl_future_syms));
+		if (ks) {
+			if (!gplok) {
+				printk(KERN_WARNING "Symbol %s is being used "
+				       "by a non-GPL module, which will not "
+				       "be allowed in the future\n", name);
+				printk(KERN_WARNING "Please see the file "
+				       "Documentation/feature-removal-schedule.txt "
+				       "in the kernel source tree for more "
+				       "details.\n");
+			}
+			*crc = symversion(mod->gpl_future_crcs,
+					  (ks - mod->gpl_future_syms));
+			return ks->value;
+		}
 	}
 	DEBUGP("Failed to find symbol %s\n", name);
  	return 0;
@@ -379,7 +429,6 @@
 }
 #endif /* CONFIG_SMP */
 
-#ifdef CONFIG_MODULE_UNLOAD
 #define MODINFO_ATTR(field)	\
 static void setup_modinfo_##field(struct module *mod, const char *s)  \
 {                                                                     \
@@ -411,12 +460,7 @@
 MODINFO_ATTR(version);
 MODINFO_ATTR(srcversion);
 
-static struct module_attribute *modinfo_attrs[] = {
-	&modinfo_version,
-	&modinfo_srcversion,
-	NULL,
-};
-
+#ifdef CONFIG_MODULE_UNLOAD
 /* Init the unload section of the module. */
 static void module_unload_init(struct module *mod)
 {
@@ -731,6 +775,15 @@
 }
 #endif /* CONFIG_MODULE_UNLOAD */
 
+static struct module_attribute *modinfo_attrs[] = {
+	&modinfo_version,
+	&modinfo_srcversion,
+#ifdef CONFIG_MODULE_UNLOAD
+	&refcnt,
+#endif
+	NULL,
+};
+
 #ifdef CONFIG_OBSOLETE_MODPARM
 /* Bounds checking done below */
 static int obsparm_copy_string(const char *val, struct kernel_param *kp)
@@ -1056,37 +1109,28 @@
 }
 #endif /* CONFIG_KALLSYMS */
 
-
-#ifdef CONFIG_MODULE_UNLOAD
-static inline int module_add_refcnt_attr(struct module *mod)
-{
-	return sysfs_create_file(&mod->mkobj.kobj, &refcnt.attr);
-}
-static void module_remove_refcnt_attr(struct module *mod)
-{
-	return sysfs_remove_file(&mod->mkobj.kobj, &refcnt.attr);
-}
-#else
-static inline int module_add_refcnt_attr(struct module *mod)
-{
-	return 0;
-}
-static void module_remove_refcnt_attr(struct module *mod)
-{
-}
-#endif
-
-#ifdef CONFIG_MODULE_UNLOAD
 static int module_add_modinfo_attrs(struct module *mod)
 {
 	struct module_attribute *attr;
+	struct module_attribute *temp_attr;
 	int error = 0;
 	int i;
 
+	mod->modinfo_attrs = kzalloc((sizeof(struct module_attribute) *
+					(ARRAY_SIZE(modinfo_attrs) + 1)),
+					GFP_KERNEL);
+	if (!mod->modinfo_attrs)
+		return -ENOMEM;
+
+	temp_attr = mod->modinfo_attrs;
 	for (i = 0; (attr = modinfo_attrs[i]) && !error; i++) {
 		if (!attr->test ||
-		    (attr->test && attr->test(mod)))
-			error = sysfs_create_file(&mod->mkobj.kobj,&attr->attr);
+		    (attr->test && attr->test(mod))) {
+			memcpy(temp_attr, attr, sizeof(*temp_attr));
+			temp_attr->attr.owner = mod;
+			error = sysfs_create_file(&mod->mkobj.kobj,&temp_attr->attr);
+			++temp_attr;
+		}
 	}
 	return error;
 }
@@ -1096,12 +1140,16 @@
 	struct module_attribute *attr;
 	int i;
 
-	for (i = 0; (attr = modinfo_attrs[i]); i++) {
+	for (i = 0; (attr = &mod->modinfo_attrs[i]); i++) {
+		/* pick a field to test for end of list */
+		if (!attr->attr.name)
+			break;
 		sysfs_remove_file(&mod->mkobj.kobj,&attr->attr);
-		attr->free(mod);
+		if (attr->free)
+			attr->free(mod);
 	}
+	kfree(mod->modinfo_attrs);
 }
-#endif
 
 static int mod_sysfs_setup(struct module *mod,
 			   struct kernel_param *kparam,
@@ -1119,19 +1167,13 @@
 	if (err)
 		goto out;
 
-	err = module_add_refcnt_attr(mod);
-	if (err)
-		goto out_unreg;
-
 	err = module_param_sysfs_setup(mod, kparam, num_params);
 	if (err)
 		goto out_unreg;
 
-#ifdef CONFIG_MODULE_UNLOAD
 	err = module_add_modinfo_attrs(mod);
 	if (err)
 		goto out_unreg;
-#endif
 
 	return 0;
 
@@ -1143,10 +1185,7 @@
 
 static void mod_kobject_remove(struct module *mod)
 {
-#ifdef CONFIG_MODULE_UNLOAD
 	module_remove_modinfo_attrs(mod);
-#endif
-	module_remove_refcnt_attr(mod);
 	module_param_sysfs_remove(mod);
 
 	kobject_unregister(&mod->mkobj.kobj);
@@ -1424,7 +1463,6 @@
 	return NULL;
 }
 
-#ifdef CONFIG_MODULE_UNLOAD
 static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs,
 			  unsigned int infoindex)
 {
@@ -1439,23 +1477,17 @@
 						attr->attr.name));
 	}
 }
-#endif
 
 #ifdef CONFIG_KALLSYMS
 int is_exported(const char *name, const struct module *mod)
 {
-	unsigned int i;
-
-	if (!mod) {
-		for (i = 0; __start___ksymtab+i < __stop___ksymtab; i++)
-			if (strcmp(__start___ksymtab[i].name, name) == 0)
-				return 1;
-		return 0;
-	}
-	for (i = 0; i < mod->num_syms; i++)
-		if (strcmp(mod->syms[i].name, name) == 0)
+	if (!mod && lookup_symbol(name, __start___ksymtab, __stop___ksymtab))
+		return 1;
+	else
+		if (lookup_symbol(name, mod->syms, mod->syms + mod->num_syms))
 			return 1;
-	return 0;
+		else
+			return 0;
 }
 
 /* As per nm */
@@ -1537,7 +1569,8 @@
 	char *secstrings, *args, *modmagic, *strtab = NULL;
 	unsigned int i, symindex = 0, strindex = 0, setupindex, exindex,
 		exportindex, modindex, obsparmindex, infoindex, gplindex,
-		crcindex, gplcrcindex, versindex, pcpuindex;
+		crcindex, gplcrcindex, versindex, pcpuindex, gplfutureindex,
+		gplfuturecrcindex;
 	long arglen;
 	struct module *mod;
 	long err = 0;
@@ -1618,8 +1651,10 @@
 	/* Optional sections */
 	exportindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab");
 	gplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl");
+	gplfutureindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl_future");
 	crcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab");
 	gplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl");
+	gplfuturecrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl_future");
 	setupindex = find_sec(hdr, sechdrs, secstrings, "__param");
 	exindex = find_sec(hdr, sechdrs, secstrings, "__ex_table");
 	obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm");
@@ -1755,10 +1790,8 @@
 	if (strcmp(mod->name, "driverloader") == 0)
 		add_taint(TAINT_PROPRIETARY_MODULE);
 
-#ifdef CONFIG_MODULE_UNLOAD
 	/* Set up MODINFO_ATTR fields */
 	setup_modinfo(mod, sechdrs, infoindex);
-#endif
 
 	/* Fix up syms, so that st_value is a pointer to location. */
 	err = simplify_symbols(sechdrs, symindex, strtab, versindex, pcpuindex,
@@ -1775,10 +1808,16 @@
 	mod->gpl_syms = (void *)sechdrs[gplindex].sh_addr;
 	if (gplcrcindex)
 		mod->gpl_crcs = (void *)sechdrs[gplcrcindex].sh_addr;
+	mod->num_gpl_future_syms = sechdrs[gplfutureindex].sh_size /
+					sizeof(*mod->gpl_future_syms);
+	mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr;
+	if (gplfuturecrcindex)
+		mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr;
 
 #ifdef CONFIG_MODVERSIONS
 	if ((mod->num_syms && !crcindex) || 
-	    (mod->num_gpl_syms && !gplcrcindex)) {
+	    (mod->num_gpl_syms && !gplcrcindex) ||
+	    (mod->num_gpl_future_syms && !gplfuturecrcindex)) {
 		printk(KERN_WARNING "%s: No versions for exported symbols."
 		       " Tainting kernel.\n", mod->name);
 		add_taint(TAINT_FORCED_MODULE);
diff --git a/kernel/params.c b/kernel/params.c
index c76ad25..a291505 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -638,13 +638,8 @@
 	if (!attribute->show)
 		return -EIO;
 
-	if (!try_module_get(mk->mod))
-		return -ENODEV;
-
 	ret = attribute->show(attribute, mk->mod, buf);
 
-	module_put(mk->mod);
-
 	return ret;
 }
 
@@ -662,13 +657,8 @@
 	if (!attribute->store)
 		return -EIO;
 
-	if (!try_module_get(mk->mod))
-		return -ENODEV;
-
 	ret = attribute->store(attribute, mk->mod, buf, len);
 
-	module_put(mk->mod);
-
 	return ret;
 }
 
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c
index 8cf15a5..fedf5e3 100644
--- a/kernel/rcupdate.c
+++ b/kernel/rcupdate.c
@@ -609,7 +609,7 @@
 module_param(rsinterval, int, 0);
 #endif
 EXPORT_SYMBOL_GPL(rcu_batches_completed);
-EXPORT_SYMBOL(call_rcu);  /* WARNING: GPL-only in April 2006. */
-EXPORT_SYMBOL(call_rcu_bh);  /* WARNING: GPL-only in April 2006. */
+EXPORT_SYMBOL_GPL_FUTURE(call_rcu);	/* WARNING: GPL-only in April 2006. */
+EXPORT_SYMBOL_GPL_FUTURE(call_rcu_bh);	/* WARNING: GPL-only in April 2006. */
 EXPORT_SYMBOL_GPL(synchronize_rcu);
-EXPORT_SYMBOL(synchronize_kernel);  /* WARNING: GPL-only in April 2006. */
+EXPORT_SYMBOL_GPL_FUTURE(synchronize_kernel); /* WARNING: GPL-only in April 2006. */
diff --git a/lib/kobject.c b/lib/kobject.c
index efe67fa..25204a4 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -194,6 +194,17 @@
 		unlink(kobj);
 		if (parent)
 			kobject_put(parent);
+
+		/* be noisy on error issues */
+		if (error == -EEXIST)
+			printk("kobject_add failed for %s with -EEXIST, "
+			       "don't try to register things with the "
+			       "same name in the same directory.\n",
+			       kobject_name(kobj));
+		else
+			printk("kobject_add failed for %s (%d)\n",
+			       kobject_name(kobj), error);
+		dump_stack();
 	}
 
 	return error;
@@ -207,18 +218,13 @@
 
 int kobject_register(struct kobject * kobj)
 {
-	int error = 0;
+	int error = -EINVAL;
 	if (kobj) {
 		kobject_init(kobj);
 		error = kobject_add(kobj);
-		if (error) {
-			printk("kobject_register failed for %s (%d)\n",
-			       kobject_name(kobj),error);
-			dump_stack();
-		} else
+		if (!error)
 			kobject_uevent(kobj, KOBJ_ADD);
-	} else
-		error = -EINVAL;
+	}
 	return error;
 }
 
@@ -379,6 +385,44 @@
 }
 
 
+static void dir_release(struct kobject *kobj)
+{
+	kfree(kobj);
+}
+
+static struct kobj_type dir_ktype = {
+	.release	= dir_release,
+	.sysfs_ops	= NULL,
+	.default_attrs	= NULL,
+};
+
+/**
+ *	kobject_add_dir - add sub directory of object.
+ *	@parent:	object in which a directory is created.
+ *	@name:	directory name.
+ *
+ *	Add a plain directory object as child of given object.
+ */
+struct kobject *kobject_add_dir(struct kobject *parent, const char *name)
+{
+	struct kobject *k;
+
+	if (!parent)
+		return NULL;
+
+	k = kzalloc(sizeof(*k), GFP_KERNEL);
+	if (!k)
+		return NULL;
+
+	k->parent = parent;
+	k->ktype = &dir_ktype;
+	kobject_set_name(k, name);
+	kobject_register(k);
+
+	return k;
+}
+EXPORT_SYMBOL_GPL(kobject_add_dir);
+
 /**
  *	kset_init - initialize a kset for use
  *	@k:	kset 
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
index 086a0c6..982226d 100644
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -26,6 +26,8 @@
 #define NUM_ENVP	32	/* number of env pointers */
 
 #if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET)
+u64 uevent_seqnum;
+char uevent_helper[UEVENT_HELPER_PATH_LEN] = "/sbin/hotplug";
 static DEFINE_SPINLOCK(sequence_lock);
 static struct sock *uevent_sock;
 
diff --git a/lib/kref.c b/lib/kref.c
index 0d07cc3..4a467fa 100644
--- a/lib/kref.c
+++ b/lib/kref.c
@@ -52,7 +52,12 @@
 	WARN_ON(release == NULL);
 	WARN_ON(release == (void (*)(struct kref *))kfree);
 
-	if (atomic_dec_and_test(&kref->refcount)) {
+	/*
+	 * if current count is one, we are the last user and can release object
+	 * right now, avoiding an atomic operation on 'refcount'
+	 */
+	if ((atomic_read(&kref->refcount) == 1) ||
+	    (atomic_dec_and_test(&kref->refcount))) {
 		release(kref);
 		return 1;
 	}
diff --git a/scripts/genksyms/keywords.c_shipped b/scripts/genksyms/keywords.c_shipped
index ee46478..d8153f5 100644
--- a/scripts/genksyms/keywords.c_shipped
+++ b/scripts/genksyms/keywords.c_shipped
@@ -52,9 +52,9 @@
       71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
       71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
       71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
-      71, 71, 71, 71, 71, 71, 71, 71, 71, 15,
-      71, 71, 71, 71, 71, 71, 15, 71, 71, 71,
-      10, 71, 71, 71, 71, 71, 71, 71, 71, 71,
+      71, 71, 71, 71, 71, 71, 71, 71, 71,  0,
+      71, 71, 71, 71, 71, 71, 35, 71, 71, 71,
+       5, 71, 71, 71, 71, 71, 71, 71, 71, 71,
       71, 71, 71, 71, 71,  0, 71,  0, 71,  5,
        5,  0, 10, 20, 71, 25, 71, 71, 20,  0,
       20, 30, 25, 71, 10,  5,  0, 20, 15, 71,
@@ -84,9 +84,9 @@
 {
   enum
     {
-      TOTAL_KEYWORDS = 41,
+      TOTAL_KEYWORDS = 42,
       MIN_WORD_LENGTH = 3,
-      MAX_WORD_LENGTH = 17,
+      MAX_WORD_LENGTH = 24,
       MIN_HASH_VALUE = 3,
       MAX_HASH_VALUE = 70
     };
@@ -94,104 +94,105 @@
   static const struct resword wordlist[] =
     {
       {""}, {""}, {""},
-#line 24 "scripts/genksyms/keywords.gperf"
+#line 25 "scripts/genksyms/keywords.gperf"
       {"asm", ASM_KEYW},
       {""},
-#line 7 "scripts/genksyms/keywords.gperf"
+#line 8 "scripts/genksyms/keywords.gperf"
       {"__asm", ASM_KEYW},
       {""},
-#line 8 "scripts/genksyms/keywords.gperf"
+#line 9 "scripts/genksyms/keywords.gperf"
       {"__asm__", ASM_KEYW},
       {""},
-#line 21 "scripts/genksyms/keywords.gperf"
+#line 22 "scripts/genksyms/keywords.gperf"
       {"_restrict", RESTRICT_KEYW},
-#line 50 "scripts/genksyms/keywords.gperf"
+#line 51 "scripts/genksyms/keywords.gperf"
       {"__typeof__", TYPEOF_KEYW},
-#line 9 "scripts/genksyms/keywords.gperf"
-      {"__attribute", ATTRIBUTE_KEYW},
-#line 11 "scripts/genksyms/keywords.gperf"
-      {"__const", CONST_KEYW},
 #line 10 "scripts/genksyms/keywords.gperf"
-      {"__attribute__", ATTRIBUTE_KEYW},
+      {"__attribute", ATTRIBUTE_KEYW},
 #line 12 "scripts/genksyms/keywords.gperf"
+      {"__const", CONST_KEYW},
+#line 11 "scripts/genksyms/keywords.gperf"
+      {"__attribute__", ATTRIBUTE_KEYW},
+#line 13 "scripts/genksyms/keywords.gperf"
       {"__const__", CONST_KEYW},
-#line 16 "scripts/genksyms/keywords.gperf"
+#line 17 "scripts/genksyms/keywords.gperf"
       {"__signed__", SIGNED_KEYW},
-#line 42 "scripts/genksyms/keywords.gperf"
+#line 43 "scripts/genksyms/keywords.gperf"
       {"static", STATIC_KEYW},
       {""},
-#line 15 "scripts/genksyms/keywords.gperf"
+#line 16 "scripts/genksyms/keywords.gperf"
       {"__signed", SIGNED_KEYW},
-#line 30 "scripts/genksyms/keywords.gperf"
+#line 31 "scripts/genksyms/keywords.gperf"
       {"char", CHAR_KEYW},
       {""},
-#line 43 "scripts/genksyms/keywords.gperf"
+#line 44 "scripts/genksyms/keywords.gperf"
       {"struct", STRUCT_KEYW},
-#line 22 "scripts/genksyms/keywords.gperf"
-      {"__restrict__", RESTRICT_KEYW},
 #line 23 "scripts/genksyms/keywords.gperf"
+      {"__restrict__", RESTRICT_KEYW},
+#line 24 "scripts/genksyms/keywords.gperf"
       {"restrict", RESTRICT_KEYW},
-#line 33 "scripts/genksyms/keywords.gperf"
-      {"enum", ENUM_KEYW},
-#line 17 "scripts/genksyms/keywords.gperf"
-      {"__volatile", VOLATILE_KEYW},
 #line 34 "scripts/genksyms/keywords.gperf"
-      {"extern", EXTERN_KEYW},
+      {"enum", ENUM_KEYW},
 #line 18 "scripts/genksyms/keywords.gperf"
+      {"__volatile", VOLATILE_KEYW},
+#line 35 "scripts/genksyms/keywords.gperf"
+      {"extern", EXTERN_KEYW},
+#line 19 "scripts/genksyms/keywords.gperf"
       {"__volatile__", VOLATILE_KEYW},
-#line 37 "scripts/genksyms/keywords.gperf"
+#line 38 "scripts/genksyms/keywords.gperf"
       {"int", INT_KEYW},
-      {""},
-#line 31 "scripts/genksyms/keywords.gperf"
-      {"const", CONST_KEYW},
+#line 7 "scripts/genksyms/keywords.gperf"
+      {"EXPORT_SYMBOL_GPL_FUTURE", EXPORT_SYMBOL_KEYW},
 #line 32 "scripts/genksyms/keywords.gperf"
+      {"const", CONST_KEYW},
+#line 33 "scripts/genksyms/keywords.gperf"
       {"double", DOUBLE_KEYW},
       {""},
-#line 13 "scripts/genksyms/keywords.gperf"
-      {"__inline", INLINE_KEYW},
-#line 29 "scripts/genksyms/keywords.gperf"
-      {"auto", AUTO_KEYW},
 #line 14 "scripts/genksyms/keywords.gperf"
+      {"__inline", INLINE_KEYW},
+#line 30 "scripts/genksyms/keywords.gperf"
+      {"auto", AUTO_KEYW},
+#line 15 "scripts/genksyms/keywords.gperf"
       {"__inline__", INLINE_KEYW},
-#line 41 "scripts/genksyms/keywords.gperf"
+#line 42 "scripts/genksyms/keywords.gperf"
       {"signed", SIGNED_KEYW},
       {""},
-#line 46 "scripts/genksyms/keywords.gperf"
+#line 47 "scripts/genksyms/keywords.gperf"
       {"unsigned", UNSIGNED_KEYW},
       {""},
-#line 40 "scripts/genksyms/keywords.gperf"
+#line 41 "scripts/genksyms/keywords.gperf"
       {"short", SHORT_KEYW},
-#line 49 "scripts/genksyms/keywords.gperf"
+#line 50 "scripts/genksyms/keywords.gperf"
       {"typeof", TYPEOF_KEYW},
-#line 44 "scripts/genksyms/keywords.gperf"
+#line 45 "scripts/genksyms/keywords.gperf"
       {"typedef", TYPEDEF_KEYW},
-#line 48 "scripts/genksyms/keywords.gperf"
+#line 49 "scripts/genksyms/keywords.gperf"
       {"volatile", VOLATILE_KEYW},
       {""},
-#line 35 "scripts/genksyms/keywords.gperf"
+#line 36 "scripts/genksyms/keywords.gperf"
       {"float", FLOAT_KEYW},
       {""}, {""},
-#line 39 "scripts/genksyms/keywords.gperf"
+#line 40 "scripts/genksyms/keywords.gperf"
       {"register", REGISTER_KEYW},
-#line 47 "scripts/genksyms/keywords.gperf"
+#line 48 "scripts/genksyms/keywords.gperf"
       {"void", VOID_KEYW},
       {""},
-#line 36 "scripts/genksyms/keywords.gperf"
+#line 37 "scripts/genksyms/keywords.gperf"
       {"inline", INLINE_KEYW},
       {""},
 #line 5 "scripts/genksyms/keywords.gperf"
       {"EXPORT_SYMBOL", EXPORT_SYMBOL_KEYW},
       {""},
-#line 20 "scripts/genksyms/keywords.gperf"
+#line 21 "scripts/genksyms/keywords.gperf"
       {"_Bool", BOOL_KEYW},
       {""},
 #line 6 "scripts/genksyms/keywords.gperf"
       {"EXPORT_SYMBOL_GPL", EXPORT_SYMBOL_KEYW},
       {""}, {""}, {""}, {""}, {""}, {""},
-#line 38 "scripts/genksyms/keywords.gperf"
+#line 39 "scripts/genksyms/keywords.gperf"
       {"long", LONG_KEYW},
       {""}, {""}, {""}, {""}, {""},
-#line 45 "scripts/genksyms/keywords.gperf"
+#line 46 "scripts/genksyms/keywords.gperf"
       {"union", UNION_KEYW}
     };
 
diff --git a/scripts/genksyms/keywords.gperf b/scripts/genksyms/keywords.gperf
index b6bec76..c75e0c8 100644
--- a/scripts/genksyms/keywords.gperf
+++ b/scripts/genksyms/keywords.gperf
@@ -4,6 +4,7 @@
 %%
 EXPORT_SYMBOL, EXPORT_SYMBOL_KEYW
 EXPORT_SYMBOL_GPL, EXPORT_SYMBOL_KEYW
+EXPORT_SYMBOL_GPL_FUTURE, EXPORT_SYMBOL_KEYW
 __asm, ASM_KEYW
 __asm__, ASM_KEYW
 __attribute, ATTRIBUTE_KEYW