Merge git://git.linux-nfs.org/projects/trondmy/nfs-2.6

* git://git.linux-nfs.org/projects/trondmy/nfs-2.6: (80 commits)
  SUNRPC: Invalidate the RPCSEC_GSS session if the server dropped the request
  make nfs_automount_list static
  NFS: remove duplicate flags assignment from nfs_validate_mount_data
  NFS - fix potential NULL pointer dereference v2
  SUNRPC: Don't change the RPCSEC_GSS context on a credential that is in use
  SUNRPC: Fix a race in gss_refresh_upcall()
  SUNRPC: Don't disconnect more than once if retransmitting NFSv4 requests
  SUNRPC: Remove the unused export of xprt_force_disconnect
  SUNRPC: remove XS_SENDMSG_RETRY
  SUNRPC: Protect creds against early garbage collection
  NFSv4: Attempt to use machine credentials in SETCLIENTID calls
  NFSv4: Reintroduce machine creds
  NFSv4: Don't use cred->cr_ops->cr_name in nfs4_proc_setclientid()
  nfs: fix printout of multiword bitfields
  nfs: return negative error value from nfs{,4}_stat_to_errno
  NLM/lockd: Ensure client locking calls use correct credentials
  NFS: Remove the buggy lock-if-signalled case from do_setlk()
  NLM/lockd: Fix a race when cancelling a blocking lock
  NLM/lockd: Ensure that nlmclnt_cancel() returns results of the CANCEL call
  NLM: Remove the signal masking in nlmclnt_proc/nlmclnt_cancel
  ...
diff --git a/CREDITS b/CREDITS
index da0a56e..8fec7b3 100644
--- a/CREDITS
+++ b/CREDITS
@@ -403,6 +403,8 @@
 N: Erik Inge Bolsø
 E: knan@mo.himolde.no
 D: Misc kernel hacks
+D: Updated PC speaker driver for 2.3
+S: Norway
 
 N: Andreas E. Bombe
 E: andreas.bombe@munich.netsurf.de
@@ -3116,6 +3118,12 @@
 S: Sunnyvale, California 94088-4132
 S: USA
 
+N: Stas Sergeev
+E: stsp@users.sourceforge.net
+D: PCM PC-Speaker driver
+D: misc fixes
+S: Russia
+
 N: Simon Shapiro
 E: shimon@i-Connect.Net
 W: http://www.-i-Connect.Net/~shimon
diff --git a/Documentation/filesystems/nfs-rdma.txt b/Documentation/filesystems/nfs-rdma.txt
new file mode 100644
index 0000000..1ae3487
--- /dev/null
+++ b/Documentation/filesystems/nfs-rdma.txt
@@ -0,0 +1,252 @@
+################################################################################
+#									       #
+#				NFS/RDMA README				       #
+#									       #
+################################################################################
+
+ Author: NetApp and Open Grid Computing
+ Date: February 25, 2008
+
+Table of Contents
+~~~~~~~~~~~~~~~~~
+ - Overview
+ - Getting Help
+ - Installation
+ - Check RDMA and NFS Setup
+ - NFS/RDMA Setup
+
+Overview
+~~~~~~~~
+
+  This document describes how to install and setup the Linux NFS/RDMA client
+  and server software.
+
+  The NFS/RDMA client was first included in Linux 2.6.24. The NFS/RDMA server
+  was first included in the following release, Linux 2.6.25.
+
+  In our testing, we have obtained excellent performance results (full 10Gbit
+  wire bandwidth at minimal client CPU) under many workloads. The code passes
+  the full Connectathon test suite and operates over both Infiniband and iWARP
+  RDMA adapters.
+
+Getting Help
+~~~~~~~~~~~~
+
+  If you get stuck, you can ask questions on the
+
+                nfs-rdma-devel@lists.sourceforge.net
+
+  mailing list.
+
+Installation
+~~~~~~~~~~~~
+
+  These instructions are a step by step guide to building a machine for
+  use with NFS/RDMA.
+
+  - Install an RDMA device
+
+    Any device supported by the drivers in drivers/infiniband/hw is acceptable.
+
+    Testing has been performed using several Mellanox-based IB cards, the
+    Ammasso AMS1100 iWARP adapter, and the Chelsio cxgb3 iWARP adapter.
+
+  - Install a Linux distribution and tools
+
+    The first kernel release to contain both the NFS/RDMA client and server was
+    Linux 2.6.25  Therefore, a distribution compatible with this and subsequent
+    Linux kernel release should be installed.
+
+    The procedures described in this document have been tested with
+    distributions from Red Hat's Fedora Project (http://fedora.redhat.com/).
+
+  - Install nfs-utils-1.1.1 or greater on the client
+
+    An NFS/RDMA mount point can only be obtained by using the mount.nfs
+    command in nfs-utils-1.1.1 or greater. To see which version of mount.nfs
+    you are using, type:
+
+    > /sbin/mount.nfs -V
+
+    If the version is less than 1.1.1 or the command does not exist,
+    then you will need to install the latest version of nfs-utils.
+
+    Download the latest package from:
+
+    http://www.kernel.org/pub/linux/utils/nfs
+
+    Uncompress the package and follow the installation instructions.
+
+    If you will not be using GSS and NFSv4, the installation process
+    can be simplified by disabling these features when running configure:
+
+    > ./configure --disable-gss --disable-nfsv4
+
+    For more information on this see the package's README and INSTALL files.
+
+    After building the nfs-utils package, there will be a mount.nfs binary in
+    the utils/mount directory. This binary can be used to initiate NFS v2, v3,
+    or v4 mounts. To initiate a v4 mount, the binary must be called mount.nfs4.
+    The standard technique is to create a symlink called mount.nfs4 to mount.nfs.
+
+    NOTE: mount.nfs and therefore nfs-utils-1.1.1 or greater is only needed
+    on the NFS client machine. You do not need this specific version of
+    nfs-utils on the server. Furthermore, only the mount.nfs command from
+    nfs-utils-1.1.1 is needed on the client.
+
+  - Install a Linux kernel with NFS/RDMA
+
+    The NFS/RDMA client and server are both included in the mainline Linux
+    kernel version 2.6.25 and later. This and other versions of the 2.6 Linux
+    kernel can be found at:
+
+    ftp://ftp.kernel.org/pub/linux/kernel/v2.6/
+
+    Download the sources and place them in an appropriate location.
+
+  - Configure the RDMA stack
+
+    Make sure your kernel configuration has RDMA support enabled. Under
+    Device Drivers -> InfiniBand support, update the kernel configuration
+    to enable InfiniBand support [NOTE: the option name is misleading. Enabling
+    InfiniBand support is required for all RDMA devices (IB, iWARP, etc.)].
+
+    Enable the appropriate IB HCA support (mlx4, mthca, ehca, ipath, etc.) or
+    iWARP adapter support (amso, cxgb3, etc.).
+
+    If you are using InfiniBand, be sure to enable IP-over-InfiniBand support.
+
+  - Configure the NFS client and server
+
+    Your kernel configuration must also have NFS file system support and/or
+    NFS server support enabled. These and other NFS related configuration
+    options can be found under File Systems -> Network File Systems.
+
+  - Build, install, reboot
+
+    The NFS/RDMA code will be enabled automatically if NFS and RDMA
+    are turned on. The NFS/RDMA client and server are configured via the hidden
+    SUNRPC_XPRT_RDMA config option that depends on SUNRPC and INFINIBAND. The
+    value of SUNRPC_XPRT_RDMA will be:
+
+     - N if either SUNRPC or INFINIBAND are N, in this case the NFS/RDMA client
+       and server will not be built
+     - M if both SUNRPC and INFINIBAND are on (M or Y) and at least one is M,
+       in this case the NFS/RDMA client and server will be built as modules
+     - Y if both SUNRPC and INFINIBAND are Y, in this case the NFS/RDMA client
+       and server will be built into the kernel
+
+    Therefore, if you have followed the steps above and turned no NFS and RDMA,
+    the NFS/RDMA client and server will be built.
+
+    Build a new kernel, install it, boot it.
+
+Check RDMA and NFS Setup
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Before configuring the NFS/RDMA software, it is a good idea to test
+    your new kernel to ensure that the kernel is working correctly.
+    In particular, it is a good idea to verify that the RDMA stack
+    is functioning as expected and standard NFS over TCP/IP and/or UDP/IP
+    is working properly.
+
+  - Check RDMA Setup
+
+    If you built the RDMA components as modules, load them at
+    this time. For example, if you are using a Mellanox Tavor/Sinai/Arbel
+    card:
+
+    > modprobe ib_mthca
+    > modprobe ib_ipoib
+
+    If you are using InfiniBand, make sure there is a Subnet Manager (SM)
+    running on the network. If your IB switch has an embedded SM, you can
+    use it. Otherwise, you will need to run an SM, such as OpenSM, on one
+    of your end nodes.
+
+    If an SM is running on your network, you should see the following:
+
+    > cat /sys/class/infiniband/driverX/ports/1/state
+    4: ACTIVE
+
+    where driverX is mthca0, ipath5, ehca3, etc.
+
+    To further test the InfiniBand software stack, use IPoIB (this
+    assumes you have two IB hosts named host1 and host2):
+
+    host1> ifconfig ib0 a.b.c.x
+    host2> ifconfig ib0 a.b.c.y
+    host1> ping a.b.c.y
+    host2> ping a.b.c.x
+
+    For other device types, follow the appropriate procedures.
+
+  - Check NFS Setup
+
+    For the NFS components enabled above (client and/or server),
+    test their functionality over standard Ethernet using TCP/IP or UDP/IP.
+
+NFS/RDMA Setup
+~~~~~~~~~~~~~~
+
+  We recommend that you use two machines, one to act as the client and
+  one to act as the server.
+
+  One time configuration:
+
+  - On the server system, configure the /etc/exports file and
+    start the NFS/RDMA server.
+
+    Exports entries with the following format have been tested:
+
+    /vol0   10.97.103.47(rw,async) 192.168.0.47(rw,async,insecure,no_root_squash)
+
+    Here the first IP address is the client's Ethernet address and the second
+    IP address is the clients IPoIB address.
+
+ Each time a machine boots:
+
+  - Load and configure the RDMA drivers
+
+    For InfiniBand using a Mellanox adapter:
+
+    > modprobe ib_mthca
+    > modprobe ib_ipoib
+    > ifconfig ib0 a.b.c.d
+
+    NOTE: use unique addresses for the client and server
+
+  - Start the NFS server
+
+    If the NFS/RDMA server was built as a module (CONFIG_SUNRPC_XPRT_RDMA=m in kernel config),
+    load the RDMA transport module:
+
+    > modprobe svcrdma
+
+    Regardless of how the server was built (module or built-in), start the server:
+
+    > /etc/init.d/nfs start
+
+    or
+
+    > service nfs start
+
+    Instruct the server to listen on the RDMA transport:
+
+    > echo rdma 2050 > /proc/fs/nfsd/portlist
+
+  - On the client system
+
+    If the NFS/RDMA client was built as a module (CONFIG_SUNRPC_XPRT_RDMA=m in kernel config),
+    load the RDMA client module:
+
+    > modprobe xprtrdma.ko
+
+    Regardless of how the client was built (module or built-in), issue the mount.nfs command:
+
+    > /path/to/your/mount.nfs <IPoIB-server-name-or-address>:/<export> /mnt -i -o rdma,port=2050
+
+    To verify that the mount is using RDMA, run "cat /proc/mounts" and check the
+    "proto" field for the given mount.
+
+  Congratulations! You're using NFS/RDMA!
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index e985cf5..fd4c32a 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -284,6 +284,13 @@
            control correctly. If you have problems regarding this, try
            another ALSA compliant mixer (alsamixer works).
 
+  Module snd-aw2
+  --------------
+
+    Module for Audiowerk2 sound card
+
+    This module supports multiple cards.
+
   Module snd-azt2320
   ------------------
 
@@ -818,19 +825,25 @@
 	  hippo_1	Hippo (Benq) with jack detection
 	  sony-assamd	Sony ASSAMD
 	  ultra		Samsung Q1 Ultra Vista model
+	  lenovo-3000	Lenovo 3000 y410
 	  basic		fixed pin assignment w/o SPDIF
 	  auto		auto-config reading BIOS (default)
 
-	ALC268
+	ALC267/268
+	  quanta-il1	Quanta IL1 mini-notebook
 	  3stack	3-stack model
 	  toshiba	Toshiba A205
 	  acer		Acer laptops
 	  dell		Dell OEM laptops (Vostro 1200)
+	  zepto		Zepto laptops
 	  test		for testing/debugging purpose, almost all controls can
 			adjusted.  Appearing only when compiled with
 			$CONFIG_SND_DEBUG=y
 	  auto		auto-config reading BIOS (default)
 
+	ALC269
+	  basic		Basic preset
+
 	ALC662
 	  3stack-dig	3-stack (2-channel) with SPDIF
 	  3stack-6ch	 3-stack (6-channel)
@@ -871,10 +884,11 @@
 	  lenovo-nb0763	Lenovo NB0763
 	  lenovo-ms7195-dig Lenovo MS7195
 	  haier-w66	Haier W66
-	  6stack-hp	HP machines with 6stack (Nettle boards)
 	  3stack-hp	HP machines with 3stack (Lucknow, Samba boards)
 	  6stack-dell	Dell machines with 6stack (Inspiron 530)
 	  mitac		Mitac 8252D
+	  clevo-m720	Clevo M720 laptop series
+	  fujitsu-pi2515 Fujitsu AMILO Pi2515
 	  auto		auto-config reading BIOS (default)
 
 	ALC861/660
@@ -911,6 +925,12 @@
 	  3stack	3-stack mode (default)
 	  6stack	6-stack mode
 
+	AD1884A / AD1883 / AD1984A / AD1984B
+	  desktop	3-stack desktop (default)
+	  laptop	laptop with HP jack sensing
+	  mobile	mobile devices with HP jack sensing
+	  thinkpad	Lenovo Thinkpad X300
+
 	AD1884
 	  N/A
 
@@ -936,7 +956,7 @@
 	  laptop-automute 2-channel with EAPD and HP-automute (Lenovo N100)
 	  ultra		2-channel with EAPD (Samsung Ultra tablet PC)
 
-	AD1988
+	AD1988/AD1988B/AD1989A/AD1989B
 	  6stack	6-jack
 	  6stack-dig	ditto with SPDIF
 	  3stack	3-jack
@@ -979,6 +999,7 @@
 	  dell-m26	Dell Inspiron 1501
 	  dell-m27	Dell Inspiron E1705/9400
 	  gateway	Gateway laptops with EAPD control
+	  panasonic	Panasonic CF-74
 
 	STAC9205/9254
 	  ref		Reference board
@@ -1017,6 +1038,16 @@
 	  3stack	D965 3stack
 	  5stack	D965 5stack + SPDIF
 	  dell-3stack	Dell Dimension E520
+	  dell-bios	Fixes with Dell BIOS setup
+
+	STAC92HD71B*
+	  ref		Reference board
+	  dell-m4-1	Dell desktops
+	  dell-m4-2	Dell desktops
+
+	STAC92HD73*
+	  ref		Reference board
+	  dell-m6	Dell desktops
 
 	STAC9872
 	  vaio		Setup for VAIO FE550G/SZ110
@@ -1590,6 +1621,16 @@
 
     Power management is _not_ supported.
 
+  Module snd-pcsp
+  -----------------
+
+    Module for internal PC-Speaker.
+
+    nforce_wa	- enable NForce chipset workaround. Expect bad sound.
+
+    This module supports system beeps, some kind of PCM playback and
+    even a few mixer controls.
+
   Module snd-pcxhr
   ----------------
 
diff --git a/Documentation/video4linux/CARDLIST.au0828 b/Documentation/video4linux/CARDLIST.au0828
new file mode 100644
index 0000000..aaae360
--- /dev/null
+++ b/Documentation/video4linux/CARDLIST.au0828
@@ -0,0 +1,4 @@
+  0 -> Unknown board                            (au0828)
+  1 -> Hauppauge HVR950Q                        (au0828)        [2040:7200]
+  2 -> Hauppauge HVR850                         (au0828)        [2040:7240]
+  3 -> DViCO FusionHDTV USB                     (au0828)        [0fe9:d620]
diff --git a/Documentation/video4linux/CARDLIST.bttv b/Documentation/video4linux/CARDLIST.bttv
index d97cf7c..f32efb6 100644
--- a/Documentation/video4linux/CARDLIST.bttv
+++ b/Documentation/video4linux/CARDLIST.bttv
@@ -148,3 +148,5 @@
 147 -> VoodooTV 200 (USA)                                  [121a:3000]
 148 -> DViCO FusionHDTV 2                                  [dbc0:d200]
 149 -> Typhoon TV-Tuner PCI (50684)
+150 -> Geovision GV-600                                    [008a:763c]
+151 -> Kozumi KTV-01C
diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885
index 0924e6e..929b90c 100644
--- a/Documentation/video4linux/CARDLIST.cx23885
+++ b/Documentation/video4linux/CARDLIST.cx23885
@@ -5,3 +5,6 @@
   4 -> DViCO FusionHDTV5 Express                           [18ac:d500]
   5 -> Hauppauge WinTV-HVR1500Q                            [0070:7790,0070:7797]
   6 -> Hauppauge WinTV-HVR1500                             [0070:7710,0070:7717]
+  7 -> Hauppauge WinTV-HVR1200                             [0070:71d1]
+  8 -> Hauppauge WinTV-HVR1700                             [0070:8101]
+  9 -> Hauppauge WinTV-HVR1400                             [0070:8010]
diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88
index bc5593b..5439573 100644
--- a/Documentation/video4linux/CARDLIST.cx88
+++ b/Documentation/video4linux/CARDLIST.cx88
@@ -57,3 +57,12 @@
  56 -> Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder   [0070:9600,0070:9601,0070:9602]
  57 -> ADS Tech Instant Video PCI                          [1421:0390]
  58 -> Pinnacle PCTV HD 800i                               [11bd:0051]
+ 59 -> DViCO FusionHDTV 5 PCI nano                         [18ac:d530]
+ 60 -> Pinnacle Hybrid PCTV                                [12ab:1788]
+ 61 -> Winfast TV2000 XP Global                            [107d:6f18]
+ 62 -> PowerColor Real Angel 330                           [14f1:ea3d]
+ 63 -> Geniatech X8000-MT DVBT                             [14f1:8852]
+ 64 -> DViCO FusionHDTV DVB-T PRO                          [18ac:db30]
+ 65 -> DViCO FusionHDTV 7 Gold                             [18ac:d610]
+ 66 -> Prolink Pixelview MPEG 8000GT                       [1554:4935]
+ 67 -> Kworld PlusTV HD PCI 120 (ATSC 120)                 [17de:08c1]
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
index 0424901..44d84dd 100644
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -25,8 +25,8 @@
  24 -> KNC One TV-Station DVR                   [1894:a006]
  25 -> ASUS TV-FM 7133                          [1043:4843]
  26 -> Pinnacle PCTV Stereo (saa7134)           [11bd:002b]
- 27 -> Manli MuchTV M-TV002/Behold TV 403 FM
- 28 -> Manli MuchTV M-TV001/Behold TV 401
+ 27 -> Manli MuchTV M-TV002
+ 28 -> Manli MuchTV M-TV001
  29 -> Nagase Sangyo TransGear 3000TV           [1461:050c]
  30 -> Elitegroup ECS TVP3XP FM1216 Tuner Card(PAL-BG,FM)  [1019:4cb4]
  31 -> Elitegroup ECS TVP3XP FM1236 Tuner Card (NTSC,FM) [1019:4cb5]
@@ -131,3 +131,12 @@
 130 -> Beholder BeholdTV M6 / BeholdTV M6 Extra [5ace:6190,5ace:6193]
 131 -> Twinhan Hybrid DTV-DVB 3056 PCI          [1822:0022]
 132 -> Genius TVGO AM11MCE
+133 -> NXP Snake DVB-S reference design
+134 -> Medion/Creatix CTX953 Hybrid             [16be:0010]
+135 -> MSI TV@nywhere A/D v1.1                  [1462:8625]
+136 -> AVerMedia Cardbus TV/Radio (E506R)       [1461:f436]
+137 -> AVerMedia Hybrid TV/Radio (A16D)         [1461:f936]
+138 -> Avermedia M115                           [1461:a836]
+139 -> Compro VideoMate T750                    [185b:c900]
+140 -> Avermedia DVB-S Pro A700                 [1461:a7a1]
+141 -> Avermedia DVB-S Hybrid+FM A700           [1461:a7a2]
diff --git a/Documentation/video4linux/extract_xc3028.pl b/Documentation/video4linux/extract_xc3028.pl
index cced8ac..2cb8160 100644
--- a/Documentation/video4linux/extract_xc3028.pl
+++ b/Documentation/video4linux/extract_xc3028.pl
@@ -686,11 +686,11 @@
 	write_hunk(812664, 192);
 
 	#
-	# Firmware 58, type: SCODE FW  HAS IF (0x60000000), IF = 4.50 MHz id: NTSC/M Jp (0000000000002000), size: 192
+	# Firmware 58, type: SCODE FW  MTS LCD NOGD MONO IF HAS IF (0x6002b004), IF = 4.50 MHz id: NTSC PAL/M PAL/N (000000000000b700), size: 192
 	#
 
-	write_le32(0x60000000);			# Type
-	write_le64(0x00000000, 0x00002000);	# ID
+	write_le32(0x6002b004);			# Type
+	write_le64(0x00000000, 0x0000b700);	# ID
 	write_le16(4500);			# IF
 	write_le32(192);			# Size
 	write_hunk(807672, 192);
@@ -706,10 +706,10 @@
 	write_hunk(807864, 192);
 
 	#
-	# Firmware 60, type: SCODE FW  DTV78 ZARLINK456 HAS IF (0x62000100), IF = 4.76 MHz id: (0000000000000000), size: 192
+	# Firmware 60, type: SCODE FW  DTV6 QAM DTV7 DTV78 DTV8 ZARLINK456 HAS IF (0x620003e0), IF = 4.76 MHz id: (0000000000000000), size: 192
 	#
 
-	write_le32(0x62000100);			# Type
+	write_le32(0x620003e0);			# Type
 	write_le64(0x00000000, 0x00000000);	# ID
 	write_le16(4760);			# IF
 	write_le32(192);			# Size
@@ -726,30 +726,30 @@
 	write_hunk(811512, 192);
 
 	#
-	# Firmware 62, type: SCODE FW  DTV7 ZARLINK456 HAS IF (0x62000080), IF = 5.26 MHz id: (0000000000000000), size: 192
+	# Firmware 62, type: SCODE FW  HAS IF (0x60000000), IF = 5.26 MHz id: (0000000000000000), size: 192
 	#
 
-	write_le32(0x62000080);			# Type
+	write_le32(0x60000000);			# Type
 	write_le64(0x00000000, 0x00000000);	# ID
 	write_le16(5260);			# IF
 	write_le32(192);			# Size
 	write_hunk(810552, 192);
 
 	#
-	# Firmware 63, type: SCODE FW  MONO HAS IF (0x60008000), IF = 5.32 MHz id: PAL/BG NICAM/B (0000000800000007), size: 192
+	# Firmware 63, type: SCODE FW  MONO HAS IF (0x60008000), IF = 5.32 MHz id: PAL/BG A2 NICAM (0000000f00000007), size: 192
 	#
 
 	write_le32(0x60008000);			# Type
-	write_le64(0x00000008, 0x00000007);	# ID
+	write_le64(0x0000000f, 0x00000007);	# ID
 	write_le16(5320);			# IF
 	write_le32(192);			# Size
 	write_hunk(810744, 192);
 
 	#
-	# Firmware 64, type: SCODE FW  DTV8 CHINA HAS IF (0x64000200), IF = 5.40 MHz id: (0000000000000000), size: 192
+	# Firmware 64, type: SCODE FW  DTV7 DTV78 DTV8 DIBCOM52 CHINA HAS IF (0x65000380), IF = 5.40 MHz id: (0000000000000000), size: 192
 	#
 
-	write_le32(0x64000200);			# Type
+	write_le32(0x65000380);			# Type
 	write_le64(0x00000000, 0x00000000);	# ID
 	write_le16(5400);			# IF
 	write_le32(192);			# Size
@@ -766,50 +766,50 @@
 	write_hunk(809592, 192);
 
 	#
-	# Firmware 66, type: SCODE FW  HAS IF (0x60000000), IF = 5.64 MHz id: PAL/BG A2/B (0000000200000007), size: 192
+	# Firmware 66, type: SCODE FW  HAS IF (0x60000000), IF = 5.64 MHz id: PAL/BG A2 (0000000300000007), size: 192
 	#
 
 	write_le32(0x60000000);			# Type
-	write_le64(0x00000002, 0x00000007);	# ID
+	write_le64(0x00000003, 0x00000007);	# ID
 	write_le16(5640);			# IF
 	write_le32(192);			# Size
 	write_hunk(808440, 192);
 
 	#
-	# Firmware 67, type: SCODE FW  HAS IF (0x60000000), IF = 5.74 MHz id: PAL/BG NICAM/B (0000000800000007), size: 192
+	# Firmware 67, type: SCODE FW  HAS IF (0x60000000), IF = 5.74 MHz id: PAL/BG NICAM (0000000c00000007), size: 192
 	#
 
 	write_le32(0x60000000);			# Type
-	write_le64(0x00000008, 0x00000007);	# ID
+	write_le64(0x0000000c, 0x00000007);	# ID
 	write_le16(5740);			# IF
 	write_le32(192);			# Size
 	write_hunk(808632, 192);
 
 	#
-	# Firmware 68, type: SCODE FW  DTV7 DIBCOM52 HAS IF (0x61000080), IF = 5.90 MHz id: (0000000000000000), size: 192
+	# Firmware 68, type: SCODE FW  HAS IF (0x60000000), IF = 5.90 MHz id: (0000000000000000), size: 192
 	#
 
-	write_le32(0x61000080);			# Type
+	write_le32(0x60000000);			# Type
 	write_le64(0x00000000, 0x00000000);	# ID
 	write_le16(5900);			# IF
 	write_le32(192);			# Size
 	write_hunk(810360, 192);
 
 	#
-	# Firmware 69, type: SCODE FW  MONO HAS IF (0x60008000), IF = 6.00 MHz id: PAL/I (0000000000000010), size: 192
+	# Firmware 69, type: SCODE FW  MONO HAS IF (0x60008000), IF = 6.00 MHz id: PAL/DK PAL/I SECAM/K3 SECAM/L SECAM/Lc NICAM (0000000c04c000f0), size: 192
 	#
 
 	write_le32(0x60008000);			# Type
-	write_le64(0x00000000, 0x00000010);	# ID
+	write_le64(0x0000000c, 0x04c000f0);	# ID
 	write_le16(6000);			# IF
 	write_le32(192);			# Size
 	write_hunk(808824, 192);
 
 	#
-	# Firmware 70, type: SCODE FW  DTV6 QAM F6MHZ HAS IF (0x68000060), IF = 6.20 MHz id: (0000000000000000), size: 192
+	# Firmware 70, type: SCODE FW  DTV6 QAM ATSC LG60 F6MHZ HAS IF (0x68050060), IF = 6.20 MHz id: (0000000000000000), size: 192
 	#
 
-	write_le32(0x68000060);			# Type
+	write_le32(0x68050060);			# Type
 	write_le64(0x00000000, 0x00000000);	# ID
 	write_le16(6200);			# IF
 	write_le32(192);			# Size
@@ -846,11 +846,11 @@
 	write_hunk(809208, 192);
 
 	#
-	# Firmware 74, type: SCODE FW  MONO HAS IF (0x60008000), IF = 6.50 MHz id: SECAM/K3 (0000000004000000), size: 192
+	# Firmware 74, type: SCODE FW  MONO HAS IF (0x60008000), IF = 6.50 MHz id: PAL/DK SECAM/K3 SECAM/L NICAM (0000000c044000e0), size: 192
 	#
 
 	write_le32(0x60008000);			# Type
-	write_le64(0x00000000, 0x04000000);	# ID
+	write_le64(0x0000000c, 0x044000e0);	# ID
 	write_le16(6500);			# IF
 	write_le32(192);			# Size
 	write_hunk(811128, 192);
diff --git a/MAINTAINERS b/MAINTAINERS
index c0cc52a..f50e927 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2558,12 +2558,10 @@
 S:	Maintained
 
 MAC80211
-P:	Michael Wu
-M:	flamingice@sourmilk.net
 P:	Johannes Berg
 M:	johannes@sipsolutions.net
-P:	Jiri Benc
-M:	jbenc@suse.cz
+P:	Michael Wu
+M:	flamingice@sourmilk.net
 L:	linux-wireless@vger.kernel.org
 W:	http://linuxwireless.org/
 T:	git kernel.org:/pub/scm/linux/kernel/git/linville/wireless-2.6.git
diff --git a/Makefile b/Makefile
index 3dbc826..d35c524 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 25
-EXTRAVERSION =
+EXTRAVERSION = -numa
 NAME = Funky Weasel is Jiggy wit it
 
 # *DOCUMENTATION*
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index 8c71daf..9fee37e 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -75,6 +75,7 @@
 	lock_kernel();
 	mm = current->mm;
 	mm->end_code = bss_start + bss_len;
+	mm->start_brk = bss_start + bss_len;
 	mm->brk = bss_start + bss_len;
 #if 0
 	printk("set_program_attributes(%lx %lx %lx %lx)\n",
diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
index c107cc0..7835779 100644
--- a/arch/alpha/kernel/pci.c
+++ b/arch/alpha/kernel/pci.c
@@ -71,25 +71,13 @@
 static void __init
 quirk_cypress(struct pci_dev *dev)
 {
-	/* The Notorious Cy82C693 chip.  */
-
-	/* The Cypress IDE controller doesn't support native mode, but it
-	   has programmable addresses of IDE command/control registers.
-	   This violates PCI specifications, confuses the IDE subsystem and
-	   causes resource conflicts between the primary HD_CMD register and
-	   the floppy controller.  Ugh.  Fix that.  */
-	if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE) {
-		dev->resource[0].flags = 0;
-		dev->resource[1].flags = 0;
-	}
-
 	/* The Cypress bridge responds on the PCI bus in the address range
 	   0xffff0000-0xffffffff (conventional x86 BIOS ROM).  There is no
 	   way to turn this off.  The bridge also supports several extended
 	   BIOS ranges (disabled after power-up), and some consoles do turn
 	   them on.  So if we use a large direct-map window, or a large SG
 	   window, we must avoid the entire 0xfff00000-0xffffffff region.  */
-	else if (dev->class >> 8 == PCI_CLASS_BRIDGE_ISA) {
+	if (dev->class >> 8 == PCI_CLASS_BRIDGE_ISA) {
 		if (__direct_map_base + __direct_map_size >= 0xfff00000UL)
 			__direct_map_size = 0xfff00000UL - __direct_map_base;
 		else {
@@ -391,7 +379,7 @@
 	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
 }
 
-static void __init
+void __init
 pcibios_claim_one_bus(struct pci_bus *b)
 {
 	struct pci_dev *dev;
@@ -405,7 +393,8 @@
 
 			if (r->parent || !r->start || !r->flags)
 				continue;
-			pci_claim_resource(dev, i);
+			if (pci_probe_only || (r->flags & IORESOURCE_PCI_FIXED))
+				pci_claim_resource(dev, i);
 		}
 	}
 
@@ -444,8 +433,7 @@
 		}
 	}
 
-	if (pci_probe_only)
-		pcibios_claim_console_setup();
+	pcibios_claim_console_setup();
 
 	pci_assign_unassigned_resources();
 	pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq);
diff --git a/arch/alpha/kernel/sys_nautilus.c b/arch/alpha/kernel/sys_nautilus.c
index 920196b..a7f23b5 100644
--- a/arch/alpha/kernel/sys_nautilus.c
+++ b/arch/alpha/kernel/sys_nautilus.c
@@ -187,6 +187,7 @@
 }
 
 extern void free_reserved_mem(void *, void *);
+extern void pcibios_claim_one_bus(struct pci_bus *);
 
 static struct resource irongate_mem = {
 	.name	= "Irongate PCI MEM",
@@ -205,6 +206,7 @@
 	/* Scan our single hose.  */
 	bus = pci_scan_bus(0, alpha_mv.pci_ops, hose);
 	hose->bus = bus;
+	pcibios_claim_one_bus(bus);
 
 	irongate = pci_get_bus_and_slot(0, 0);
 	bus->self = irongate;
diff --git a/arch/arm/mach-integrator/time.c b/arch/arm/mach-integrator/time.c
index 5235f64..8508a0d 100644
--- a/arch/arm/mach-integrator/time.c
+++ b/arch/arm/mach-integrator/time.c
@@ -124,8 +124,11 @@
 
 	xtime.tv_sec = __raw_readl(rtc_base + RTC_DR);
 
+	/* note that 'dev' is merely used for irq disambiguation;
+	 * it is not actually referenced in the irq handler
+	 */
 	ret = request_irq(dev->irq[0], arm_rtc_interrupt, IRQF_DISABLED,
-			  "rtc-pl030", NULL);
+			  "rtc-pl030", dev);
 	if (ret)
 		goto map_out;
 
diff --git a/arch/arm/mach-lh7a40x/arch-kev7a400.c b/arch/arm/mach-lh7a40x/arch-kev7a400.c
index 6d26661..2ef7d00 100644
--- a/arch/arm/mach-lh7a40x/arch-kev7a400.c
+++ b/arch/arm/mach-lh7a40x/arch-kev7a400.c
@@ -75,10 +75,9 @@
 {
 	u32 mask = CPLD_LATCHED_INTS;
 	irq = IRQ_KEV7A400_CPLD;
-	for (; mask; mask >>= 1, ++irq) {
+	for (; mask; mask >>= 1, ++irq)
 		if (mask & 1)
-			desc[irq].handle (irq, desc);
-	}
+			desc_handle_irq(irq, desc);
 }
 
 void __init lh7a40x_init_board_irq (void)
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 746cbb7..1b8229d 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -32,6 +32,7 @@
 	depends on !MMU
 	select CPU_32v4T
 	select CPU_ABRT_LV4T
+	select CPU_PABRT_NOIFAR
 	select CPU_CACHE_V4
 	help
 	  A 32-bit RISC microprocessor based on the ARM7 processor core
@@ -85,6 +86,7 @@
 	depends on !MMU
 	select CPU_32v4T
 	select CPU_ABRT_LV4T
+	select CPU_PABRT_NOIFAR
 	select CPU_CACHE_V3	# although the core is v4t
 	select CPU_CP15_MPU
 	help
@@ -101,6 +103,7 @@
 	depends on !MMU
 	select CPU_32v4T
 	select CPU_ABRT_NOMMU
+	select CPU_PABRT_NOIFAR
 	select CPU_CACHE_V4
 	help
 	  A 32-bit RISC microprocessor based on the ARM9 processor core
@@ -200,6 +203,7 @@
 	depends on !MMU
 	select CPU_32v4T
 	select CPU_ABRT_NOMMU
+	select CPU_PABRT_NOIFAR
 	select CPU_CACHE_VIVT
 	select CPU_CP15_MPU
 	help
@@ -217,6 +221,7 @@
 	depends on !MMU
 	select CPU_32v5
 	select CPU_ABRT_NOMMU
+	select CPU_PABRT_NOIFAR
 	select CPU_CACHE_VIVT
 	select CPU_CP15_MPU
 	help
@@ -351,6 +356,7 @@
 	default y
 	select CPU_32v5
 	select CPU_ABRT_EV5T
+	select CPU_PABRT_NOIFAR
 	select CPU_CACHE_VIVT
 	select CPU_CP15_MMU
 	select CPU_TLB_V4WBI if MMU
diff --git a/arch/arm/mm/proc-arm1020.S b/arch/arm/mm/proc-arm1020.S
index 32fd7ea..5673f4d 100644
--- a/arch/arm/mm/proc-arm1020.S
+++ b/arch/arm/mm/proc-arm1020.S
@@ -471,6 +471,7 @@
 	.type	arm1020_processor_functions, #object
 arm1020_processor_functions:
 	.word	v4t_early_abort
+	.word	pabort_noifar
 	.word	cpu_arm1020_proc_init
 	.word	cpu_arm1020_proc_fin
 	.word	cpu_arm1020_reset
@@ -478,7 +479,6 @@
 	.word	cpu_arm1020_dcache_clean_area
 	.word	cpu_arm1020_switch_mm
 	.word	cpu_arm1020_set_pte_ext
-	.word	pabort_noifar
 	.size	arm1020_processor_functions, . - arm1020_processor_functions
 
 	.section ".rodata"
diff --git a/arch/arm/mm/proc-arm1020e.S b/arch/arm/mm/proc-arm1020e.S
index fe2b0ae..4343fdb 100644
--- a/arch/arm/mm/proc-arm1020e.S
+++ b/arch/arm/mm/proc-arm1020e.S
@@ -452,6 +452,7 @@
 	.type	arm1020e_processor_functions, #object
 arm1020e_processor_functions:
 	.word	v4t_early_abort
+	.word	pabort_noifar
 	.word	cpu_arm1020e_proc_init
 	.word	cpu_arm1020e_proc_fin
 	.word	cpu_arm1020e_reset
@@ -459,7 +460,6 @@
 	.word	cpu_arm1020e_dcache_clean_area
 	.word	cpu_arm1020e_switch_mm
 	.word	cpu_arm1020e_set_pte_ext
-	.word	pabort_noifar
 	.size	arm1020e_processor_functions, . - arm1020e_processor_functions
 
 	.section ".rodata"
diff --git a/arch/arm/mm/proc-arm1022.S b/arch/arm/mm/proc-arm1022.S
index 06dde67..2a4ea16 100644
--- a/arch/arm/mm/proc-arm1022.S
+++ b/arch/arm/mm/proc-arm1022.S
@@ -435,6 +435,7 @@
 	.type	arm1022_processor_functions, #object
 arm1022_processor_functions:
 	.word	v4t_early_abort
+	.word	pabort_noifar
 	.word	cpu_arm1022_proc_init
 	.word	cpu_arm1022_proc_fin
 	.word	cpu_arm1022_reset
@@ -442,7 +443,6 @@
 	.word	cpu_arm1022_dcache_clean_area
 	.word	cpu_arm1022_switch_mm
 	.word	cpu_arm1022_set_pte_ext
-	.word	pabort_noifar
 	.size	arm1022_processor_functions, . - arm1022_processor_functions
 
 	.section ".rodata"
diff --git a/arch/arm/mm/proc-arm1026.S b/arch/arm/mm/proc-arm1026.S
index f5506e6..77a1bab 100644
--- a/arch/arm/mm/proc-arm1026.S
+++ b/arch/arm/mm/proc-arm1026.S
@@ -430,6 +430,7 @@
 	.type	arm1026_processor_functions, #object
 arm1026_processor_functions:
 	.word	v5t_early_abort
+	.word	pabort_noifar
 	.word	cpu_arm1026_proc_init
 	.word	cpu_arm1026_proc_fin
 	.word	cpu_arm1026_reset
@@ -437,7 +438,6 @@
 	.word	cpu_arm1026_dcache_clean_area
 	.word	cpu_arm1026_switch_mm
 	.word	cpu_arm1026_set_pte_ext
-	.word	pabort_noifar
 	.size	arm1026_processor_functions, . - arm1026_processor_functions
 
 	.section .rodata
diff --git a/arch/arm/mm/proc-arm6_7.S b/arch/arm/mm/proc-arm6_7.S
index 14b6a95..c371fc8 100644
--- a/arch/arm/mm/proc-arm6_7.S
+++ b/arch/arm/mm/proc-arm6_7.S
@@ -293,6 +293,7 @@
 		.type	arm6_processor_functions, #object
 ENTRY(arm6_processor_functions)
 		.word	cpu_arm6_data_abort
+		.word	pabort_noifar
 		.word	cpu_arm6_proc_init
 		.word	cpu_arm6_proc_fin
 		.word	cpu_arm6_reset
@@ -300,7 +301,6 @@
 		.word	cpu_arm6_dcache_clean_area
 		.word	cpu_arm6_switch_mm
 		.word	cpu_arm6_set_pte_ext
-		.word	pabort_noifar
 		.size	arm6_processor_functions, . - arm6_processor_functions
 
 /*
@@ -310,6 +310,7 @@
 		.type	arm7_processor_functions, #object
 ENTRY(arm7_processor_functions)
 		.word	cpu_arm7_data_abort
+		.word	pabort_noifar
 		.word	cpu_arm7_proc_init
 		.word	cpu_arm7_proc_fin
 		.word	cpu_arm7_reset
@@ -317,7 +318,6 @@
 		.word	cpu_arm7_dcache_clean_area
 		.word	cpu_arm7_switch_mm
 		.word	cpu_arm7_set_pte_ext
-		.word	pabort_noifar
 		.size	arm7_processor_functions, . - arm7_processor_functions
 
 		.section ".rodata"
diff --git a/arch/arm/mm/proc-arm720.S b/arch/arm/mm/proc-arm720.S
index ca5e7aa..d64f8e6 100644
--- a/arch/arm/mm/proc-arm720.S
+++ b/arch/arm/mm/proc-arm720.S
@@ -198,6 +198,7 @@
 		.type	arm720_processor_functions, #object
 ENTRY(arm720_processor_functions)
 		.word	v4t_late_abort
+		.word	pabort_noifar
 		.word	cpu_arm720_proc_init
 		.word	cpu_arm720_proc_fin
 		.word	cpu_arm720_reset
@@ -205,7 +206,6 @@
 		.word	cpu_arm720_dcache_clean_area
 		.word	cpu_arm720_switch_mm
 		.word	cpu_arm720_set_pte_ext
-		.word	pabort_noifar
 		.size	arm720_processor_functions, . - arm720_processor_functions
 
 		.section ".rodata"
diff --git a/arch/arm/mm/proc-arm740.S b/arch/arm/mm/proc-arm740.S
index 7069f49..3a57376 100644
--- a/arch/arm/mm/proc-arm740.S
+++ b/arch/arm/mm/proc-arm740.S
@@ -126,6 +126,7 @@
 	.type	arm740_processor_functions, #object
 ENTRY(arm740_processor_functions)
 	.word	v4t_late_abort
+	.word	pabort_noifar
 	.word	cpu_arm740_proc_init
 	.word	cpu_arm740_proc_fin
 	.word	cpu_arm740_reset
diff --git a/arch/arm/mm/proc-arm7tdmi.S b/arch/arm/mm/proc-arm7tdmi.S
index d091c25..7b3ecde 100644
--- a/arch/arm/mm/proc-arm7tdmi.S
+++ b/arch/arm/mm/proc-arm7tdmi.S
@@ -64,6 +64,7 @@
 		.type	arm7tdmi_processor_functions, #object
 ENTRY(arm7tdmi_processor_functions)
 		.word	v4t_late_abort
+		.word	pabort_noifar
 		.word	cpu_arm7tdmi_proc_init
 		.word	cpu_arm7tdmi_proc_fin
 		.word	cpu_arm7tdmi_reset
diff --git a/arch/arm/mm/proc-arm920.S b/arch/arm/mm/proc-arm920.S
index 0170d4f..28cdb06 100644
--- a/arch/arm/mm/proc-arm920.S
+++ b/arch/arm/mm/proc-arm920.S
@@ -417,6 +417,7 @@
 	.type	arm920_processor_functions, #object
 arm920_processor_functions:
 	.word	v4t_early_abort
+	.word	pabort_noifar
 	.word	cpu_arm920_proc_init
 	.word	cpu_arm920_proc_fin
 	.word	cpu_arm920_reset
@@ -424,7 +425,6 @@
 	.word	cpu_arm920_dcache_clean_area
 	.word	cpu_arm920_switch_mm
 	.word	cpu_arm920_set_pte_ext
-	.word	pabort_noifar
 	.size	arm920_processor_functions, . - arm920_processor_functions
 
 	.section ".rodata"
diff --git a/arch/arm/mm/proc-arm922.S b/arch/arm/mm/proc-arm922.S
index b795249..94ddcb4 100644
--- a/arch/arm/mm/proc-arm922.S
+++ b/arch/arm/mm/proc-arm922.S
@@ -421,6 +421,7 @@
 	.type	arm922_processor_functions, #object
 arm922_processor_functions:
 	.word	v4t_early_abort
+	.word	pabort_noifar
 	.word	cpu_arm922_proc_init
 	.word	cpu_arm922_proc_fin
 	.word	cpu_arm922_reset
@@ -428,7 +429,6 @@
 	.word	cpu_arm922_dcache_clean_area
 	.word	cpu_arm922_switch_mm
 	.word	cpu_arm922_set_pte_ext
-	.word	pabort_noifar
 	.size	arm922_processor_functions, . - arm922_processor_functions
 
 	.section ".rodata"
diff --git a/arch/arm/mm/proc-arm925.S b/arch/arm/mm/proc-arm925.S
index e2988eb..065087a 100644
--- a/arch/arm/mm/proc-arm925.S
+++ b/arch/arm/mm/proc-arm925.S
@@ -484,6 +484,7 @@
 	.type	arm925_processor_functions, #object
 arm925_processor_functions:
 	.word	v4t_early_abort
+	.word	pabort_noifar
 	.word	cpu_arm925_proc_init
 	.word	cpu_arm925_proc_fin
 	.word	cpu_arm925_reset
@@ -491,7 +492,6 @@
 	.word	cpu_arm925_dcache_clean_area
 	.word	cpu_arm925_switch_mm
 	.word	cpu_arm925_set_pte_ext
-	.word	pabort_noifar
 	.size	arm925_processor_functions, . - arm925_processor_functions
 
 	.section ".rodata"
diff --git a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S
index 62f7d1d..997db84 100644
--- a/arch/arm/mm/proc-arm926.S
+++ b/arch/arm/mm/proc-arm926.S
@@ -437,6 +437,7 @@
 	.type	arm926_processor_functions, #object
 arm926_processor_functions:
 	.word	v5tj_early_abort
+	.word	pabort_noifar
 	.word	cpu_arm926_proc_init
 	.word	cpu_arm926_proc_fin
 	.word	cpu_arm926_reset
@@ -444,7 +445,6 @@
 	.word	cpu_arm926_dcache_clean_area
 	.word	cpu_arm926_switch_mm
 	.word	cpu_arm926_set_pte_ext
-	.word	pabort_noifar
 	.size	arm926_processor_functions, . - arm926_processor_functions
 
 	.section ".rodata"
diff --git a/arch/arm/mm/proc-arm940.S b/arch/arm/mm/proc-arm940.S
index 786c593..44ead90 100644
--- a/arch/arm/mm/proc-arm940.S
+++ b/arch/arm/mm/proc-arm940.S
@@ -321,6 +321,7 @@
 	.type	arm940_processor_functions, #object
 ENTRY(arm940_processor_functions)
 	.word	nommu_early_abort
+	.word	pabort_noifar
 	.word	cpu_arm940_proc_init
 	.word	cpu_arm940_proc_fin
 	.word	cpu_arm940_reset
diff --git a/arch/arm/mm/proc-arm946.S b/arch/arm/mm/proc-arm946.S
index a60c142..2218b0c 100644
--- a/arch/arm/mm/proc-arm946.S
+++ b/arch/arm/mm/proc-arm946.S
@@ -376,6 +376,7 @@
 	.type	arm946_processor_functions, #object
 ENTRY(arm946_processor_functions)
 	.word	nommu_early_abort
+	.word	pabort_noifar
 	.word	cpu_arm946_proc_init
 	.word	cpu_arm946_proc_fin
 	.word	cpu_arm946_reset
diff --git a/arch/arm/mm/proc-arm9tdmi.S b/arch/arm/mm/proc-arm9tdmi.S
index 4848eea..c85c1f5 100644
--- a/arch/arm/mm/proc-arm9tdmi.S
+++ b/arch/arm/mm/proc-arm9tdmi.S
@@ -64,6 +64,7 @@
 		.type	arm9tdmi_processor_functions, #object
 ENTRY(arm9tdmi_processor_functions)
 		.word	nommu_early_abort
+		.word	pabort_noifar
 		.word	cpu_arm9tdmi_proc_init
 		.word	cpu_arm9tdmi_proc_fin
 		.word	cpu_arm9tdmi_reset
diff --git a/arch/arm/mm/proc-feroceon.S b/arch/arm/mm/proc-feroceon.S
index 2f169b2..90e7594 100644
--- a/arch/arm/mm/proc-feroceon.S
+++ b/arch/arm/mm/proc-feroceon.S
@@ -423,6 +423,7 @@
 	.type	feroceon_processor_functions, #object
 feroceon_processor_functions:
 	.word	v5t_early_abort
+	.word	pabort_noifar
 	.word	cpu_feroceon_proc_init
 	.word	cpu_feroceon_proc_fin
 	.word	cpu_feroceon_reset
@@ -430,7 +431,6 @@
 	.word	cpu_feroceon_dcache_clean_area
 	.word	cpu_feroceon_switch_mm
 	.word	cpu_feroceon_set_pte_ext
-	.word	pabort_noifar
 	.size	feroceon_processor_functions, . - feroceon_processor_functions
 
 	.section ".rodata"
diff --git a/arch/arm/mm/proc-sa110.S b/arch/arm/mm/proc-sa110.S
index 4db3d62..9818195 100644
--- a/arch/arm/mm/proc-sa110.S
+++ b/arch/arm/mm/proc-sa110.S
@@ -216,6 +216,7 @@
 	.type	sa110_processor_functions, #object
 ENTRY(sa110_processor_functions)
 	.word	v4_early_abort
+	.word	pabort_noifar
 	.word	cpu_sa110_proc_init
 	.word	cpu_sa110_proc_fin
 	.word	cpu_sa110_reset
@@ -223,7 +224,6 @@
 	.word	cpu_sa110_dcache_clean_area
 	.word	cpu_sa110_switch_mm
 	.word	cpu_sa110_set_pte_ext
-	.word	pabort_noifar
 	.size	sa110_processor_functions, . - sa110_processor_functions
 
 	.section ".rodata"
diff --git a/arch/arm/mm/proc-sa1100.S b/arch/arm/mm/proc-sa1100.S
index 3cdef04..c5fe27a 100644
--- a/arch/arm/mm/proc-sa1100.S
+++ b/arch/arm/mm/proc-sa1100.S
@@ -231,6 +231,7 @@
 	.type	sa1100_processor_functions, #object
 ENTRY(sa1100_processor_functions)
 	.word	v4_early_abort
+	.word	pabort_noifar
 	.word	cpu_sa1100_proc_init
 	.word	cpu_sa1100_proc_fin
 	.word	cpu_sa1100_reset
@@ -238,7 +239,6 @@
 	.word	cpu_sa1100_dcache_clean_area
 	.word	cpu_sa1100_switch_mm
 	.word	cpu_sa1100_set_pte_ext
-	.word	pabort_noifar
 	.size	sa1100_processor_functions, . - sa1100_processor_functions
 
 	.section ".rodata"
diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S
index bf760ea..5702ec5 100644
--- a/arch/arm/mm/proc-v6.S
+++ b/arch/arm/mm/proc-v6.S
@@ -219,6 +219,7 @@
 	.type	v6_processor_functions, #object
 ENTRY(v6_processor_functions)
 	.word	v6_early_abort
+	.word	pabort_noifar
 	.word	cpu_v6_proc_init
 	.word	cpu_v6_proc_fin
 	.word	cpu_v6_reset
@@ -226,7 +227,6 @@
 	.word	cpu_v6_dcache_clean_area
 	.word	cpu_v6_switch_mm
 	.word	cpu_v6_set_pte_ext
-	.word	pabort_noifar
 	.size	v6_processor_functions, . - v6_processor_functions
 
 	.type	cpu_arch_name, #object
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index a1d7331..b49f9a4 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -205,6 +205,7 @@
 	.type	v7_processor_functions, #object
 ENTRY(v7_processor_functions)
 	.word	v7_early_abort
+	.word	pabort_ifar
 	.word	cpu_v7_proc_init
 	.word	cpu_v7_proc_fin
 	.word	cpu_v7_reset
@@ -212,7 +213,6 @@
 	.word	cpu_v7_dcache_clean_area
 	.word	cpu_v7_switch_mm
 	.word	cpu_v7_set_pte_ext
-	.word	pabort_ifar
 	.size	v7_processor_functions, . - v7_processor_functions
 
 	.type	cpu_arch_name, #object
diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S
index d95921a..3533741 100644
--- a/arch/arm/mm/proc-xsc3.S
+++ b/arch/arm/mm/proc-xsc3.S
@@ -450,6 +450,7 @@
 	.type	xsc3_processor_functions, #object
 ENTRY(xsc3_processor_functions)
 	.word	v5t_early_abort
+	.word	pabort_noifar
 	.word	cpu_xsc3_proc_init
 	.word	cpu_xsc3_proc_fin
 	.word	cpu_xsc3_reset
diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S
index 1a6d898..2dd8527 100644
--- a/arch/arm/mm/proc-xscale.S
+++ b/arch/arm/mm/proc-xscale.S
@@ -527,6 +527,7 @@
 	.type	xscale_processor_functions, #object
 ENTRY(xscale_processor_functions)
 	.word	v5t_early_abort
+	.word	pabort_noifar
 	.word	cpu_xscale_proc_init
 	.word	cpu_xscale_proc_fin
 	.word	cpu_xscale_reset
@@ -534,7 +535,6 @@
 	.word	cpu_xscale_dcache_clean_area
 	.word	cpu_xscale_switch_mm
 	.word	cpu_xscale_set_pte_ext
-	.word	pabort_noifar
 	.size	xscale_processor_functions, . - xscale_processor_functions
 
 	.section ".rodata"
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
index 2dd1f30..795d0ac 100644
--- a/arch/blackfin/Kconfig
+++ b/arch/blackfin/Kconfig
@@ -47,10 +47,6 @@
 	bool
 	default y
 
-config GENERIC_TIME
-	bool
-	default n
-
 config GENERIC_GPIO
 	bool
 	default y
@@ -224,16 +220,6 @@
 	depends on (BF542 || BF544 || BF547 || BF548 || BF549)
 	default y
 
-config BFIN_DUAL_CORE
-	bool
-	depends on (BF561)
-	default y
-
-config BFIN_SINGLE_CORE
-	bool
-	depends on !BFIN_DUAL_CORE
-	default y
-
 config MEM_GENERIC_BOARD
 	bool
 	depends on GENERIC_BOARD
@@ -263,7 +249,7 @@
 
 config MEM_MT48LC32M16A2TG_75
 	bool
-	depends on (BFIN527_EZKIT)
+	depends on (BFIN527_EZKIT || BFIN532_IP0X)
 	default y
 
 source "arch/blackfin/mach-bf527/Kconfig"
@@ -286,17 +272,34 @@
 	  to the kernel, you may specify one here. As a minimum, you should specify
 	  the memory size and the root device (e.g., mem=8M, root=/dev/nfs).
 
+config BOOT_LOAD
+	hex "Kernel load address for booting"
+	default "0x1000"
+	range 0x1000 0x20000000
+	help
+	  This option allows you to set the load address of the kernel.
+	  This can be useful if you are on a board which has a small amount
+	  of memory or you wish to reserve some memory at the beginning of
+	  the address space.
+
+	  Note that you need to keep this value above 4k (0x1000) as this
+	  memory region is used to capture NULL pointer references as well
+	  as some core kernel functions.
+
 comment "Clock/PLL Setup"
 
 config CLKIN_HZ
-	int "Crystal Frequency in Hz"
+	int "Frequency of the crystal on the board in Hz"
 	default "11059200" if BFIN533_STAMP
 	default "27000000" if BFIN533_EZKIT
 	default "25000000" if (BFIN537_STAMP || BFIN527_EZKIT || H8606_HVSISTEMAS)
 	default "30000000" if BFIN561_EZKIT
 	default "24576000" if PNAV10
+	default "10000000" if BFIN532_IP0X
 	help
 	  The frequency of CLKIN crystal oscillator on the board in Hz.
+	  Warning: This value should match the crystal on the board. Otherwise,
+	  peripherals won't work properly.
 
 config BFIN_KERNEL_CLOCK
 	bool "Re-program Clocks while Kernel boots?"
@@ -307,6 +310,25 @@
 	  are also not changed, and the Bootloader does 100% of the hardware
 	  configuration.
 
+config MEM_SIZE
+	int "SDRAM Memory Size in MBytes"
+	depends on BFIN_KERNEL_CLOCK
+	default 64
+
+config MEM_ADD_WIDTH
+	int "Memory Address Width"
+	depends on BFIN_KERNEL_CLOCK
+	depends on (!BF54x)
+	range 8 11
+	default  9 if BFIN533_EZKIT
+	default  9 if BFIN561_EZKIT
+	default  9 if H8606_HVSISTEMAS
+	default 10 if BFIN527_EZKIT
+	default 10 if BFIN537_STAMP
+	default 11 if BFIN533_STAMP
+	default 10 if PNAV10
+	default 10 if BFIN532_IP0X
+
 config PLL_BYPASS
 	bool "Bypass PLL"
 	depends on BFIN_KERNEL_CLOCK
@@ -325,7 +347,7 @@
 	range 1 64
 	default "22" if BFIN533_EZKIT
 	default "45" if BFIN533_STAMP
-	default "20" if (BFIN537_STAMP || BFIN527_EZKIT || BFIN548_EZKIT)
+	default "20" if (BFIN537_STAMP || BFIN527_EZKIT || BFIN548_EZKIT || BFIN548_BLUETECHNIX_CM)
 	default "22" if BFIN533_BLUETECHNIX_CM
 	default "20" if BFIN537_BLUETECHNIX_CM
 	default "20" if BFIN561_BLUETECHNIX_CM
@@ -360,19 +382,33 @@
 	int "System Clock Divider"
 	depends on BFIN_KERNEL_CLOCK
 	range 1 15
-	default 5 if BFIN533_EZKIT
-	default 5 if BFIN533_STAMP
-	default 4 if (BFIN537_STAMP || BFIN527_EZKIT || BFIN548_EZKIT)
-	default 5 if BFIN533_BLUETECHNIX_CM
-	default 4 if BFIN537_BLUETECHNIX_CM
-	default 4 if BFIN561_BLUETECHNIX_CM
-	default 5 if BFIN561_EZKIT
-	default 3 if H8606_HVSISTEMAS
+	default 5
 	help
 	  This sets the frequency of the system clock (including SDRAM or DDR).
 	  This can be between 1 and 15
 	  System Clock = (PLL frequency) / (this setting)
 
+config MAX_MEM_SIZE
+	int "Max SDRAM Memory Size in MBytes"
+	depends on !BFIN_KERNEL_CLOCK && !MPU
+	default 512
+	help
+	  This is the max memory size that the kernel will create CPLB
+	  tables for.  Your system will not be able to handle any more.
+
+choice
+	prompt "DDR SDRAM Chip Type"
+	depends on BFIN_KERNEL_CLOCK
+	depends on BF54x
+	default MEM_MT46V32M16_5B
+
+config MEM_MT46V32M16_6T
+	bool "MT46V32M16_6T"
+
+config MEM_MT46V32M16_5B
+	bool "MT46V32M16_5B"
+endchoice
+
 #
 # Max & Min Speeds for various Chips
 #
@@ -415,42 +451,33 @@
 
 source kernel/Kconfig.hz
 
+config GENERIC_TIME
+	bool "Generic time"
+	default y
+
+config GENERIC_CLOCKEVENTS
+	bool "Generic clock events"
+	depends on GENERIC_TIME
+	default y
+
+config CYCLES_CLOCKSOURCE
+	bool "Use 'CYCLES' as a clocksource (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	depends on GENERIC_CLOCKEVENTS
+	depends on !BFIN_SCRATCH_REG_CYCLES
+	default n
+	help
+	  If you say Y here, you will enable support for using the 'cycles'
+	  registers as a clock source.  Doing so means you will be unable to
+	  safely write to the 'cycles' register during runtime.  You will
+	  still be able to read it (such as for performance monitoring), but
+	  writing the registers will most likely crash the kernel.
+
+source kernel/time/Kconfig
+
 comment "Memory Setup"
 
-config MEM_SIZE
-	int "SDRAM Memory Size in MBytes"
-	default  32 if BFIN533_EZKIT
-	default  64 if BFIN527_EZKIT
-	default  64 if BFIN537_STAMP
-	default  64 if BFIN548_EZKIT
-	default  64 if BFIN561_EZKIT
-	default 128 if BFIN533_STAMP
-	default  64 if PNAV10
-	default  32 if H8606_HVSISTEMAS
-
-config MEM_ADD_WIDTH
-	int "SDRAM Memory Address Width"
-	depends on (!BF54x)
-	default  9 if BFIN533_EZKIT
-	default  9 if BFIN561_EZKIT
-	default  9 if H8606_HVSISTEMAS
-	default 10 if BFIN527_EZKIT
-	default 10 if BFIN537_STAMP
-	default 11 if BFIN533_STAMP
-	default 10 if PNAV10
-
-
-choice
-	prompt "DDR SDRAM Chip Type"
-	depends on BFIN548_EZKIT
-	default MEM_MT46V32M16_5B
-
-config MEM_MT46V32M16_6T
-        bool "MT46V32M16_6T"
-
-config MEM_MT46V32M16_5B
-        bool "MT46V32M16_5B"
-endchoice
+comment "Misc"
 
 config ENET_FLASH_PIN
 	int "PF port/pin used for flash and ethernet sharing"
@@ -462,20 +489,6 @@
 	  code.
 	  For example: PF0 --> 0,PF1 --> 1,PF2 --> 2, etc.
 
-config BOOT_LOAD
-	hex "Kernel load address for booting"
-	default "0x1000"
-	range 0x1000 0x20000000
-	help
-	  This option allows you to set the load address of the kernel.
-	  This can be useful if you are on a board which has a small amount
-	  of memory or you wish to reserve some memory at the beginning of
-	  the address space.
-
-	  Note that you need to keep this value above 4k (0x1000) as this
-	  memory region is used to capture NULL pointer references as well
-	  as some core kernel functions.
-
 choice
 	prompt "Blackfin Exception Scratch Register"
 	default BFIN_SCRATCH_REG_RETN
@@ -661,14 +674,6 @@
 
 source "mm/Kconfig"
 
-config LARGE_ALLOCS
-	bool "Allow allocating large blocks (> 1MB) of memory"
-	help
-	  Allow the slab memory allocator to keep chains for very large
-	  memory sizes - upto 32MB. You may need this if your system has
-	  a lot of RAM, and you need to able to allocate very large
-	  contiguous chunks. If unsure, say N.
-
 config BFIN_GPTIMERS
 	tristate "Enable Blackfin General Purpose Timers API"
 	default n
diff --git a/arch/blackfin/Makefile b/arch/blackfin/Makefile
index 75eba2c..3cbe16c 100644
--- a/arch/blackfin/Makefile
+++ b/arch/blackfin/Makefile
@@ -72,6 +72,11 @@
 KBUILD_CFLAGS += -mcpu=$(cpu-y)-$(rev-y)
 KBUILD_AFLAGS += -mcpu=$(cpu-y)-$(rev-y)
 
+# - we utilize the silicon rev from the toolchain, so move it over to the checkflags
+# - the l1_text attribute is Blackfin specific, so fake it out as used to kill warnings
+CHECKFLAGS_SILICON = $(shell echo "" | $(CPP) $(KBUILD_CFLAGS) -dD - 2>/dev/null | awk '$$2 == "__SILICON_REVISION__" { print $$3 }')
+CHECKFLAGS += -D__SILICON_REVISION__=$(CHECKFLAGS_SILICON) -Dl1_text=__used__
+
 head-y   := arch/$(ARCH)/mach-$(MACHINE)/head.o arch/$(ARCH)/kernel/init_task.o
 
 core-y   += arch/$(ARCH)/kernel/ arch/$(ARCH)/mm/ arch/$(ARCH)/mach-common/
diff --git a/arch/blackfin/boot/.gitignore b/arch/blackfin/boot/.gitignore
new file mode 100644
index 0000000..3ae0399
--- /dev/null
+++ b/arch/blackfin/boot/.gitignore
@@ -0,0 +1 @@
++vmImage
diff --git a/arch/blackfin/configs/BF527-EZKIT_defconfig b/arch/blackfin/configs/BF527-EZKIT_defconfig
index ae320dc..64876df 100644
--- a/arch/blackfin/configs/BF527-EZKIT_defconfig
+++ b/arch/blackfin/configs/BF527-EZKIT_defconfig
@@ -13,7 +13,7 @@
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
-# CONFIG_GENERIC_TIME is not set
+CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_GPIO=y
 CONFIG_FORCE_MAX_ZONEORDER=14
 CONFIG_GENERIC_CALIBRATE_DELAY=y
@@ -250,7 +250,7 @@
 #
 # Memory Setup
 #
-CONFIG_MEM_SIZE=64
+CONFIG_MAX_MEM_SIZE=512
 CONFIG_MEM_ADD_WIDTH=10
 CONFIG_BOOT_LOAD=0x1000
 CONFIG_BFIN_SCRATCH_REG_RETN=y
@@ -720,8 +720,8 @@
 #
 CONFIG_SERIAL_BFIN=y
 CONFIG_SERIAL_BFIN_CONSOLE=y
-# CONFIG_SERIAL_BFIN_DMA is not set
-CONFIG_SERIAL_BFIN_PIO=y
+CONFIG_SERIAL_BFIN_DMA=y
+# CONFIG_SERIAL_BFIN_PIO is not set
 # CONFIG_SERIAL_BFIN_UART0 is not set
 CONFIG_SERIAL_BFIN_UART1=y
 # CONFIG_BFIN_UART1_CTSRTS is not set
diff --git a/arch/blackfin/configs/BF533-EZKIT_defconfig b/arch/blackfin/configs/BF533-EZKIT_defconfig
index 9621caa..8d817ba 100644
--- a/arch/blackfin/configs/BF533-EZKIT_defconfig
+++ b/arch/blackfin/configs/BF533-EZKIT_defconfig
@@ -13,7 +13,7 @@
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
-# CONFIG_GENERIC_TIME is not set
+CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_GPIO=y
 CONFIG_FORCE_MAX_ZONEORDER=14
 CONFIG_GENERIC_CALIBRATE_DELAY=y
@@ -212,7 +212,7 @@
 #
 # Memory Setup
 #
-CONFIG_MEM_SIZE=32
+CONFIG_MAX_MEM_SIZE=512
 CONFIG_MEM_ADD_WIDTH=9
 CONFIG_BOOT_LOAD=0x1000
 CONFIG_BFIN_SCRATCH_REG_RETN=y
diff --git a/arch/blackfin/configs/BF533-STAMP_defconfig b/arch/blackfin/configs/BF533-STAMP_defconfig
index b51e76c..20d598d 100644
--- a/arch/blackfin/configs/BF533-STAMP_defconfig
+++ b/arch/blackfin/configs/BF533-STAMP_defconfig
@@ -13,7 +13,7 @@
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
-# CONFIG_GENERIC_TIME is not set
+CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_GPIO=y
 CONFIG_FORCE_MAX_ZONEORDER=14
 CONFIG_GENERIC_CALIBRATE_DELAY=y
@@ -212,7 +212,7 @@
 #
 # Memory Setup
 #
-CONFIG_MEM_SIZE=128
+CONFIG_MAX_MEM_SIZE=512
 CONFIG_MEM_ADD_WIDTH=11
 CONFIG_ENET_FLASH_PIN=0
 CONFIG_BOOT_LOAD=0x1000
diff --git a/arch/blackfin/configs/BF537-STAMP_defconfig b/arch/blackfin/configs/BF537-STAMP_defconfig
index d45fa53..b5189c8 100644
--- a/arch/blackfin/configs/BF537-STAMP_defconfig
+++ b/arch/blackfin/configs/BF537-STAMP_defconfig
@@ -13,7 +13,7 @@
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
-# CONFIG_GENERIC_TIME is not set
+CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_GPIO=y
 CONFIG_FORCE_MAX_ZONEORDER=14
 CONFIG_GENERIC_CALIBRATE_DELAY=y
@@ -220,7 +220,7 @@
 #
 # Memory Setup
 #
-CONFIG_MEM_SIZE=64
+CONFIG_MAX_MEM_SIZE=512
 CONFIG_MEM_ADD_WIDTH=10
 CONFIG_BOOT_LOAD=0x1000
 CONFIG_BFIN_SCRATCH_REG_RETN=y
diff --git a/arch/blackfin/configs/BF548-EZKIT_defconfig b/arch/blackfin/configs/BF548-EZKIT_defconfig
index c9707f7..5bfdfb2 100644
--- a/arch/blackfin/configs/BF548-EZKIT_defconfig
+++ b/arch/blackfin/configs/BF548-EZKIT_defconfig
@@ -13,7 +13,7 @@
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
-# CONFIG_GENERIC_TIME is not set
+CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_GPIO=y
 CONFIG_FORCE_MAX_ZONEORDER=14
 CONFIG_GENERIC_CALIBRATE_DELAY=y
@@ -285,7 +285,7 @@
 #
 # Memory Setup
 #
-CONFIG_MEM_SIZE=64
+CONFIG_MAX_MEM_SIZE=512
 # CONFIG_MEM_MT46V32M16_6T is not set
 CONFIG_MEM_MT46V32M16_5B=y
 CONFIG_BOOT_LOAD=0x1000
@@ -813,8 +813,8 @@
 #
 CONFIG_SERIAL_BFIN=y
 CONFIG_SERIAL_BFIN_CONSOLE=y
-# CONFIG_SERIAL_BFIN_DMA is not set
-CONFIG_SERIAL_BFIN_PIO=y
+CONFIG_SERIAL_BFIN_DMA=y
+# CONFIG_SERIAL_BFIN_PIO is not set
 # CONFIG_SERIAL_BFIN_UART0 is not set
 CONFIG_SERIAL_BFIN_UART1=y
 # CONFIG_BFIN_UART1_CTSRTS is not set
diff --git a/arch/blackfin/configs/BF561-EZKIT_defconfig b/arch/blackfin/configs/BF561-EZKIT_defconfig
index 4d8a633..b4a20c8 100644
--- a/arch/blackfin/configs/BF561-EZKIT_defconfig
+++ b/arch/blackfin/configs/BF561-EZKIT_defconfig
@@ -13,7 +13,7 @@
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
-# CONFIG_GENERIC_TIME is not set
+CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_GPIO=y
 CONFIG_FORCE_MAX_ZONEORDER=14
 CONFIG_GENERIC_CALIBRATE_DELAY=y
@@ -256,7 +256,7 @@
 #
 # Memory Setup
 #
-CONFIG_MEM_SIZE=64
+CONFIG_MAX_MEM_SIZE=512
 CONFIG_MEM_ADD_WIDTH=9
 CONFIG_BOOT_LOAD=0x1000
 CONFIG_BFIN_SCRATCH_REG_RETN=y
diff --git a/arch/blackfin/configs/CM-BF533_defconfig b/arch/blackfin/configs/CM-BF533_defconfig
new file mode 100644
index 0000000..560890f
--- /dev/null
+++ b/arch/blackfin/configs/CM-BF533_defconfig
@@ -0,0 +1,912 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.22.16
+#
+# CONFIG_MMU is not set
+# CONFIG_FPU is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_BLACKFIN=y
+CONFIG_ZONE_DMA=y
+CONFIG_SEMAPHORE_SLEEPERS=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_FORCE_MAX_ZONEORDER=14
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+# CONFIG_UID16 is not set
+CONFIG_SYSCTL_SYSCALL=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_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_BIG_ORDER_ALLOC_NOFAIL_MAGIC=3
+# CONFIG_NP2 is not set
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF 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 is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Blackfin Processor Options
+#
+
+#
+# Processor and Board Settings
+#
+# CONFIG_BF522 is not set
+# CONFIG_BF523 is not set
+# CONFIG_BF524 is not set
+# CONFIG_BF525 is not set
+# CONFIG_BF526 is not set
+# CONFIG_BF527 is not set
+# CONFIG_BF531 is not set
+# CONFIG_BF532 is not set
+CONFIG_BF533=y
+# CONFIG_BF534 is not set
+# CONFIG_BF536 is not set
+# CONFIG_BF537 is not set
+# CONFIG_BF542 is not set
+# CONFIG_BF544 is not set
+# CONFIG_BF547 is not set
+# CONFIG_BF548 is not set
+# CONFIG_BF549 is not set
+# CONFIG_BF561 is not set
+# CONFIG_BF_REV_0_0 is not set
+# CONFIG_BF_REV_0_1 is not set
+# CONFIG_BF_REV_0_2 is not set
+CONFIG_BF_REV_0_3=y
+# CONFIG_BF_REV_0_4 is not set
+# CONFIG_BF_REV_0_5 is not set
+# CONFIG_BF_REV_ANY is not set
+# CONFIG_BF_REV_NONE is not set
+CONFIG_BF53x=y
+CONFIG_BFIN_SINGLE_CORE=y
+CONFIG_MEM_MT48LC16M16A2TG_75=y
+# CONFIG_BFIN533_EZKIT is not set
+# CONFIG_BFIN533_STAMP is not set
+CONFIG_BFIN533_BLUETECHNIX_CM=y
+# CONFIG_H8606_HVSISTEMAS is not set
+# CONFIG_GENERIC_BF533_BOARD is not set
+
+#
+# BF533/2/1 Specific Configuration
+#
+
+#
+# Interrupt Priority Assignment
+#
+
+#
+# Priority
+#
+CONFIG_UART_ERROR=7
+CONFIG_SPORT0_ERROR=7
+CONFIG_SPI_ERROR=7
+CONFIG_SPORT1_ERROR=7
+CONFIG_PPI_ERROR=7
+CONFIG_DMA_ERROR=7
+CONFIG_PLLWAKE_ERROR=7
+CONFIG_RTC_ERROR=8
+CONFIG_DMA0_PPI=8
+CONFIG_DMA1_SPORT0RX=9
+CONFIG_DMA2_SPORT0TX=9
+CONFIG_DMA3_SPORT1RX=9
+CONFIG_DMA4_SPORT1TX=9
+CONFIG_DMA5_SPI=10
+CONFIG_DMA6_UARTRX=10
+CONFIG_DMA7_UARTTX=10
+CONFIG_TIMER0=11
+CONFIG_TIMER1=11
+CONFIG_TIMER2=11
+CONFIG_PFA=12
+CONFIG_PFB=12
+CONFIG_MEMDMA0=13
+CONFIG_MEMDMA1=13
+CONFIG_WDTIMER=13
+
+#
+# Board customizations
+#
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Clock/PLL Setup
+#
+CONFIG_CLKIN_HZ=25000000
+# CONFIG_BFIN_KERNEL_CLOCK is not set
+CONFIG_MAX_VCO_HZ=750000000
+CONFIG_MIN_VCO_HZ=50000000
+CONFIG_MAX_SCLK_HZ=133333333
+CONFIG_MIN_SCLK_HZ=27000000
+
+#
+# Kernel Timer/Scheduler
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+
+#
+# Memory Setup
+#
+CONFIG_MAX_MEM_SIZE=32
+CONFIG_MEM_ADD_WIDTH=9
+CONFIG_BOOT_LOAD=0x1000
+CONFIG_BFIN_SCRATCH_REG_RETN=y
+# CONFIG_BFIN_SCRATCH_REG_RETE is not set
+# CONFIG_BFIN_SCRATCH_REG_CYCLES is not set
+
+#
+# Blackfin Kernel Optimizations
+#
+
+#
+# Memory Optimizations
+#
+CONFIG_I_ENTRY_L1=y
+CONFIG_EXCPT_IRQ_SYSC_L1=y
+CONFIG_DO_IRQ_L1=y
+CONFIG_CORE_TIMER_IRQ_L1=y
+CONFIG_IDLE_L1=y
+CONFIG_SCHEDULE_L1=y
+CONFIG_ARITHMETIC_OPS_L1=y
+CONFIG_ACCESS_OK_L1=y
+CONFIG_MEMSET_L1=y
+CONFIG_MEMCPY_L1=y
+CONFIG_SYS_BFIN_SPINLOCK_L1=y
+CONFIG_IP_CHECKSUM_L1=y
+CONFIG_CACHELINE_ALIGNED_L1=y
+CONFIG_SYSCALL_TAB_L1=y
+CONFIG_CPLB_SWITCH_TAB_L1=y
+CONFIG_RAMKERNEL=y
+# CONFIG_ROMKERNEL is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_LARGE_ALLOCS=y
+# CONFIG_BFIN_GPTIMERS is not set
+CONFIG_BFIN_DMA_5XX=y
+# CONFIG_DMA_UNCACHED_2M is not set
+CONFIG_DMA_UNCACHED_1M=y
+# CONFIG_DMA_UNCACHED_NONE is not set
+
+#
+# Cache Support
+#
+CONFIG_BFIN_ICACHE=y
+CONFIG_BFIN_DCACHE=y
+# CONFIG_BFIN_DCACHE_BANKA is not set
+# CONFIG_BFIN_ICACHE_LOCK is not set
+CONFIG_BFIN_WB=y
+# CONFIG_BFIN_WT is not set
+CONFIG_L1_MAX_PIECE=16
+# CONFIG_MPU is not set
+
+#
+# Asynchonous Memory Configuration
+#
+
+#
+# EBIU_AMGCTL Global Control
+#
+CONFIG_C_AMCKEN=y
+CONFIG_C_CDPRIO=y
+# CONFIG_C_AMBEN is not set
+# CONFIG_C_AMBEN_B0 is not set
+# CONFIG_C_AMBEN_B0_B1 is not set
+# CONFIG_C_AMBEN_B0_B1_B2 is not set
+CONFIG_C_AMBEN_ALL=y
+
+#
+# EBIU_AMBCTL Control
+#
+CONFIG_BANK_0=0x7BB0
+CONFIG_BANK_1=0x7BB0
+CONFIG_BANK_2=0x7BB0
+CONFIG_BANK_3=0xFFC3
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_PCI is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF_FDPIC=y
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_ZFLAT=y
+CONFIG_BINFMT_SHARED_FLAT=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+# CONFIG_PM_WAKEUP_BY_GPIO is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# 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=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETLABEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# 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_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_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_RAM=y
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_UCLINUX=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNPACPI is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_SMC91X=y
+# CONFIG_SMSC911X is not set
+# CONFIG_DM9000 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_AX88180 is not set
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_AD9960 is not set
+# CONFIG_SPI_ADC_BF533 is not set
+# CONFIG_BF5xx_PFLAGS is not set
+# CONFIG_BF5xx_PPIFCD is not set
+# CONFIG_BFIN_SIMPLE_TIMER is not set
+# CONFIG_BF5xx_PPI is not set
+CONFIG_BFIN_SPORT=y
+# CONFIG_BFIN_TIMER_LATENCY is not set
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_BFIN=y
+CONFIG_SERIAL_BFIN_CONSOLE=y
+CONFIG_SERIAL_BFIN_DMA=y
+# CONFIG_SERIAL_BFIN_PIO is not set
+CONFIG_SERIAL_BFIN_UART0=y
+# CONFIG_BFIN_UART0_CTSRTS is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_BFIN_SPORT is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# CAN, the car bus and industrial fieldbus
+#
+# CONFIG_CAN4LINUX is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# 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
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+
+#
+# Enable Host or Gadget support to see Inventra options
+#
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# PBX support
+#
+# CONFIG_PBX is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_FS_MBCACHE=y
+# 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_GFS2_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
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# 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_SYSCTL=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_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_YAFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# 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 is not set
+# CONFIG_NFSD 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
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_MMRS is not set
+CONFIG_DEBUG_HUNT_FOR_ZERO=y
+CONFIG_DEBUG_BFIN_HWTRACE_ON=y
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
+# CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
+# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+# CONFIG_EARLY_PRINTK is not set
+CONFIG_CPLB_INFO=y
+CONFIG_ACCESS_CHECK=y
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+CONFIG_SECURITY=y
+# CONFIG_SECURITY_NETWORK is not set
+CONFIG_SECURITY_CAPABILITIES=y
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/blackfin/configs/CM-BF537E_defconfig b/arch/blackfin/configs/CM-BF537E_defconfig
new file mode 100644
index 0000000..9f66d2d
--- /dev/null
+++ b/arch/blackfin/configs/CM-BF537E_defconfig
@@ -0,0 +1,940 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.22.16
+#
+# CONFIG_MMU is not set
+# CONFIG_FPU is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_BLACKFIN=y
+CONFIG_ZONE_DMA=y
+CONFIG_SEMAPHORE_SLEEPERS=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_FORCE_MAX_ZONEORDER=14
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+# CONFIG_UID16 is not set
+CONFIG_SYSCTL_SYSCALL=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_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_BIG_ORDER_ALLOC_NOFAIL_MAGIC=3
+# CONFIG_NP2 is not set
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF 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 is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Blackfin Processor Options
+#
+
+#
+# Processor and Board Settings
+#
+# CONFIG_BF522 is not set
+# CONFIG_BF523 is not set
+# CONFIG_BF524 is not set
+# CONFIG_BF525 is not set
+# CONFIG_BF526 is not set
+# CONFIG_BF527 is not set
+# CONFIG_BF531 is not set
+# CONFIG_BF532 is not set
+# CONFIG_BF533 is not set
+# CONFIG_BF534 is not set
+# CONFIG_BF536 is not set
+CONFIG_BF537=y
+# CONFIG_BF542 is not set
+# CONFIG_BF544 is not set
+# CONFIG_BF547 is not set
+# CONFIG_BF548 is not set
+# CONFIG_BF549 is not set
+# CONFIG_BF561 is not set
+# CONFIG_BF_REV_0_0 is not set
+# CONFIG_BF_REV_0_1 is not set
+CONFIG_BF_REV_0_2=y
+# CONFIG_BF_REV_0_3 is not set
+# CONFIG_BF_REV_0_4 is not set
+# CONFIG_BF_REV_0_5 is not set
+# CONFIG_BF_REV_ANY is not set
+# CONFIG_BF_REV_NONE is not set
+CONFIG_BF53x=y
+CONFIG_BFIN_SINGLE_CORE=y
+CONFIG_MEM_MT48LC16M16A2TG_75=y
+CONFIG_IRQ_PLL_WAKEUP=7
+CONFIG_IRQ_RTC=8
+CONFIG_IRQ_PPI=8
+CONFIG_IRQ_SPORT0_RX=9
+CONFIG_IRQ_SPORT0_TX=9
+CONFIG_IRQ_SPORT1_RX=9
+CONFIG_IRQ_SPORT1_TX=9
+CONFIG_IRQ_TWI=10
+CONFIG_IRQ_SPI=10
+CONFIG_IRQ_UART0_RX=10
+CONFIG_IRQ_UART0_TX=10
+CONFIG_IRQ_UART1_RX=10
+CONFIG_IRQ_UART1_TX=10
+CONFIG_IRQ_MAC_RX=11
+CONFIG_IRQ_MAC_TX=11
+CONFIG_IRQ_TMR0=12
+CONFIG_IRQ_TMR1=12
+CONFIG_IRQ_TMR2=12
+CONFIG_IRQ_TMR3=12
+CONFIG_IRQ_TMR4=12
+CONFIG_IRQ_TMR5=12
+CONFIG_IRQ_TMR6=12
+CONFIG_IRQ_TMR7=12
+CONFIG_IRQ_PORTG_INTB=12
+CONFIG_IRQ_MEM_DMA0=13
+CONFIG_IRQ_MEM_DMA1=13
+CONFIG_IRQ_WATCH=13
+# CONFIG_BFIN537_STAMP is not set
+CONFIG_BFIN537_BLUETECHNIX_CM=y
+# CONFIG_PNAV10 is not set
+# CONFIG_CAMSIG_MINOTAUR is not set
+# CONFIG_GENERIC_BF537_BOARD is not set
+
+#
+# BF537 Specific Configuration
+#
+
+#
+# Interrupt Priority Assignment
+#
+
+#
+# Priority
+#
+CONFIG_IRQ_DMA_ERROR=7
+CONFIG_IRQ_ERROR=7
+CONFIG_IRQ_CAN_RX=11
+CONFIG_IRQ_CAN_TX=11
+CONFIG_IRQ_PROG_INTA=12
+
+#
+# Board customizations
+#
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Clock/PLL Setup
+#
+CONFIG_CLKIN_HZ=25000000
+# CONFIG_BFIN_KERNEL_CLOCK is not set
+CONFIG_MAX_VCO_HZ=600000000
+CONFIG_MIN_VCO_HZ=50000000
+CONFIG_MAX_SCLK_HZ=133333333
+CONFIG_MIN_SCLK_HZ=27000000
+
+#
+# Kernel Timer/Scheduler
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+
+#
+# Memory Setup
+#
+CONFIG_MAX_MEM_SIZE=32
+CONFIG_MEM_ADD_WIDTH=9
+CONFIG_BOOT_LOAD=0x1000
+CONFIG_BFIN_SCRATCH_REG_RETN=y
+# CONFIG_BFIN_SCRATCH_REG_RETE is not set
+# CONFIG_BFIN_SCRATCH_REG_CYCLES is not set
+
+#
+# Blackfin Kernel Optimizations
+#
+
+#
+# Memory Optimizations
+#
+CONFIG_I_ENTRY_L1=y
+CONFIG_EXCPT_IRQ_SYSC_L1=y
+CONFIG_DO_IRQ_L1=y
+CONFIG_CORE_TIMER_IRQ_L1=y
+CONFIG_IDLE_L1=y
+CONFIG_SCHEDULE_L1=y
+CONFIG_ARITHMETIC_OPS_L1=y
+CONFIG_ACCESS_OK_L1=y
+CONFIG_MEMSET_L1=y
+CONFIG_MEMCPY_L1=y
+CONFIG_SYS_BFIN_SPINLOCK_L1=y
+CONFIG_IP_CHECKSUM_L1=y
+CONFIG_CACHELINE_ALIGNED_L1=y
+CONFIG_SYSCALL_TAB_L1=y
+CONFIG_CPLB_SWITCH_TAB_L1=y
+CONFIG_RAMKERNEL=y
+# CONFIG_ROMKERNEL is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_LARGE_ALLOCS=y
+# CONFIG_BFIN_GPTIMERS is not set
+CONFIG_BFIN_DMA_5XX=y
+# CONFIG_DMA_UNCACHED_2M is not set
+CONFIG_DMA_UNCACHED_1M=y
+# CONFIG_DMA_UNCACHED_NONE is not set
+
+#
+# Cache Support
+#
+CONFIG_BFIN_ICACHE=y
+CONFIG_BFIN_DCACHE=y
+# CONFIG_BFIN_DCACHE_BANKA is not set
+# CONFIG_BFIN_ICACHE_LOCK is not set
+CONFIG_BFIN_WB=y
+# CONFIG_BFIN_WT is not set
+CONFIG_L1_MAX_PIECE=16
+# CONFIG_MPU is not set
+
+#
+# Asynchonous Memory Configuration
+#
+
+#
+# EBIU_AMGCTL Global Control
+#
+CONFIG_C_AMCKEN=y
+CONFIG_C_CDPRIO=y
+# CONFIG_C_AMBEN is not set
+# CONFIG_C_AMBEN_B0 is not set
+# CONFIG_C_AMBEN_B0_B1 is not set
+# CONFIG_C_AMBEN_B0_B1_B2 is not set
+CONFIG_C_AMBEN_ALL=y
+
+#
+# EBIU_AMBCTL Control
+#
+CONFIG_BANK_0=0x7BB0
+CONFIG_BANK_1=0x7BB0
+CONFIG_BANK_2=0x7BB0
+CONFIG_BANK_3=0xFFC3
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_PCI is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF_FDPIC=y
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_ZFLAT=y
+CONFIG_BINFMT_SHARED_FLAT=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+# CONFIG_PM_WAKEUP_BY_GPIO is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# 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=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETLABEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# 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_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_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_RAM=y
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_UCLINUX=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNPACPI is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_FIXED_PHY is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_SMC91X is not set
+CONFIG_BFIN_MAC=y
+CONFIG_BFIN_MAC_USE_L1=y
+CONFIG_BFIN_TX_DESC_NUM=10
+CONFIG_BFIN_RX_DESC_NUM=20
+# CONFIG_BFIN_MAC_RMII is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DM9000 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_AX88180 is not set
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_AD9960 is not set
+# CONFIG_SPI_ADC_BF533 is not set
+# CONFIG_BF5xx_PFLAGS is not set
+# CONFIG_BF5xx_PPIFCD is not set
+# CONFIG_BFIN_SIMPLE_TIMER is not set
+# CONFIG_BF5xx_PPI is not set
+CONFIG_BFIN_SPORT=y
+# CONFIG_BFIN_TIMER_LATENCY is not set
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_BFIN=y
+CONFIG_SERIAL_BFIN_CONSOLE=y
+CONFIG_SERIAL_BFIN_DMA=y
+# CONFIG_SERIAL_BFIN_PIO is not set
+CONFIG_SERIAL_BFIN_UART0=y
+# CONFIG_BFIN_UART0_CTSRTS is not set
+CONFIG_SERIAL_BFIN_UART1=y
+# CONFIG_BFIN_UART1_CTSRTS is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_BFIN_SPORT is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# CAN, the car bus and industrial fieldbus
+#
+# CONFIG_CAN4LINUX is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# 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
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+
+#
+# Enable Host or Gadget support to see Inventra options
+#
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# PBX support
+#
+# CONFIG_PBX is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_FS_MBCACHE=y
+# 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_GFS2_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
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# 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_SYSCTL=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_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_YAFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# 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 is not set
+# CONFIG_NFSD 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
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_MMRS is not set
+# CONFIG_DEBUG_HUNT_FOR_ZERO is not set
+CONFIG_DEBUG_BFIN_HWTRACE_ON=y
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
+# CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
+# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+# CONFIG_EARLY_PRINTK is not set
+CONFIG_CPLB_INFO=y
+CONFIG_ACCESS_CHECK=y
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+CONFIG_SECURITY=y
+# CONFIG_SECURITY_NETWORK is not set
+CONFIG_SECURITY_CAPABILITIES=y
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/blackfin/configs/CM-BF537U_defconfig b/arch/blackfin/configs/CM-BF537U_defconfig
new file mode 100644
index 0000000..2694d06
--- /dev/null
+++ b/arch/blackfin/configs/CM-BF537U_defconfig
@@ -0,0 +1,940 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.22.16
+#
+# CONFIG_MMU is not set
+# CONFIG_FPU is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_BLACKFIN=y
+CONFIG_ZONE_DMA=y
+CONFIG_SEMAPHORE_SLEEPERS=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_FORCE_MAX_ZONEORDER=14
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+# CONFIG_UID16 is not set
+CONFIG_SYSCTL_SYSCALL=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_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_BIG_ORDER_ALLOC_NOFAIL_MAGIC=3
+# CONFIG_NP2 is not set
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF 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 is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Blackfin Processor Options
+#
+
+#
+# Processor and Board Settings
+#
+# CONFIG_BF522 is not set
+# CONFIG_BF523 is not set
+# CONFIG_BF524 is not set
+# CONFIG_BF525 is not set
+# CONFIG_BF526 is not set
+# CONFIG_BF527 is not set
+# CONFIG_BF531 is not set
+# CONFIG_BF532 is not set
+# CONFIG_BF533 is not set
+# CONFIG_BF534 is not set
+# CONFIG_BF536 is not set
+CONFIG_BF537=y
+# CONFIG_BF542 is not set
+# CONFIG_BF544 is not set
+# CONFIG_BF547 is not set
+# CONFIG_BF548 is not set
+# CONFIG_BF549 is not set
+# CONFIG_BF561 is not set
+# CONFIG_BF_REV_0_0 is not set
+# CONFIG_BF_REV_0_1 is not set
+CONFIG_BF_REV_0_2=y
+# CONFIG_BF_REV_0_3 is not set
+# CONFIG_BF_REV_0_4 is not set
+# CONFIG_BF_REV_0_5 is not set
+# CONFIG_BF_REV_ANY is not set
+# CONFIG_BF_REV_NONE is not set
+CONFIG_BF53x=y
+CONFIG_BFIN_SINGLE_CORE=y
+CONFIG_MEM_MT48LC16M16A2TG_75=y
+CONFIG_IRQ_PLL_WAKEUP=7
+CONFIG_IRQ_RTC=8
+CONFIG_IRQ_PPI=8
+CONFIG_IRQ_SPORT0_RX=9
+CONFIG_IRQ_SPORT0_TX=9
+CONFIG_IRQ_SPORT1_RX=9
+CONFIG_IRQ_SPORT1_TX=9
+CONFIG_IRQ_TWI=10
+CONFIG_IRQ_SPI=10
+CONFIG_IRQ_UART0_RX=10
+CONFIG_IRQ_UART0_TX=10
+CONFIG_IRQ_UART1_RX=10
+CONFIG_IRQ_UART1_TX=10
+CONFIG_IRQ_MAC_RX=11
+CONFIG_IRQ_MAC_TX=11
+CONFIG_IRQ_TMR0=12
+CONFIG_IRQ_TMR1=12
+CONFIG_IRQ_TMR2=12
+CONFIG_IRQ_TMR3=12
+CONFIG_IRQ_TMR4=12
+CONFIG_IRQ_TMR5=12
+CONFIG_IRQ_TMR6=12
+CONFIG_IRQ_TMR7=12
+CONFIG_IRQ_PORTG_INTB=12
+CONFIG_IRQ_MEM_DMA0=13
+CONFIG_IRQ_MEM_DMA1=13
+CONFIG_IRQ_WATCH=13
+# CONFIG_BFIN537_STAMP is not set
+CONFIG_BFIN537_BLUETECHNIX_CM=y
+# CONFIG_PNAV10 is not set
+# CONFIG_CAMSIG_MINOTAUR is not set
+# CONFIG_GENERIC_BF537_BOARD is not set
+
+#
+# BF537 Specific Configuration
+#
+
+#
+# Interrupt Priority Assignment
+#
+
+#
+# Priority
+#
+CONFIG_IRQ_DMA_ERROR=7
+CONFIG_IRQ_ERROR=7
+CONFIG_IRQ_CAN_RX=11
+CONFIG_IRQ_CAN_TX=11
+CONFIG_IRQ_PROG_INTA=12
+
+#
+# Board customizations
+#
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Clock/PLL Setup
+#
+CONFIG_CLKIN_HZ=30000000
+# CONFIG_BFIN_KERNEL_CLOCK is not set
+CONFIG_MAX_VCO_HZ=600000000
+CONFIG_MIN_VCO_HZ=50000000
+CONFIG_MAX_SCLK_HZ=133333333
+CONFIG_MIN_SCLK_HZ=27000000
+
+#
+# Kernel Timer/Scheduler
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+
+#
+# Memory Setup
+#
+CONFIG_MAX_MEM_SIZE=32
+CONFIG_MEM_ADD_WIDTH=9
+CONFIG_BOOT_LOAD=0x1000
+CONFIG_BFIN_SCRATCH_REG_RETN=y
+# CONFIG_BFIN_SCRATCH_REG_RETE is not set
+# CONFIG_BFIN_SCRATCH_REG_CYCLES is not set
+
+#
+# Blackfin Kernel Optimizations
+#
+
+#
+# Memory Optimizations
+#
+CONFIG_I_ENTRY_L1=y
+CONFIG_EXCPT_IRQ_SYSC_L1=y
+CONFIG_DO_IRQ_L1=y
+CONFIG_CORE_TIMER_IRQ_L1=y
+CONFIG_IDLE_L1=y
+CONFIG_SCHEDULE_L1=y
+CONFIG_ARITHMETIC_OPS_L1=y
+CONFIG_ACCESS_OK_L1=y
+CONFIG_MEMSET_L1=y
+CONFIG_MEMCPY_L1=y
+CONFIG_SYS_BFIN_SPINLOCK_L1=y
+CONFIG_IP_CHECKSUM_L1=y
+CONFIG_CACHELINE_ALIGNED_L1=y
+CONFIG_SYSCALL_TAB_L1=y
+CONFIG_CPLB_SWITCH_TAB_L1=y
+CONFIG_RAMKERNEL=y
+# CONFIG_ROMKERNEL is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_LARGE_ALLOCS=y
+# CONFIG_BFIN_GPTIMERS is not set
+CONFIG_BFIN_DMA_5XX=y
+# CONFIG_DMA_UNCACHED_2M is not set
+CONFIG_DMA_UNCACHED_1M=y
+# CONFIG_DMA_UNCACHED_NONE is not set
+
+#
+# Cache Support
+#
+CONFIG_BFIN_ICACHE=y
+CONFIG_BFIN_DCACHE=y
+# CONFIG_BFIN_DCACHE_BANKA is not set
+# CONFIG_BFIN_ICACHE_LOCK is not set
+CONFIG_BFIN_WB=y
+# CONFIG_BFIN_WT is not set
+CONFIG_L1_MAX_PIECE=16
+# CONFIG_MPU is not set
+
+#
+# Asynchonous Memory Configuration
+#
+
+#
+# EBIU_AMGCTL Global Control
+#
+CONFIG_C_AMCKEN=y
+CONFIG_C_CDPRIO=y
+# CONFIG_C_AMBEN is not set
+# CONFIG_C_AMBEN_B0 is not set
+# CONFIG_C_AMBEN_B0_B1 is not set
+# CONFIG_C_AMBEN_B0_B1_B2 is not set
+CONFIG_C_AMBEN_ALL=y
+
+#
+# EBIU_AMBCTL Control
+#
+CONFIG_BANK_0=0x7BB0
+CONFIG_BANK_1=0x7BB0
+CONFIG_BANK_2=0xFFC3
+CONFIG_BANK_3=0xFFC3
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_PCI is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF_FDPIC=y
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_ZFLAT=y
+CONFIG_BINFMT_SHARED_FLAT=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+# CONFIG_PM_WAKEUP_BY_GPIO is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# 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=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETLABEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# 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_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_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_RAM=y
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_UCLINUX=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNPACPI is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_SMC91X=y
+# CONFIG_BFIN_MAC is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DM9000 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_AX88180 is not set
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_AD9960 is not set
+# CONFIG_SPI_ADC_BF533 is not set
+# CONFIG_BF5xx_PFLAGS is not set
+# CONFIG_BF5xx_PPIFCD is not set
+# CONFIG_BFIN_SIMPLE_TIMER is not set
+# CONFIG_BF5xx_PPI is not set
+CONFIG_BFIN_SPORT=y
+# CONFIG_BFIN_TIMER_LATENCY is not set
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_BFIN=y
+CONFIG_SERIAL_BFIN_CONSOLE=y
+CONFIG_SERIAL_BFIN_DMA=y
+# CONFIG_SERIAL_BFIN_PIO is not set
+CONFIG_SERIAL_BFIN_UART0=y
+# CONFIG_BFIN_UART0_CTSRTS is not set
+CONFIG_SERIAL_BFIN_UART1=y
+# CONFIG_BFIN_UART1_CTSRTS is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_BFIN_SPORT is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# CAN, the car bus and industrial fieldbus
+#
+# CONFIG_CAN4LINUX is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# 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
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+CONFIG_USB_GADGET_NET2272=y
+CONFIG_USB_NET2272=y
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# PBX support
+#
+# CONFIG_PBX is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_FS_MBCACHE=y
+# 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_GFS2_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
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# 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_SYSCTL=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_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_YAFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# 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 is not set
+# CONFIG_NFSD 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
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_MMRS is not set
+# CONFIG_DEBUG_HUNT_FOR_ZERO is not set
+CONFIG_DEBUG_BFIN_HWTRACE_ON=y
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
+# CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
+# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+# CONFIG_EARLY_PRINTK is not set
+CONFIG_CPLB_INFO=y
+CONFIG_ACCESS_CHECK=y
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+CONFIG_SECURITY=y
+# CONFIG_SECURITY_NETWORK is not set
+CONFIG_SECURITY_CAPABILITIES=y
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/blackfin/configs/CM-BF548_defconfig b/arch/blackfin/configs/CM-BF548_defconfig
new file mode 100644
index 0000000..9020725
--- /dev/null
+++ b/arch/blackfin/configs/CM-BF548_defconfig
@@ -0,0 +1,1373 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.24.4
+#
+# CONFIG_MMU is not set
+# CONFIG_FPU is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_BLACKFIN=y
+CONFIG_ZONE_DMA=y
+CONFIG_SEMAPHORE_SLEEPERS=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_FORCE_MAX_ZONEORDER=14
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FAIR_USER_SCHED=y
+# CONFIG_FAIR_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=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_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_BIG_ORDER_ALLOC_NOFAIL_MAGIC=3
+# CONFIG_NP2 is not set
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+# CONFIG_IOSCHED_DEADLINE is not set
+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_PREEMPT_NONE is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+# CONFIG_PREEMPT is not set
+
+#
+# Blackfin Processor Options
+#
+
+#
+# Processor and Board Settings
+#
+# CONFIG_BF522 is not set
+# CONFIG_BF523 is not set
+# CONFIG_BF524 is not set
+# CONFIG_BF525 is not set
+# CONFIG_BF526 is not set
+# CONFIG_BF527 is not set
+# CONFIG_BF531 is not set
+# CONFIG_BF532 is not set
+# CONFIG_BF533 is not set
+# CONFIG_BF534 is not set
+# CONFIG_BF536 is not set
+# CONFIG_BF537 is not set
+# CONFIG_BF542 is not set
+# CONFIG_BF544 is not set
+# CONFIG_BF547 is not set
+CONFIG_BF548=y
+# CONFIG_BF549 is not set
+# CONFIG_BF561 is not set
+CONFIG_BF_REV_0_0=y
+# CONFIG_BF_REV_0_1 is not set
+# CONFIG_BF_REV_0_2 is not set
+# CONFIG_BF_REV_0_3 is not set
+# CONFIG_BF_REV_0_4 is not set
+# CONFIG_BF_REV_0_5 is not set
+# CONFIG_BF_REV_ANY is not set
+# CONFIG_BF_REV_NONE is not set
+CONFIG_BF54x=y
+CONFIG_IRQ_PLL_WAKEUP=7
+CONFIG_IRQ_RTC=8
+CONFIG_IRQ_SPORT0_RX=9
+CONFIG_IRQ_SPORT0_TX=9
+CONFIG_IRQ_SPORT1_RX=9
+CONFIG_IRQ_SPORT1_TX=9
+CONFIG_IRQ_UART0_RX=10
+CONFIG_IRQ_UART0_TX=10
+CONFIG_IRQ_UART1_RX=10
+CONFIG_IRQ_UART1_TX=10
+CONFIG_IRQ_CNT=8
+CONFIG_IRQ_USB_INT0=11
+CONFIG_IRQ_USB_INT1=11
+CONFIG_IRQ_USB_INT2=11
+CONFIG_IRQ_USB_DMA=11
+CONFIG_IRQ_TIMER0=11
+CONFIG_IRQ_TIMER1=11
+CONFIG_IRQ_TIMER2=11
+CONFIG_IRQ_TIMER3=11
+CONFIG_IRQ_TIMER4=11
+CONFIG_IRQ_TIMER5=11
+CONFIG_IRQ_TIMER6=11
+CONFIG_IRQ_TIMER7=11
+CONFIG_IRQ_TIMER8=11
+CONFIG_IRQ_TIMER9=11
+CONFIG_IRQ_TIMER10=11
+# CONFIG_BFIN548_EZKIT is not set
+CONFIG_BFIN548_BLUETECHNIX_CM=y
+
+#
+# BF548 Specific Configuration
+#
+# CONFIG_DEB_DMA_URGENT is not set
+
+#
+# Interrupt Priority Assignment
+#
+
+#
+# Priority
+#
+CONFIG_IRQ_DMAC0_ERR=7
+CONFIG_IRQ_EPPI0_ERR=7
+CONFIG_IRQ_SPORT0_ERR=7
+CONFIG_IRQ_SPORT1_ERR=7
+CONFIG_IRQ_SPI0_ERR=7
+CONFIG_IRQ_UART0_ERR=7
+CONFIG_IRQ_EPPI0=8
+CONFIG_IRQ_SPI0=10
+CONFIG_IRQ_PINT0=12
+CONFIG_IRQ_PINT1=12
+CONFIG_IRQ_MDMAS0=13
+CONFIG_IRQ_MDMAS1=13
+CONFIG_IRQ_WATCHDOG=13
+CONFIG_IRQ_DMAC1_ERR=7
+CONFIG_IRQ_SPORT2_ERR=7
+CONFIG_IRQ_SPORT3_ERR=7
+CONFIG_IRQ_MXVR_DATA=7
+CONFIG_IRQ_SPI1_ERR=7
+CONFIG_IRQ_SPI2_ERR=7
+CONFIG_IRQ_UART1_ERR=7
+CONFIG_IRQ_UART2_ERR=7
+CONFIG_IRQ_CAN0_ERR=7
+CONFIG_IRQ_SPORT2_RX=9
+CONFIG_IRQ_SPORT2_TX=9
+CONFIG_IRQ_SPORT3_RX=9
+CONFIG_IRQ_SPORT3_TX=9
+CONFIG_IRQ_EPPI1=9
+CONFIG_IRQ_EPPI2=9
+CONFIG_IRQ_SPI1=10
+CONFIG_IRQ_SPI2=10
+CONFIG_IRQ_ATAPI_RX=10
+CONFIG_IRQ_ATAPI_TX=10
+CONFIG_IRQ_TWI0=11
+CONFIG_IRQ_TWI1=11
+CONFIG_IRQ_CAN0_RX=11
+CONFIG_IRQ_CAN0_TX=11
+CONFIG_IRQ_MDMAS2=13
+CONFIG_IRQ_MDMAS3=13
+CONFIG_IRQ_MXVR_ERR=11
+CONFIG_IRQ_MXVR_MSG=11
+CONFIG_IRQ_MXVR_PKT=11
+CONFIG_IRQ_EPPI1_ERR=7
+CONFIG_IRQ_EPPI2_ERR=7
+CONFIG_IRQ_UART3_ERR=7
+CONFIG_IRQ_HOST_ERR=7
+CONFIG_IRQ_PIXC_ERR=7
+CONFIG_IRQ_NFC_ERR=7
+CONFIG_IRQ_ATAPI_ERR=7
+CONFIG_IRQ_CAN1_ERR=7
+CONFIG_IRQ_HS_DMA_ERR=7
+CONFIG_IRQ_PIXC_IN0=8
+CONFIG_IRQ_PIXC_IN1=8
+CONFIG_IRQ_PIXC_OUT=8
+CONFIG_IRQ_SDH=8
+CONFIG_IRQ_KEY=8
+CONFIG_IRQ_CAN1_RX=11
+CONFIG_IRQ_CAN1_TX=11
+CONFIG_IRQ_SDH_MASK0=11
+CONFIG_IRQ_SDH_MASK1=11
+CONFIG_IRQ_OTPSEC=11
+CONFIG_IRQ_PINT2=11
+CONFIG_IRQ_PINT3=11
+
+#
+# Pin Interrupt to Port Assignment
+#
+
+#
+# Assignment
+#
+CONFIG_PINTx_REASSIGN=y
+CONFIG_PINT0_ASSIGN=0x00000101
+CONFIG_PINT1_ASSIGN=0x01010000
+CONFIG_PINT2_ASSIGN=0x07000101
+CONFIG_PINT3_ASSIGN=0x02020303
+
+#
+# Board customizations
+#
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Clock/PLL Setup
+#
+CONFIG_CLKIN_HZ=25000000
+# CONFIG_BFIN_KERNEL_CLOCK is not set
+CONFIG_MAX_VCO_HZ=600000000
+CONFIG_MIN_VCO_HZ=50000000
+CONFIG_MAX_SCLK_HZ=133333333
+CONFIG_MIN_SCLK_HZ=27000000
+
+#
+# Kernel Timer/Scheduler
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_GENERIC_TIME is not set
+# CONFIG_TICK_ONESHOT is not set
+
+#
+# Memory Setup
+#
+CONFIG_MAX_MEM_SIZE=64
+# CONFIG_MEM_MT46V32M16_6T is not set
+CONFIG_MEM_MT46V32M16_5B=y
+CONFIG_BOOT_LOAD=0x1000
+CONFIG_BFIN_SCRATCH_REG_RETN=y
+# CONFIG_BFIN_SCRATCH_REG_RETE is not set
+# CONFIG_BFIN_SCRATCH_REG_CYCLES is not set
+
+#
+# Blackfin Kernel Optimizations
+#
+
+#
+# Memory Optimizations
+#
+CONFIG_I_ENTRY_L1=y
+CONFIG_EXCPT_IRQ_SYSC_L1=y
+CONFIG_DO_IRQ_L1=y
+CONFIG_CORE_TIMER_IRQ_L1=y
+CONFIG_IDLE_L1=y
+# CONFIG_SCHEDULE_L1 is not set
+CONFIG_ARITHMETIC_OPS_L1=y
+CONFIG_ACCESS_OK_L1=y
+# CONFIG_MEMSET_L1 is not set
+# CONFIG_MEMCPY_L1 is not set
+# CONFIG_SYS_BFIN_SPINLOCK_L1 is not set
+# CONFIG_IP_CHECKSUM_L1 is not set
+CONFIG_CACHELINE_ALIGNED_L1=y
+# CONFIG_SYSCALL_TAB_L1 is not set
+# CONFIG_CPLB_SWITCH_TAB_L1 is not set
+CONFIG_RAMKERNEL=y
+# CONFIG_ROMKERNEL is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_BFIN_GPTIMERS is not set
+CONFIG_BFIN_DMA_5XX=y
+# CONFIG_DMA_UNCACHED_2M is not set
+CONFIG_DMA_UNCACHED_1M=y
+# CONFIG_DMA_UNCACHED_NONE is not set
+
+#
+# Cache Support
+#
+CONFIG_BFIN_ICACHE=y
+CONFIG_BFIN_DCACHE=y
+# CONFIG_BFIN_DCACHE_BANKA is not set
+# CONFIG_BFIN_ICACHE_LOCK is not set
+# CONFIG_BFIN_WB is not set
+CONFIG_BFIN_WT=y
+CONFIG_L1_MAX_PIECE=16
+# CONFIG_MPU is not set
+
+#
+# Asynchonous Memory Configuration
+#
+
+#
+# EBIU_AMGCTL Global Control
+#
+CONFIG_C_AMCKEN=y
+# CONFIG_C_CDPRIO is not set
+# CONFIG_C_AMBEN is not set
+# CONFIG_C_AMBEN_B0 is not set
+# CONFIG_C_AMBEN_B0_B1 is not set
+# CONFIG_C_AMBEN_B0_B1_B2 is not set
+CONFIG_C_AMBEN_ALL=y
+
+#
+# EBIU_AMBCTL Control
+#
+CONFIG_BANK_0=0x7BB0
+CONFIG_BANK_1=0x5554
+CONFIG_BANK_2=0x7BB0
+CONFIG_BANK_3=0x99B3
+CONFIG_EBIU_MBSCTLVAL=0x0
+CONFIG_EBIU_MODEVAL=0x1
+CONFIG_EBIU_FCTLVAL=0x6
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_PCI is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF_FDPIC=y
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_ZFLAT=y
+# CONFIG_BINFMT_SHARED_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_SUSPEND_UP_POSSIBLE=y
+# CONFIG_PM_WAKEUP_BY_GPIO is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# 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=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE 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_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETLABEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# 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_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# 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_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+CONFIG_MTD_RAM=y
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0x20000000
+CONFIG_MTD_PHYSMAP_LEN=0x800000
+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+# CONFIG_MTD_UCLINUX is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD 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_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+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=y
+# CONFIG_BLK_DEV_SR_VENDOR 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
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_SMC91X is not set
+CONFIG_SMSC911X=y
+# CONFIG_DM9000 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_B44 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# 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_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=m
+CONFIG_INPUT_EVBUG=m
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_BFIN is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET 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_AD9960 is not set
+# CONFIG_SPI_ADC_BF533 is not set
+# CONFIG_BF5xx_PPIFCD is not set
+# CONFIG_BFIN_SIMPLE_TIMER is not set
+# CONFIG_BF5xx_PPI is not set
+CONFIG_BFIN_OTP=y
+# CONFIG_BFIN_OTP_WRITE_ENABLE is not set
+# CONFIG_BFIN_SPORT is not set
+# CONFIG_BFIN_TIMER_LATENCY is not set
+# CONFIG_TWI_LCD is not set
+# CONFIG_SIMPLE_GPIO is not set
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_BFIN=y
+CONFIG_SERIAL_BFIN_CONSOLE=y
+# CONFIG_SERIAL_BFIN_DMA is not set
+CONFIG_SERIAL_BFIN_PIO=y
+# CONFIG_SERIAL_BFIN_UART0 is not set
+CONFIG_SERIAL_BFIN_UART1=y
+# CONFIG_BFIN_UART1_CTSRTS is not set
+# CONFIG_SERIAL_BFIN_UART2 is not set
+# CONFIG_SERIAL_BFIN_UART3 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_BFIN_SPORT is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# CAN, the car bus and industrial fieldbus
+#
+# CONFIG_CAN4LINUX is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_GEN_RTC is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+CONFIG_I2C_BLACKFIN_TWI=y
+CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=50
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_AD5252 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8575 is not set
+# CONFIG_SENSORS_PCA9543 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 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=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BFIN=y
+# CONFIG_SPI_BITBANG is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 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_LM93 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_BFIN_WDT=y
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_SOC=y
+
+#
+# Blackfin BF54x, BF525 and BF527 high speed USB support
+#
+CONFIG_USB_MUSB_HOST=y
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+# CONFIG_USB_MUSB_OTG is not set
+CONFIG_USB_MUSB_HDRC_HCD=y
+# CONFIG_MUSB_PIO_ONLY is not set
+# CONFIG_USB_INVENTRA_DMA is not set
+# CONFIG_USB_TI_CPPI_DMA is not set
+CONFIG_USB_MUSB_LOGLEVEL=0
+
+#
+# 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=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_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_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK 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_ADUTUX 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_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_SDH_BFIN=y
+# CONFIG_MMC_SPI is not set
+# CONFIG_SPI_MMC is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_BFIN=y
+
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
+# PBX support
+#
+# CONFIG_PBX is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_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_GFS2_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
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_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_YAFFS_FS=m
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# 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
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=m
+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=m
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
+# CONFIG_NFSD_V4 is not set
+CONFIG_NFSD_TCP=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+# CONFIG_SUNRPC_BIND34 is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="cp437"
+CONFIG_CIFS=y
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_WEAK_PW_HASH is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_DEBUG2 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
+
+#
+# Partition Types
+#
+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
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+# CONFIG_DLM is not set
+CONFIG_INSTRUMENTATION=y
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_SAMPLES is not set
+# CONFIG_DEBUG_MMRS is not set
+CONFIG_DEBUG_HUNT_FOR_ZERO=y
+CONFIG_DEBUG_BFIN_HWTRACE_ON=y
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
+# CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
+# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+# CONFIG_EARLY_PRINTK is not set
+CONFIG_CPLB_INFO=y
+CONFIG_ACCESS_CHECK=y
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+CONFIG_SECURITY=y
+# CONFIG_SECURITY_NETWORK is not set
+# CONFIG_SECURITY_CAPABILITIES is not set
+# CONFIG_SECURITY_ROOTPLUG is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/blackfin/configs/CM-BF561_defconfig b/arch/blackfin/configs/CM-BF561_defconfig
new file mode 100644
index 0000000..daf0090
--- /dev/null
+++ b/arch/blackfin/configs/CM-BF561_defconfig
@@ -0,0 +1,876 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.24.4
+# Tue Apr  1 10:50:11 2008
+#
+# CONFIG_MMU is not set
+# CONFIG_FPU is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_BLACKFIN=y
+CONFIG_ZONE_DMA=y
+CONFIG_SEMAPHORE_SLEEPERS=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_FORCE_MAX_ZONEORDER=14
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FAIR_USER_SCHED=y
+# CONFIG_FAIR_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+# CONFIG_UID16 is not set
+CONFIG_SYSCTL_SYSCALL=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_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_BIG_ORDER_ALLOC_NOFAIL_MAGIC=3
+# CONFIG_NP2 is not set
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG 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 is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Blackfin Processor Options
+#
+
+#
+# Processor and Board Settings
+#
+# CONFIG_BF522 is not set
+# CONFIG_BF523 is not set
+# CONFIG_BF524 is not set
+# CONFIG_BF525 is not set
+# CONFIG_BF526 is not set
+# CONFIG_BF527 is not set
+# CONFIG_BF531 is not set
+# CONFIG_BF532 is not set
+# CONFIG_BF533 is not set
+# CONFIG_BF534 is not set
+# CONFIG_BF536 is not set
+# CONFIG_BF537 is not set
+# CONFIG_BF542 is not set
+# CONFIG_BF544 is not set
+# CONFIG_BF547 is not set
+# CONFIG_BF548 is not set
+# CONFIG_BF549 is not set
+CONFIG_BF561=y
+# CONFIG_BF_REV_0_0 is not set
+# CONFIG_BF_REV_0_1 is not set
+# CONFIG_BF_REV_0_2 is not set
+CONFIG_BF_REV_0_3=y
+# CONFIG_BF_REV_0_4 is not set
+# CONFIG_BF_REV_0_5 is not set
+# CONFIG_BF_REV_ANY is not set
+# CONFIG_BF_REV_NONE is not set
+CONFIG_BFIN_DUAL_CORE=y
+CONFIG_MEM_MT48LC8M32B2B5_7=y
+CONFIG_IRQ_PLL_WAKEUP=7
+CONFIG_IRQ_SPORT0_ERROR=7
+CONFIG_IRQ_SPORT1_ERROR=7
+CONFIG_IRQ_SPI_ERROR=7
+# CONFIG_BFIN561_EZKIT is not set
+# CONFIG_BFIN561_TEPLA is not set
+CONFIG_BFIN561_BLUETECHNIX_CM=y
+# CONFIG_GENERIC_BF561_BOARD is not set
+
+#
+# BF561 Specific Configuration
+#
+
+#
+# Core B Support
+#
+
+#
+# Core B Support
+#
+CONFIG_BF561_COREB=y
+# CONFIG_BF561_COREB_RESET is not set
+
+#
+# Interrupt Priority Assignment
+#
+
+#
+# Priority
+#
+CONFIG_IRQ_DMA1_ERROR=7
+CONFIG_IRQ_DMA2_ERROR=7
+CONFIG_IRQ_IMDMA_ERROR=7
+CONFIG_IRQ_PPI0_ERROR=7
+CONFIG_IRQ_PPI1_ERROR=7
+CONFIG_IRQ_UART_ERROR=7
+CONFIG_IRQ_RESERVED_ERROR=7
+CONFIG_IRQ_DMA1_0=8
+CONFIG_IRQ_DMA1_1=8
+CONFIG_IRQ_DMA1_2=8
+CONFIG_IRQ_DMA1_3=8
+CONFIG_IRQ_DMA1_4=8
+CONFIG_IRQ_DMA1_5=8
+CONFIG_IRQ_DMA1_6=8
+CONFIG_IRQ_DMA1_7=8
+CONFIG_IRQ_DMA1_8=8
+CONFIG_IRQ_DMA1_9=8
+CONFIG_IRQ_DMA1_10=8
+CONFIG_IRQ_DMA1_11=8
+CONFIG_IRQ_DMA2_0=9
+CONFIG_IRQ_DMA2_1=9
+CONFIG_IRQ_DMA2_2=9
+CONFIG_IRQ_DMA2_3=9
+CONFIG_IRQ_DMA2_4=9
+CONFIG_IRQ_DMA2_5=9
+CONFIG_IRQ_DMA2_6=9
+CONFIG_IRQ_DMA2_7=9
+CONFIG_IRQ_DMA2_8=9
+CONFIG_IRQ_DMA2_9=9
+CONFIG_IRQ_DMA2_10=9
+CONFIG_IRQ_DMA2_11=9
+CONFIG_IRQ_TIMER0=10
+CONFIG_IRQ_TIMER1=10
+CONFIG_IRQ_TIMER2=10
+CONFIG_IRQ_TIMER3=10
+CONFIG_IRQ_TIMER4=10
+CONFIG_IRQ_TIMER5=10
+CONFIG_IRQ_TIMER6=10
+CONFIG_IRQ_TIMER7=10
+CONFIG_IRQ_TIMER8=10
+CONFIG_IRQ_TIMER9=10
+CONFIG_IRQ_TIMER10=10
+CONFIG_IRQ_TIMER11=10
+CONFIG_IRQ_PROG0_INTA=11
+CONFIG_IRQ_PROG0_INTB=11
+CONFIG_IRQ_PROG1_INTA=11
+CONFIG_IRQ_PROG1_INTB=11
+CONFIG_IRQ_PROG2_INTA=11
+CONFIG_IRQ_PROG2_INTB=11
+CONFIG_IRQ_DMA1_WRRD0=8
+CONFIG_IRQ_DMA1_WRRD1=8
+CONFIG_IRQ_DMA2_WRRD0=9
+CONFIG_IRQ_DMA2_WRRD1=9
+CONFIG_IRQ_IMDMA_WRRD0=12
+CONFIG_IRQ_IMDMA_WRRD1=12
+CONFIG_IRQ_WDTIMER=13
+
+#
+# Board customizations
+#
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Clock/PLL Setup
+#
+CONFIG_CLKIN_HZ=25000000
+# CONFIG_BFIN_KERNEL_CLOCK is not set
+CONFIG_MAX_VCO_HZ=600000000
+CONFIG_MIN_VCO_HZ=50000000
+CONFIG_MAX_SCLK_HZ=133333333
+CONFIG_MIN_SCLK_HZ=27000000
+
+#
+# Kernel Timer/Scheduler
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_CYCLES_CLOCKSOURCE is not set
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+
+#
+# Memory Setup
+#
+CONFIG_MAX_MEM_SIZE=32
+CONFIG_BOOT_LOAD=0x1000
+CONFIG_BFIN_SCRATCH_REG_RETN=y
+# CONFIG_BFIN_SCRATCH_REG_RETE is not set
+# CONFIG_BFIN_SCRATCH_REG_CYCLES is not set
+
+#
+# Blackfin Kernel Optimizations
+#
+
+#
+# Memory Optimizations
+#
+CONFIG_I_ENTRY_L1=y
+CONFIG_EXCPT_IRQ_SYSC_L1=y
+CONFIG_DO_IRQ_L1=y
+CONFIG_CORE_TIMER_IRQ_L1=y
+CONFIG_IDLE_L1=y
+CONFIG_SCHEDULE_L1=y
+CONFIG_ARITHMETIC_OPS_L1=y
+CONFIG_ACCESS_OK_L1=y
+CONFIG_MEMSET_L1=y
+CONFIG_MEMCPY_L1=y
+CONFIG_SYS_BFIN_SPINLOCK_L1=y
+CONFIG_IP_CHECKSUM_L1=y
+CONFIG_CACHELINE_ALIGNED_L1=y
+CONFIG_SYSCALL_TAB_L1=y
+CONFIG_CPLB_SWITCH_TAB_L1=y
+CONFIG_RAMKERNEL=y
+# CONFIG_ROMKERNEL is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_VIRT_TO_BUS=y
+CONFIG_LARGE_ALLOCS=y
+# CONFIG_BFIN_GPTIMERS is not set
+CONFIG_BFIN_DMA_5XX=y
+# CONFIG_DMA_UNCACHED_2M is not set
+CONFIG_DMA_UNCACHED_1M=y
+# CONFIG_DMA_UNCACHED_NONE is not set
+
+#
+# Cache Support
+#
+CONFIG_BFIN_ICACHE=y
+CONFIG_BFIN_DCACHE=y
+# CONFIG_BFIN_DCACHE_BANKA is not set
+# CONFIG_BFIN_ICACHE_LOCK is not set
+CONFIG_BFIN_WB=y
+# CONFIG_BFIN_WT is not set
+CONFIG_L1_MAX_PIECE=16
+# CONFIG_MPU is not set
+
+#
+# Asynchonous Memory Configuration
+#
+
+#
+# EBIU_AMGCTL Global Control
+#
+CONFIG_C_AMCKEN=y
+CONFIG_C_CDPRIO=y
+CONFIG_C_B0PEN=y
+CONFIG_C_B1PEN=y
+CONFIG_C_B2PEN=y
+# CONFIG_C_B3PEN is not set
+# CONFIG_C_AMBEN is not set
+# CONFIG_C_AMBEN_B0 is not set
+# CONFIG_C_AMBEN_B0_B1 is not set
+# CONFIG_C_AMBEN_B0_B1_B2 is not set
+CONFIG_C_AMBEN_ALL=y
+
+#
+# EBIU_AMBCTL Control
+#
+CONFIG_BANK_0=0x7BB0
+CONFIG_BANK_1=0x7BB0
+CONFIG_BANK_2=0x7BB0
+CONFIG_BANK_3=0xFFC3
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_PCI is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF_FDPIC=y
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_ZFLAT=y
+CONFIG_BINFMT_SHARED_FLAT=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_SUSPEND_UP_POSSIBLE=y
+# CONFIG_PM_WAKEUP_BY_GPIO is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# 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=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETLABEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# 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_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# 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_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_RAM=y
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_UCLINUX=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_IDE is not set
+# CONFIG_BFIN_IDE_ADDRESS_MAPPING_MODE0 is not set
+# CONFIG_BFIN_IDE_ADDRESS_MAPPING_MODE1 is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_SMC91X=y
+# CONFIG_SMSC911X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_B44 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_AX88180 is not set
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_AD9960 is not set
+# CONFIG_SPI_ADC_BF533 is not set
+# CONFIG_BF5xx_PPIFCD is not set
+# CONFIG_BFIN_SIMPLE_TIMER is not set
+# CONFIG_BF5xx_PPI is not set
+# CONFIG_BFIN_SPORT is not set
+# CONFIG_BFIN_TIMER_LATENCY is not set
+# CONFIG_SIMPLE_GPIO is not set
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_BFIN=y
+CONFIG_SERIAL_BFIN_CONSOLE=y
+CONFIG_SERIAL_BFIN_DMA=y
+# CONFIG_SERIAL_BFIN_PIO is not set
+CONFIG_SERIAL_BFIN_UART0=y
+# CONFIG_BFIN_UART0_CTSRTS is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_BFIN_SPORT is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# CAN, the car bus and industrial fieldbus
+#
+# CONFIG_CAN4LINUX is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+
+#
+# Enable Host or Gadget support to see Inventra options
+#
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_RTC_CLASS is not set
+
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
+# PBX support
+#
+# CONFIG_PBX is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_FS_MBCACHE=y
+# 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_GFS2_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
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# 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_SYSCTL=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_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_YAFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# 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
+CONFIG_NETWORK_FILESYSTEMS=y
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD 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
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+# CONFIG_DLM is not set
+CONFIG_INSTRUMENTATION=y
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_SAMPLES is not set
+# CONFIG_DEBUG_MMRS is not set
+CONFIG_DEBUG_HUNT_FOR_ZERO=y
+CONFIG_DEBUG_BFIN_HWTRACE_ON=y
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
+# CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
+# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+# CONFIG_EARLY_PRINTK is not set
+# CONFIG_DUAL_CORE_TEST_MODULE is not set
+CONFIG_CPLB_INFO=y
+CONFIG_ACCESS_CHECK=y
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+CONFIG_SECURITY=y
+# CONFIG_SECURITY_NETWORK is not set
+CONFIG_SECURITY_CAPABILITIES=y
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/blackfin/configs/H8606_defconfig b/arch/blackfin/configs/H8606_defconfig
index 18cbb8c..679c748 100644
--- a/arch/blackfin/configs/H8606_defconfig
+++ b/arch/blackfin/configs/H8606_defconfig
@@ -13,7 +13,7 @@
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
-# CONFIG_GENERIC_TIME is not set
+CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_GPIO=y
 CONFIG_FORCE_MAX_ZONEORDER=14
 CONFIG_GENERIC_CALIBRATE_DELAY=y
@@ -207,7 +207,7 @@
 #
 # Memory Setup
 #
-CONFIG_MEM_SIZE=32
+CONFIG_MAX_MEM_SIZE=32
 CONFIG_MEM_ADD_WIDTH=9
 CONFIG_BOOT_LOAD=0x1000
 CONFIG_BFIN_SCRATCH_REG_RETN=y
diff --git a/arch/blackfin/configs/IP0X_defconfig b/arch/blackfin/configs/IP0X_defconfig
new file mode 100644
index 0000000..5f6ff04
--- /dev/null
+++ b/arch/blackfin/configs/IP0X_defconfig
@@ -0,0 +1,1252 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.22.18
+#
+# CONFIG_MMU is not set
+# CONFIG_FPU is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_BLACKFIN=y
+CONFIG_ZONE_DMA=y
+CONFIG_SEMAPHORE_SLEEPERS=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+# CONFIG_GENERIC_TIME is not set
+CONFIG_GENERIC_GPIO=y
+CONFIG_FORCE_MAX_ZONEORDER=14
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=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_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_BIG_ORDER_ALLOC_NOFAIL_MAGIC=3
+# CONFIG_NP2 is not set
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+# CONFIG_IOSCHED_DEADLINE is not set
+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_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Blackfin Processor Options
+#
+
+#
+# Processor and Board Settings
+#
+# CONFIG_BF522 is not set
+# CONFIG_BF523 is not set
+# CONFIG_BF524 is not set
+# CONFIG_BF525 is not set
+# CONFIG_BF526 is not set
+# CONFIG_BF527 is not set
+# CONFIG_BF531 is not set
+CONFIG_BF532=y
+# CONFIG_BF533 is not set
+# CONFIG_BF534 is not set
+# CONFIG_BF536 is not set
+# CONFIG_BF537 is not set
+# CONFIG_BF542 is not set
+# CONFIG_BF544 is not set
+# CONFIG_BF547 is not set
+# CONFIG_BF548 is not set
+# CONFIG_BF549 is not set
+# CONFIG_BF561 is not set
+# CONFIG_BF_REV_0_0 is not set
+# CONFIG_BF_REV_0_1 is not set
+# CONFIG_BF_REV_0_2 is not set
+# CONFIG_BF_REV_0_3 is not set
+# CONFIG_BF_REV_0_4 is not set
+CONFIG_BF_REV_0_5=y
+# CONFIG_BF_REV_ANY is not set
+# CONFIG_BF_REV_NONE is not set
+CONFIG_BF53x=y
+CONFIG_BFIN_SINGLE_CORE=y
+CONFIG_MEM_MT48LC32M16A2TG_75=y
+# CONFIG_BFIN533_EZKIT is not set
+# CONFIG_BFIN533_STAMP is not set
+# CONFIG_BFIN533_BLUETECHNIX_CM is not set
+# CONFIG_H8606_HVSISTEMAS is not set
+CONFIG_BFIN532_IP0X=y
+# CONFIG_GENERIC_BF533_BOARD is not set
+
+#
+# BF533/2/1 Specific Configuration
+#
+
+#
+# Interrupt Priority Assignment
+#
+
+#
+# Priority
+#
+CONFIG_UART_ERROR=7
+CONFIG_SPORT0_ERROR=7
+CONFIG_SPI_ERROR=7
+CONFIG_SPORT1_ERROR=7
+CONFIG_PPI_ERROR=7
+CONFIG_DMA_ERROR=7
+CONFIG_PLLWAKE_ERROR=7
+CONFIG_RTC_ERROR=8
+CONFIG_DMA0_PPI=8
+CONFIG_DMA1_SPORT0RX=9
+CONFIG_DMA2_SPORT0TX=9
+CONFIG_DMA3_SPORT1RX=9
+CONFIG_DMA4_SPORT1TX=9
+CONFIG_DMA5_SPI=10
+CONFIG_DMA6_UARTRX=10
+CONFIG_DMA7_UARTTX=10
+CONFIG_TIMER0=11
+CONFIG_TIMER1=11
+CONFIG_TIMER2=11
+CONFIG_PFA=12
+CONFIG_PFB=12
+CONFIG_MEMDMA0=13
+CONFIG_MEMDMA1=13
+CONFIG_WDTIMER=13
+
+#
+# Board customizations
+#
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Clock/PLL Setup
+#
+CONFIG_CLKIN_HZ=10000000
+# CONFIG_BFIN_KERNEL_CLOCK is not set
+CONFIG_MAX_VCO_HZ=400000000
+CONFIG_MIN_VCO_HZ=50000000
+CONFIG_MAX_SCLK_HZ=133333333
+CONFIG_MIN_SCLK_HZ=27000000
+
+#
+# Kernel Timer/Scheduler
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+
+#
+# Memory Setup
+#
+CONFIG_MEM_SIZE=64
+CONFIG_MEM_ADD_WIDTH=10
+
+#
+# Hardware addresses
+#
+CONFIG_IP0X_NET1=0x20100000
+CONFIG_IP0X_NET2=0x20200000
+CONFIG_IP0X_USB=0x20300000
+CONFIG_BOOT_LOAD=0x1000
+CONFIG_BFIN_SCRATCH_REG_RETN=y
+# CONFIG_BFIN_SCRATCH_REG_RETE is not set
+# CONFIG_BFIN_SCRATCH_REG_CYCLES is not set
+
+#
+# Blackfin Kernel Optimizations
+#
+
+#
+# Memory Optimizations
+#
+CONFIG_I_ENTRY_L1=y
+CONFIG_EXCPT_IRQ_SYSC_L1=y
+CONFIG_DO_IRQ_L1=y
+CONFIG_CORE_TIMER_IRQ_L1=y
+CONFIG_IDLE_L1=y
+CONFIG_SCHEDULE_L1=y
+CONFIG_ARITHMETIC_OPS_L1=y
+CONFIG_ACCESS_OK_L1=y
+CONFIG_MEMSET_L1=y
+CONFIG_MEMCPY_L1=y
+CONFIG_SYS_BFIN_SPINLOCK_L1=y
+# CONFIG_IP_CHECKSUM_L1 is not set
+CONFIG_CACHELINE_ALIGNED_L1=y
+# CONFIG_SYSCALL_TAB_L1 is not set
+# CONFIG_CPLB_SWITCH_TAB_L1 is not set
+CONFIG_RAMKERNEL=y
+# CONFIG_ROMKERNEL is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_LARGE_ALLOCS=y
+# CONFIG_BFIN_GPTIMERS is not set
+CONFIG_BFIN_DMA_5XX=y
+# CONFIG_DMA_UNCACHED_2M is not set
+CONFIG_DMA_UNCACHED_1M=y
+# CONFIG_DMA_UNCACHED_NONE is not set
+
+#
+# Cache Support
+#
+# CONFIG_BFIN_ICACHE is not set
+# CONFIG_BFIN_DCACHE is not set
+# CONFIG_BFIN_ICACHE_LOCK is not set
+CONFIG_L1_MAX_PIECE=16
+# CONFIG_MPU is not set
+
+#
+# Asynchonous Memory Configuration
+#
+
+#
+# EBIU_AMGCTL Global Control
+#
+CONFIG_C_AMCKEN=y
+CONFIG_C_CDPRIO=y
+# CONFIG_C_AMBEN is not set
+# CONFIG_C_AMBEN_B0 is not set
+# CONFIG_C_AMBEN_B0_B1 is not set
+# CONFIG_C_AMBEN_B0_B1_B2 is not set
+CONFIG_C_AMBEN_ALL=y
+
+#
+# EBIU_AMBCTL Control
+#
+CONFIG_BANK_0=0xffc2
+CONFIG_BANK_1=0xffc2
+CONFIG_BANK_2=0xffc2
+CONFIG_BANK_3=0xffc2
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_PCI is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF_FDPIC=y
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_ZFLAT=y
+# CONFIG_BINFMT_SHARED_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_LEGACY is not set
+# CONFIG_PM_DEBUG is not set
+# CONFIG_PM_SYSFS_DEPRECATED is not set
+CONFIG_PM_BFIN_SLEEP_DEEPER=y
+# CONFIG_PM_BFIN_SLEEP is not set
+# CONFIG_PM_WAKEUP_BY_GPIO is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# 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=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE 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_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETLABEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK is not set
+# CONFIG_NF_CONNTRACK_ENABLED is not set
+# CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=y
+# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
+# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
+# CONFIG_NETFILTER_XT_TARGET_MARK is not set
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_IPRANGE=y
+CONFIG_IP_NF_MATCH_TOS=y
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_AH 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_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+# CONFIG_IP_NF_TARGET_LOG is not set
+# CONFIG_IP_NF_TARGET_ULOG is not set
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_TARGET_TOS=y
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_TTL is not set
+# CONFIG_IP_NF_RAW is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# 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_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_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+CONFIG_MTD_RAM=y
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_UCLINUX=y
+CONFIG_MTD_PLATRAM=y
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_BFIN=y
+CONFIG_BFIN_NAND_BASE=0x20000000
+CONFIG_BFIN_NAND_SIZE=0x10000000
+CONFIG_BFIN_NAND_CLE=2
+CONFIG_BFIN_NAND_ALE=1
+CONFIG_BFIN_NAND_READY=10
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNPACPI is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD 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_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+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
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# 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
+# CONFIG_SCSI_SAS_LIBSAS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_SMC91X is not set
+# CONFIG_SMSC911X is not set
+CONFIG_DM9000=y
+CONFIG_NETDEV_1000=y
+# CONFIG_AX88180 is not set
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# 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_MII is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_AD9960 is not set
+# CONFIG_SPI_ADC_BF533 is not set
+# CONFIG_BF5xx_PFLAGS is not set
+# CONFIG_BF5xx_PPIFCD is not set
+# CONFIG_BFIN_SIMPLE_TIMER is not set
+# CONFIG_BF5xx_PPI is not set
+CONFIG_BFIN_SPORT=y
+# CONFIG_BFIN_TIMER_LATENCY is not set
+# CONFIG_AD5304 is not set
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_BFIN=y
+CONFIG_SERIAL_BFIN_CONSOLE=y
+CONFIG_SERIAL_BFIN_DMA=y
+# CONFIG_SERIAL_BFIN_PIO is not set
+CONFIG_SERIAL_BFIN_UART0=y
+# CONFIG_BFIN_UART0_CTSRTS is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_BFIN_SPORT is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# CAN, the car bus and industrial fieldbus
+#
+# CONFIG_CAN4LINUX is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_BFIN_WDT is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_GEN_RTC is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BFIN=y
+# CONFIG_SPI_BITBANG is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_SPIDEV is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+# CONFIG_HWMON is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_OTG is not set
+CONFIG_USB_OTG_WHITELIST=y
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_ISP1362_HCD=y
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_MUSB_HDRC 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=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_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
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK 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_ADUTUX 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_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+CONFIG_MMC=m
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=m
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_SPI_MMC=m
+CONFIG_SPI_MMC_FRAMEWORK_DRIVER=y
+# CONFIG_SPI_MMC_BFIN_PIO_SPI is not set
+CONFIG_SPI_MMC_CS_CHAN=5
+CONFIG_SPI_MMC_MAX_HZ=20000000
+# CONFIG_SPI_MMC_CARD_DETECT is not set
+# CONFIG_SPI_MMC_DEBUG_MODE is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_BFIN=y
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# PBX support
+#
+# CONFIG_PBX is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_FS_MBCACHE=y
+# 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_GFS2_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
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_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_YAFFS_FS=y
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# 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 is not set
+# CONFIG_NFSD 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=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# 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
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# 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_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_MMRS is not set
+CONFIG_DEBUG_HUNT_FOR_ZERO=y
+CONFIG_DEBUG_BFIN_HWTRACE_ON=y
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
+# CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
+# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+# CONFIG_EARLY_PRINTK is not set
+CONFIG_CPLB_INFO=y
+CONFIG_ACCESS_CHECK=y
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+CONFIG_SECURITY=y
+# CONFIG_SECURITY_NETWORK is not set
+CONFIG_SECURITY_CAPABILITIES=m
+# CONFIG_SECURITY_ROOTPLUG is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/blackfin/configs/PNAV-10_defconfig b/arch/blackfin/configs/PNAV-10_defconfig
index 25709f5..87622ad 100644
--- a/arch/blackfin/configs/PNAV-10_defconfig
+++ b/arch/blackfin/configs/PNAV-10_defconfig
@@ -13,7 +13,7 @@
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
-# CONFIG_GENERIC_TIME is not set
+CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_GPIO=y
 CONFIG_FORCE_MAX_ZONEORDER=14
 CONFIG_GENERIC_CALIBRATE_DELAY=y
@@ -214,7 +214,7 @@
 #
 # Memory Setup
 #
-CONFIG_MEM_SIZE=64
+CONFIG_MAX_MEM_SIZE=64
 CONFIG_MEM_ADD_WIDTH=10
 CONFIG_BOOT_LOAD=0x1000
 CONFIG_BFIN_SCRATCH_REG_RETN=y
diff --git a/arch/blackfin/configs/SRV1_defconfig b/arch/blackfin/configs/SRV1_defconfig
new file mode 100644
index 0000000..951ea04
--- /dev/null
+++ b/arch/blackfin/configs/SRV1_defconfig
@@ -0,0 +1,1290 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.22.10
+# Fri Nov  2 20:50:23 2007
+#
+# CONFIG_MMU is not set
+# CONFIG_FPU is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_BLACKFIN=y
+CONFIG_ZONE_DMA=y
+CONFIG_BFIN=y
+CONFIG_SEMAPHORE_SLEEPERS=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+# CONFIG_GENERIC_TIME is not set
+CONFIG_GENERIC_GPIO=y
+CONFIG_FORCE_MAX_ZONEORDER=14
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_IRQCHIP_DEMUX_GPIO=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=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_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_BIG_ORDER_ALLOC_NOFAIL_MAGIC=3
+# CONFIG_NP2 is not set
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+# CONFIG_IOSCHED_DEADLINE is not set
+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_PREEMPT_NONE is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+# CONFIG_PREEMPT is not set
+
+#
+# Blackfin Processor Options
+#
+
+#
+# Processor and Board Settings
+#
+# CONFIG_BF522 is not set
+# CONFIG_BF525 is not set
+# CONFIG_BF527 is not set
+# CONFIG_BF531 is not set
+# CONFIG_BF532 is not set
+# CONFIG_BF533 is not set
+# CONFIG_BF534 is not set
+# CONFIG_BF536 is not set
+CONFIG_BF537=y
+# CONFIG_BF542 is not set
+# CONFIG_BF544 is not set
+# CONFIG_BF548 is not set
+# CONFIG_BF549 is not set
+# CONFIG_BF561 is not set
+# CONFIG_BF_REV_0_0 is not set
+# CONFIG_BF_REV_0_1 is not set
+CONFIG_BF_REV_0_2=y
+# CONFIG_BF_REV_0_3 is not set
+# CONFIG_BF_REV_0_4 is not set
+# CONFIG_BF_REV_0_5 is not set
+# CONFIG_BF_REV_ANY is not set
+# CONFIG_BF_REV_NONE is not set
+CONFIG_BF53x=y
+CONFIG_BFIN_SINGLE_CORE=y
+# CONFIG_BFIN527_EZKIT is not set
+# CONFIG_BFIN533_EZKIT is not set
+# CONFIG_BFIN533_STAMP is not set
+# CONFIG_BFIN537_STAMP is not set
+# CONFIG_CAMSIG_MINOTAUR is not set
+# CONFIG_BFIN533_BLUETECHNIX_CM is not set
+# CONFIG_BFIN537_BLUETECHNIX_CM is not set
+# CONFIG_BFIN548_EZKIT is not set
+# CONFIG_BFIN561_BLUETECHNIX_CM is not set
+# CONFIG_BFIN561_EZKIT is not set
+# CONFIG_BFIN561_TEPLA is not set
+# CONFIG_PNAV10 is not set
+# CONFIG_VISTASCAN is not set
+# CONFIG_BFIN533_SR3K is not set
+CONFIG_GENERIC_BOARD=y
+CONFIG_MEM_GENERIC_BOARD=y
+CONFIG_IRQ_PLL_WAKEUP=7
+CONFIG_IRQ_RTC=8
+CONFIG_IRQ_PPI=8
+CONFIG_IRQ_SPORT0_RX=9
+CONFIG_IRQ_SPORT0_TX=9
+CONFIG_IRQ_SPORT1_RX=9
+CONFIG_IRQ_SPORT1_TX=9
+CONFIG_IRQ_TWI=10
+CONFIG_IRQ_SPI=10
+CONFIG_IRQ_UART0_RX=10
+CONFIG_IRQ_UART0_TX=10
+CONFIG_IRQ_UART1_RX=10
+CONFIG_IRQ_UART1_TX=10
+CONFIG_IRQ_MAC_RX=11
+CONFIG_IRQ_MAC_TX=11
+CONFIG_IRQ_TMR0=12
+CONFIG_IRQ_TMR1=12
+CONFIG_IRQ_TMR2=12
+CONFIG_IRQ_TMR3=12
+CONFIG_IRQ_TMR4=12
+CONFIG_IRQ_TMR5=12
+CONFIG_IRQ_TMR6=12
+CONFIG_IRQ_TMR7=12
+CONFIG_IRQ_PORTG_INTB=12
+CONFIG_IRQ_MEM_DMA0=13
+CONFIG_IRQ_MEM_DMA1=13
+CONFIG_IRQ_WATCH=13
+
+#
+# BF537 Specific Configuration
+#
+
+#
+# Interrupt Priority Assignment
+#
+
+#
+# Priority
+#
+CONFIG_IRQ_DMA_ERROR=7
+CONFIG_IRQ_ERROR=7
+CONFIG_IRQ_CAN_RX=11
+CONFIG_IRQ_CAN_TX=11
+CONFIG_IRQ_PROG_INTA=12
+
+#
+# Board customizations
+#
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Clock/PLL Setup
+#
+CONFIG_CLKIN_HZ=22118400
+# CONFIG_BFIN_KERNEL_CLOCK is not set
+CONFIG_MAX_VCO_HZ=600000000
+CONFIG_MIN_VCO_HZ=50000000
+CONFIG_MAX_SCLK_HZ=133000000
+CONFIG_MIN_SCLK_HZ=27000000
+
+#
+# Kernel Timer/Scheduler
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+
+#
+# Memory Setup
+#
+CONFIG_MAX_MEM_SIZE=32
+CONFIG_MEM_ADD_WIDTH=9
+CONFIG_BOOT_LOAD=0x400000
+CONFIG_BFIN_SCRATCH_REG_RETN=y
+# CONFIG_BFIN_SCRATCH_REG_RETE is not set
+# CONFIG_BFIN_SCRATCH_REG_CYCLES is not set
+
+#
+# Blackfin Kernel Optimizations
+#
+
+#
+# Memory Optimizations
+#
+CONFIG_I_ENTRY_L1=y
+CONFIG_EXCPT_IRQ_SYSC_L1=y
+CONFIG_DO_IRQ_L1=y
+CONFIG_CORE_TIMER_IRQ_L1=y
+CONFIG_IDLE_L1=y
+CONFIG_SCHEDULE_L1=y
+CONFIG_ARITHMETIC_OPS_L1=y
+CONFIG_ACCESS_OK_L1=y
+CONFIG_MEMSET_L1=y
+CONFIG_MEMCPY_L1=y
+CONFIG_SYS_BFIN_SPINLOCK_L1=y
+# CONFIG_IP_CHECKSUM_L1 is not set
+CONFIG_CACHELINE_ALIGNED_L1=y
+# CONFIG_SYSCALL_TAB_L1 is not set
+# CONFIG_CPLB_SWITCH_TAB_L1 is not set
+CONFIG_RAMKERNEL=y
+# CONFIG_ROMKERNEL is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_LARGE_ALLOCS=y
+CONFIG_BFIN_DMA_5XX=y
+CONFIG_DMA_UNCACHED_2M=y
+# CONFIG_DMA_UNCACHED_1M is not set
+# CONFIG_DMA_UNCACHED_NONE is not set
+
+#
+# Cache Support
+#
+CONFIG_BFIN_ICACHE=y
+CONFIG_BFIN_DCACHE=y
+# CONFIG_BFIN_DCACHE_BANKA is not set
+# CONFIG_BFIN_ICACHE_LOCK is not set
+# CONFIG_BFIN_WB is not set
+CONFIG_BFIN_WT=y
+CONFIG_L1_MAX_PIECE=16
+
+#
+# Asynchonous Memory Configuration
+#
+
+#
+# EBIU_AMGCTL Global Control
+#
+CONFIG_C_AMCKEN=y
+CONFIG_C_CDPRIO=y
+# CONFIG_C_AMBEN is not set
+# CONFIG_C_AMBEN_B0 is not set
+# CONFIG_C_AMBEN_B0_B1 is not set
+# CONFIG_C_AMBEN_B0_B1_B2 is not set
+CONFIG_C_AMBEN_ALL=y
+
+#
+# EBIU_AMBCTL Control
+#
+CONFIG_BANK_0=0x7BB0
+CONFIG_BANK_1=0x7BB0
+CONFIG_BANK_2=0x7BB0
+CONFIG_BANK_3=0x99B3
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_PCI is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF_FDPIC=y
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_ZFLAT=y
+# CONFIG_BINFMT_SHARED_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_LEGACY is not set
+# CONFIG_PM_DEBUG is not set
+# CONFIG_PM_SYSFS_DEPRECATED is not set
+CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR=y
+# CONFIG_PM_WAKEUP_BY_GPIO is not set
+# CONFIG_PM_WAKEUP_GPIO_API is not set
+CONFIG_PM_WAKEUP_SIC_IWR=0x80000000
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# 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=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE 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_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETLABEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# 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_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=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRCOMM=m
+# CONFIG_IRDA_ULTRA is not set
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+# CONFIG_IRDA_FAST_RR is not set
+# CONFIG_IRDA_DEBUG is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+CONFIG_IRTTY_SIR=m
+
+#
+# Dongle support
+#
+# CONFIG_DONGLE is not set
+
+#
+# Old SIR device drivers
+#
+# CONFIG_IRPORT_SIR is not set
+
+#
+# Old Serial dongle support
+#
+
+#
+# FIR device drivers
+#
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+CONFIG_MTD_JEDECPROBE=m
+CONFIG_MTD_GEN_PROBE=m
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_MW320D=m
+CONFIG_MTD_RAM=y
+CONFIG_MTD_ROM=m
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_BF5xx=m
+CONFIG_BFIN_FLASH_SIZE=0x400000
+CONFIG_EBIU_FLASH_BASE=0x20000000
+CONFIG_MTD_UCLINUX=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=m
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_BFIN=m
+CONFIG_BFIN_NAND_BASE=0x20212000
+CONFIG_BFIN_NAND_CLE=2
+CONFIG_BFIN_NAND_ALE=1
+CONFIG_BFIN_NAND_READY=3
+CONFIG_MTD_NAND_IDS=m
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNPACPI is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=m
+# 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_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+CONFIG_INPUT_UINPUT=y
+# CONFIG_BF53X_PFBUTTONS is not set
+# CONFIG_TWI_KEYPAD is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_AD9960 is not set
+# CONFIG_SPI_ADC_BF533 is not set
+CONFIG_BF5xx_PFLAGS=y
+# CONFIG_BF5xx_PFLAGS_PROC is not set
+# CONFIG_BF5xx_PPIFCD is not set
+# CONFIG_BF5xx_TIMERS is not set
+# CONFIG_BF5xx_PPI is not set
+# CONFIG_BFIN_SPORT is not set
+# CONFIG_BFIN_TIMER_LATENCY is not set
+# CONFIG_TWI_LCD is not set
+# CONFIG_AD5304 is not set
+# CONFIG_BF5xx_TEA5764 is not set
+# CONFIG_BF5xx_FBDMA is not set
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_BFIN=y
+CONFIG_SERIAL_BFIN_CONSOLE=y
+CONFIG_SERIAL_BFIN_DMA=y
+# CONFIG_SERIAL_BFIN_PIO is not set
+CONFIG_SERIAL_BFIN_UART0=y
+# CONFIG_BFIN_UART0_CTSRTS is not set
+# CONFIG_SERIAL_BFIN_UART1 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_BFIN_SPORT is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# CAN, the car bus and industrial fieldbus
+#
+# CONFIG_CAN4LINUX is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_BFIN_WDT=y
+CONFIG_HW_RANDOM=m
+# CONFIG_GEN_RTC is not set
+CONFIG_BLACKFIN_DPMC=y
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_BLACKFIN_GPIO is not set
+CONFIG_I2C_BLACKFIN_TWI=y
+CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=50
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_AD5252 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8575 is not set
+# CONFIG_SENSORS_PCA9543 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BFIN=y
+# CONFIG_SPI_BITBANG is not set
+
+#
+# SPI Protocol Masters
+#
+CONFIG_SPI_AT25=m
+# CONFIG_SPI_SPIDEV is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+CONFIG_HWMON=m
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 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_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+# CONFIG_VIDEO_V4L1 is not set
+CONFIG_VIDEO_V4L1_COMPAT=y
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set
+
+#
+# Encoders/decoders and other helper chips
+#
+
+#
+# Audio decoders
+#
+# CONFIG_VIDEO_TDA9840 is not set
+# CONFIG_VIDEO_TEA6415C is not set
+# CONFIG_VIDEO_TEA6420 is not set
+# CONFIG_VIDEO_MSP3400 is not set
+# CONFIG_VIDEO_CS53L32A is not set
+# CONFIG_VIDEO_TLV320AIC23B is not set
+# CONFIG_VIDEO_WM8775 is not set
+# CONFIG_VIDEO_WM8739 is not set
+
+#
+# Video decoders
+#
+# CONFIG_VIDEO_OV7670 is not set
+# CONFIG_VIDEO_SAA711X is not set
+# CONFIG_VIDEO_TVP5150 is not set
+
+#
+# Video and audio decoders
+#
+# CONFIG_VIDEO_CX25840 is not set
+
+#
+# MPEG video encoders
+#
+# CONFIG_VIDEO_CX2341X is not set
+
+#
+# Video encoders
+#
+# CONFIG_VIDEO_SAA7127 is not set
+
+#
+# Video improvement chips
+#
+# CONFIG_VIDEO_UPD64031A is not set
+# CONFIG_VIDEO_UPD64083 is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_VIDEO_PPI_GENERIC is not set
+CONFIG_VIDEO_BLACKFIN_CAM=m
+# CONFIG_VIDEO_BLACKFIN_MT9M001 is not set
+
+#
+# CMOS Camera Sensor Selection
+#
+# CONFIG_MT9V022 is not set
+# CONFIG_MT9M001 is not set
+# CONFIG_VS6524 is not set
+# CONFIG_VS6624 is not set
+CONFIG_OV9655=y
+# CONFIG_RADIO_ADAPTERS is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# HID Devices
+#
+# CONFIG_HID is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+
+#
+# Enable Host or Gadget support to see Inventra options
+#
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# PBX support
+#
+# CONFIG_PBX is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_FS_MBCACHE=y
+# 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_GFS2_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
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# 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_SYSCTL=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_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_YAFFS_FS=m
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# 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=m
+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_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+# CONFIG_SUNRPC_BIND34 is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT 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=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+# 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_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# 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 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# 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_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_FRAME_POINTER is not set
+# CONFIG_FORCED_INLINING is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_DEBUG_MMRS is not set
+# CONFIG_DEBUG_HWERR is not set
+CONFIG_DEBUG_HUNT_FOR_ZERO=y
+CONFIG_DEBUG_BFIN_HWTRACE_ON=y
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
+# CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
+# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+# CONFIG_EARLY_PRINTK is not set
+CONFIG_CPLB_INFO=y
+CONFIG_ACCESS_CHECK=y
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+CONFIG_SECURITY=y
+# CONFIG_SECURITY_NETWORK is not set
+CONFIG_SECURITY_CAPABILITIES=y
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile
index 318b9b6..6140cd6 100644
--- a/arch/blackfin/kernel/Makefile
+++ b/arch/blackfin/kernel/Makefile
@@ -6,9 +6,15 @@
 
 obj-y := \
 	entry.o process.o bfin_ksyms.o ptrace.o setup.o signal.o \
-	sys_bfin.o time.o traps.o irqchip.o dma-mapping.o flat.o \
+	sys_bfin.o traps.o irqchip.o dma-mapping.o flat.o \
 	fixed_code.o reboot.o bfin_gpio.o
 
+ifeq ($(CONFIG_GENERIC_CLOCKEVENTS),y)
+    obj-y += time-ts.o
+else
+    obj-y += time.o
+endif
+
 obj-$(CONFIG_BFIN_GPTIMERS)          += gptimers.o
 obj-$(CONFIG_MODULES)                += module.o
 obj-$(CONFIG_BFIN_DMA_5XX)           += bfin_dma_5xx.o
diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c
index 8fd5d22..fd5448d 100644
--- a/arch/blackfin/kernel/bfin_dma_5xx.c
+++ b/arch/blackfin/kernel/bfin_dma_5xx.c
@@ -67,7 +67,7 @@
 
 	for (i = 0; i < MAX_BLACKFIN_DMA_CHANNEL; i++) {
 		dma_ch[i].chan_status = DMA_CHANNEL_FREE;
-		dma_ch[i].regs = base_addr[i];
+		dma_ch[i].regs = dma_io_base_addr[i];
 		mutex_init(&(dma_ch[i].dmalock));
 	}
 	/* Mark MEMDMA Channel 0 as requested since we're using it internally */
@@ -106,12 +106,15 @@
 
 #ifdef CONFIG_BF54x
 	if (channel >= CH_UART2_RX && channel <= CH_UART3_TX) {
-		if (strncmp(device_id, "BFIN_UART", 9) == 0)
+		if (strncmp(device_id, "BFIN_UART", 9) == 0) {
+			dma_ch[channel].regs->peripheral_map &= 0x0FFF;
 			dma_ch[channel].regs->peripheral_map |=
-				(channel - CH_UART2_RX + 0xC);
-		else
+				((channel - CH_UART2_RX + 0xC)<<12);
+		} else {
+			dma_ch[channel].regs->peripheral_map &= 0x0FFF;
 			dma_ch[channel].regs->peripheral_map |=
-				(channel - CH_UART2_RX + 0x6);
+				((channel - CH_UART2_RX + 0x6)<<12);
+		}
 	}
 #endif
 
diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c
index 08788f7..7e8eaf4 100644
--- a/arch/blackfin/kernel/bfin_gpio.c
+++ b/arch/blackfin/kernel/bfin_gpio.c
@@ -95,14 +95,14 @@
 	AWA_data_clear = SYSCR,
 	AWA_data_set = SYSCR,
 	AWA_toggle = SYSCR,
-	AWA_maska = UART_SCR,
-	AWA_maska_clear = UART_SCR,
-	AWA_maska_set = UART_SCR,
-	AWA_maska_toggle = UART_SCR,
-	AWA_maskb = UART_GCTL,
-	AWA_maskb_clear = UART_GCTL,
-	AWA_maskb_set = UART_GCTL,
-	AWA_maskb_toggle = UART_GCTL,
+	AWA_maska = BFIN_UART_SCR,
+	AWA_maska_clear = BFIN_UART_SCR,
+	AWA_maska_set = BFIN_UART_SCR,
+	AWA_maska_toggle = BFIN_UART_SCR,
+	AWA_maskb = BFIN_UART_GCTL,
+	AWA_maskb_clear = BFIN_UART_GCTL,
+	AWA_maskb_set = BFIN_UART_GCTL,
+	AWA_maskb_toggle = BFIN_UART_GCTL,
 	AWA_dir = SPORT1_STAT,
 	AWA_polar = SPORT1_STAT,
 	AWA_edge = SPORT1_STAT,
@@ -348,11 +348,10 @@
 			offset = port_mux_lut[y].offset;
 			muxreg = bfin_read_PORT_MUX();
 
-			if (offset != 1) {
+			if (offset != 1)
 				muxreg &= ~(1 << offset);
-			} else {
+			else
 				muxreg &= ~(3 << 1);
-			}
 
 			muxreg |= (function << offset);
 			bfin_write_PORT_MUX(muxreg);
@@ -396,39 +395,11 @@
 # define portmux_setup(...)  do { } while (0)
 #endif
 
-#ifndef BF548_FAMILY
-static void default_gpio(unsigned gpio)
-{
-	unsigned short bank, bitmask;
-	unsigned long flags;
-
-	bank = gpio_bank(gpio);
-	bitmask = gpio_bit(gpio);
-
-	local_irq_save(flags);
-
-	gpio_bankb[bank]->maska_clear = bitmask;
-	gpio_bankb[bank]->maskb_clear = bitmask;
-	SSYNC();
-	gpio_bankb[bank]->inen &= ~bitmask;
-	gpio_bankb[bank]->dir &= ~bitmask;
-	gpio_bankb[bank]->polar &= ~bitmask;
-	gpio_bankb[bank]->both &= ~bitmask;
-	gpio_bankb[bank]->edge &= ~bitmask;
-	AWA_DUMMY_READ(edge);
-	local_irq_restore(flags);
-}
-#else
-# define default_gpio(...)  do { } while (0)
-#endif
-
 static int __init bfin_gpio_init(void)
 {
-
 	printk(KERN_INFO "Blackfin GPIO Controller\n");
 
 	return 0;
-
 }
 arch_initcall(bfin_gpio_init);
 
@@ -821,10 +792,10 @@
 	local_irq_save(flags);
 
 	if (unlikely(reserved_gpio_map[gpio_bank(ident)] & gpio_bit(ident))) {
+		dump_stack();
 		printk(KERN_ERR
 		    "%s: Peripheral %d is already reserved as GPIO by %s !\n",
-		       __FUNCTION__, ident, get_label(ident));
-		dump_stack();
+		       __func__, ident, get_label(ident));
 		local_irq_restore(flags);
 		return -EBUSY;
 	}
@@ -833,31 +804,31 @@
 
 		u16 funct = get_portmux(ident);
 
-	/*
-	 * Pin functions like AMC address strobes my
-	 * be requested and used by several drivers
-	 */
+		/*
+		 * Pin functions like AMC address strobes my
+		 * be requested and used by several drivers
+		 */
 
 		if (!((per & P_MAYSHARE) && (funct == P_FUNCT2MUX(per)))) {
 
-		/*
-		 * Allow that the identical pin function can
-		 * be requested from the same driver twice
-		 */
+			/*
+			 * Allow that the identical pin function can
+			 * be requested from the same driver twice
+			 */
 
-		if (cmp_label(ident, label) == 0)
-			goto anyway;
+			if (cmp_label(ident, label) == 0)
+				goto anyway;
 
+			dump_stack();
 			printk(KERN_ERR
 			       "%s: Peripheral %d function %d is already reserved by %s !\n",
-			       __FUNCTION__, ident, P_FUNCT2MUX(per), get_label(ident));
-			dump_stack();
+			       __func__, ident, P_FUNCT2MUX(per), get_label(ident));
 			local_irq_restore(flags);
 			return -EBUSY;
 		}
 	}
 
-anyway:
+ anyway:
 	reserved_peri_map[gpio_bank(ident)] |= gpio_bit(ident);
 
 	portmux_setup(ident, P_FUNCT2MUX(per));
@@ -890,47 +861,47 @@
 
 	if (!check_gpio(ident)) {
 
-	if (unlikely(reserved_gpio_map[gpio_bank(ident)] & gpio_bit(ident))) {
-		printk(KERN_ERR
-		       "%s: Peripheral %d is already reserved as GPIO by %s !\n",
-		       __FUNCTION__, ident, get_label(ident));
-		dump_stack();
-		local_irq_restore(flags);
-		return -EBUSY;
-	}
-
-	}
-
-	if (unlikely(reserved_peri_map[gpio_bank(ident)] & gpio_bit(ident))) {
-
-	/*
-	 * Pin functions like AMC address strobes my
-	 * be requested and used by several drivers
-	 */
-
-	if (!(per & P_MAYSHARE)) {
-
-	/*
-	 * Allow that the identical pin function can
-	 * be requested from the same driver twice
-	 */
-
-		if (cmp_label(ident, label) == 0)
-			goto anyway;
-
-			printk(KERN_ERR
-			       "%s: Peripheral %d function %d is already"
-			       " reserved by %s !\n",
-			       __FUNCTION__, ident, P_FUNCT2MUX(per),
-				get_label(ident));
+		if (unlikely(reserved_gpio_map[gpio_bank(ident)] & gpio_bit(ident))) {
 			dump_stack();
+			printk(KERN_ERR
+			       "%s: Peripheral %d is already reserved as GPIO by %s !\n",
+			       __func__, ident, get_label(ident));
 			local_irq_restore(flags);
 			return -EBUSY;
 		}
 
 	}
 
-anyway:
+	if (unlikely(reserved_peri_map[gpio_bank(ident)] & gpio_bit(ident))) {
+
+		/*
+		 * Pin functions like AMC address strobes my
+		 * be requested and used by several drivers
+		 */
+
+		if (!(per & P_MAYSHARE)) {
+
+			/*
+			 * Allow that the identical pin function can
+			 * be requested from the same driver twice
+			 */
+
+			if (cmp_label(ident, label) == 0)
+				goto anyway;
+
+			dump_stack();
+			printk(KERN_ERR
+			       "%s: Peripheral %d function %d is already"
+			       " reserved by %s !\n",
+			       __func__, ident, P_FUNCT2MUX(per),
+				get_label(ident));
+			local_irq_restore(flags);
+			return -EBUSY;
+		}
+
+	}
+
+ anyway:
 	portmux_setup(per, P_FUNCT2MUX(per));
 
 	port_setup(ident, PERIPHERAL_USAGE);
@@ -944,7 +915,7 @@
 EXPORT_SYMBOL(peripheral_request);
 #endif
 
-int peripheral_request_list(unsigned short per[], const char *label)
+int peripheral_request_list(const unsigned short per[], const char *label)
 {
 	u16 cnt;
 	int ret;
@@ -954,10 +925,10 @@
 		ret = peripheral_request(per[cnt], label);
 
 		if (ret < 0) {
-			for ( ; cnt > 0; cnt--) {
+			for ( ; cnt > 0; cnt--)
 				peripheral_free(per[cnt - 1]);
-			}
-		return ret;
+
+			return ret;
 		}
 	}
 
@@ -981,15 +952,13 @@
 
 	local_irq_save(flags);
 
-	if (unlikely(!(reserved_peri_map[gpio_bank(ident)]
-			 & gpio_bit(ident)))) {
+	if (unlikely(!(reserved_peri_map[gpio_bank(ident)] & gpio_bit(ident)))) {
 		local_irq_restore(flags);
 		return;
 	}
 
-	if (!(per & P_MAYSHARE)) {
+	if (!(per & P_MAYSHARE))
 		port_setup(ident, GPIO_USAGE);
-	}
 
 	reserved_peri_map[gpio_bank(ident)] &= ~gpio_bit(ident);
 
@@ -999,14 +968,11 @@
 }
 EXPORT_SYMBOL(peripheral_free);
 
-void peripheral_free_list(unsigned short per[])
+void peripheral_free_list(const unsigned short per[])
 {
 	u16 cnt;
-
-	for (cnt = 0; per[cnt] != 0; cnt++) {
+	for (cnt = 0; per[cnt] != 0; cnt++)
 		peripheral_free(per[cnt]);
-	}
-
 }
 EXPORT_SYMBOL(peripheral_free_list);
 
@@ -1046,17 +1012,17 @@
 	}
 
 	if (unlikely(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
+		dump_stack();
 		printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved by %s !\n",
 			 gpio, get_label(gpio));
-		dump_stack();
 		local_irq_restore(flags);
 		return -EBUSY;
 	}
 	if (unlikely(reserved_peri_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
+		dump_stack();
 		printk(KERN_ERR
 		       "bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n",
 		       gpio, get_label(gpio));
-		dump_stack();
 		local_irq_restore(flags);
 		return -EBUSY;
 	}
@@ -1082,14 +1048,12 @@
 	local_irq_save(flags);
 
 	if (unlikely(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)))) {
-		gpio_error(gpio);
 		dump_stack();
+		gpio_error(gpio);
 		local_irq_restore(flags);
 		return;
 	}
 
-	default_gpio(gpio);
-
 	reserved_gpio_map[gpio_bank(gpio)] &= ~gpio_bit(gpio);
 
 	set_label(gpio, "free");
@@ -1152,6 +1116,18 @@
 }
 EXPORT_SYMBOL(gpio_get_value);
 
+void bfin_gpio_irq_prepare(unsigned gpio)
+{
+	unsigned long flags;
+
+	port_setup(gpio, GPIO_USAGE);
+
+	local_irq_save(flags);
+	gpio_array[gpio_bank(gpio)]->port_dir_clear = gpio_bit(gpio);
+	gpio_array[gpio_bank(gpio)]->port_inen |= gpio_bit(gpio);
+	local_irq_restore(flags);
+}
+
 #else
 
 int gpio_direction_input(unsigned gpio)
@@ -1218,6 +1194,11 @@
 	udelay(1);
 }
 
+void bfin_gpio_irq_prepare(unsigned gpio)
+{
+	port_setup(gpio, GPIO_USAGE);
+}
+
 #endif /*BF548_FAMILY */
 
 #if defined(CONFIG_PROC_FS)
diff --git a/arch/blackfin/kernel/cplb-mpu/cplbinfo.c b/arch/blackfin/kernel/cplb-mpu/cplbinfo.c
index bd07229..822beef 100644
--- a/arch/blackfin/kernel/cplb-mpu/cplbinfo.c
+++ b/arch/blackfin/kernel/cplb-mpu/cplbinfo.c
@@ -39,14 +39,6 @@
 #include <asm/cplbinit.h>
 #include <asm/blackfin.h>
 
-#define CPLB_I 1
-#define CPLB_D 2
-
-#define SYNC_SYS    SSYNC()
-#define SYNC_CORE   CSYNC()
-
-#define CPLB_BIT_PAGESIZE 0x30000
-
 static char page_size_string_table[][4] = { "1K", "4K", "1M", "4M" };
 
 static char *cplb_print_entry(char *buf, struct cplb_entry *tbl, int switched)
diff --git a/arch/blackfin/kernel/cplb-mpu/cplbinit.c b/arch/blackfin/kernel/cplb-mpu/cplbinit.c
index dc6e8a7..4806010 100644
--- a/arch/blackfin/kernel/cplb-mpu/cplbinit.c
+++ b/arch/blackfin/kernel/cplb-mpu/cplbinit.c
@@ -43,13 +43,15 @@
 	unsigned long d_data, i_data;
 	unsigned long d_cache = 0, i_cache = 0;
 
+	printk(KERN_INFO "MPU: setting up cplb tables with memory protection\n");
+
 #ifdef CONFIG_BFIN_ICACHE
 	i_cache = CPLB_L1_CHBL | ANOMALY_05000158_WORKAROUND;
 #endif
 
 #ifdef CONFIG_BFIN_DCACHE
 	d_cache = CPLB_L1_CHBL;
-#ifdef CONFIG_BLKFIN_WT
+#ifdef CONFIG_BFIN_WT
 	d_cache |= CPLB_L1_AOW | CPLB_WT;
 #endif
 #endif
diff --git a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
index c426a22..99f2831 100644
--- a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
+++ b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
@@ -24,8 +24,6 @@
 #include <asm/cplbinit.h>
 #include <asm/mmu_context.h>
 
-#ifdef CONFIG_BFIN_ICACHE
-
 #define FAULT_RW	(1 << 16)
 #define FAULT_USERSUPV	(1 << 17)
 
@@ -143,30 +141,48 @@
 	unsigned long d_data;
 
 	nr_dcplb_miss++;
-	if (addr >= _ramend)
-		return CPLB_PROT_VIOL;
 
 	d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB;
 #ifdef CONFIG_BFIN_DCACHE
-	d_data |= CPLB_L1_CHBL | ANOMALY_05000158_WORKAROUND;
-#ifdef CONFIG_BLKFIN_WT
-	d_data |= CPLB_L1_AOW | CPLB_WT;
+	if (addr < _ramend - DMA_UNCACHED_REGION ||
+	    (reserved_mem_dcache_on && addr >= _ramend &&
+	     addr < physical_mem_end)) {
+		d_data |= CPLB_L1_CHBL | ANOMALY_05000158_WORKAROUND;
+#ifdef CONFIG_BFIN_WT
+		d_data |= CPLB_L1_AOW | CPLB_WT;
 #endif
-#endif
-	mask = current_rwx_mask;
-	if (mask) {
-		int page = addr >> PAGE_SHIFT;
-		int offs = page >> 5;
-		int bit = 1 << (page & 31);
-
-		if (mask[offs] & bit)
-			d_data |= CPLB_USER_RD;
-
-		mask += page_mask_nelts;
-		if (mask[offs] & bit)
-			d_data |= CPLB_USER_WR;
 	}
+#endif
+	if (addr >= physical_mem_end) {
+		if (addr >= ASYNC_BANK0_BASE && addr < ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE
+		    && (status & FAULT_USERSUPV)) {
+			addr &= ~0x3fffff;
+			d_data &= ~PAGE_SIZE_4KB;
+			d_data |= PAGE_SIZE_4MB;
+		} else if (addr >= BOOT_ROM_START && addr < BOOT_ROM_START + BOOT_ROM_LENGTH
+		    && (status & (FAULT_RW | FAULT_USERSUPV)) == FAULT_USERSUPV) {
+			addr &= ~(1 * 1024 * 1024 - 1);
+			d_data &= ~PAGE_SIZE_4KB;
+			d_data |= PAGE_SIZE_1MB;
+		} else
+			return CPLB_PROT_VIOL;
+	} else if (addr >= _ramend) {
+	    d_data |= CPLB_USER_RD | CPLB_USER_WR;
+	} else {
+		mask = current_rwx_mask;
+		if (mask) {
+			int page = addr >> PAGE_SHIFT;
+			int offs = page >> 5;
+			int bit = 1 << (page & 31);
 
+			if (mask[offs] & bit)
+				d_data |= CPLB_USER_RD;
+
+			mask += page_mask_nelts;
+			if (mask[offs] & bit)
+				d_data |= CPLB_USER_WR;
+		}
+	}
 	idx = evict_one_dcplb();
 
 	addr &= PAGE_MASK;
@@ -189,12 +205,14 @@
 	unsigned long i_data;
 
 	nr_icplb_miss++;
+
+	/* If inside the uncached DMA region, fault.  */
+	if (addr >= _ramend - DMA_UNCACHED_REGION && addr < _ramend)
+		return CPLB_PROT_VIOL;
+
 	if (status & FAULT_USERSUPV)
 		nr_icplb_supv_miss++;
 
-	if (addr >= _ramend)
-		return CPLB_PROT_VIOL;
-
 	/*
 	 * First, try to find a CPLB that matches this address.  If we
 	 * find one, then the fact that we're in the miss handler means
@@ -211,30 +229,48 @@
 	}
 
 	i_data = CPLB_VALID | CPLB_PORTPRIO | PAGE_SIZE_4KB;
+
 #ifdef CONFIG_BFIN_ICACHE
-	i_data |= CPLB_L1_CHBL | ANOMALY_05000158_WORKAROUND;
+	/*
+	 * Normal RAM, and possibly the reserved memory area, are
+	 * cacheable.
+	 */
+	if (addr < _ramend ||
+	    (addr < physical_mem_end && reserved_mem_icache_on))
+		i_data |= CPLB_L1_CHBL | ANOMALY_05000158_WORKAROUND;
 #endif
 
-	/*
-	 * Two cases to distinguish - a supervisor access must necessarily
-	 * be for a module page; we grant it unconditionally (could do better
-	 * here in the future).  Otherwise, check the x bitmap of the current
-	 * process.
-	 */
-	if (!(status & FAULT_USERSUPV)) {
-		unsigned long *mask = current_rwx_mask;
+	if (addr >= physical_mem_end) {
+		if (addr >= BOOT_ROM_START && addr < BOOT_ROM_START + BOOT_ROM_LENGTH
+		    && (status & FAULT_USERSUPV)) {
+			addr &= ~(1 * 1024 * 1024 - 1);
+			i_data &= ~PAGE_SIZE_4KB;
+			i_data |= PAGE_SIZE_1MB;
+		} else
+		    return CPLB_PROT_VIOL;
+	} else if (addr >= _ramend) {
+		i_data |= CPLB_USER_RD;
+	} else {
+		/*
+		 * Two cases to distinguish - a supervisor access must
+		 * necessarily be for a module page; we grant it
+		 * unconditionally (could do better here in the future).
+		 * Otherwise, check the x bitmap of the current process.
+		 */
+		if (!(status & FAULT_USERSUPV)) {
+			unsigned long *mask = current_rwx_mask;
 
-		if (mask) {
-			int page = addr >> PAGE_SHIFT;
-			int offs = page >> 5;
-			int bit = 1 << (page & 31);
+			if (mask) {
+				int page = addr >> PAGE_SHIFT;
+				int offs = page >> 5;
+				int bit = 1 << (page & 31);
 
-			mask += 2 * page_mask_nelts;
-			if (mask[offs] & bit)
-				i_data |= CPLB_USER_RD;
+				mask += 2 * page_mask_nelts;
+				if (mask[offs] & bit)
+					i_data |= CPLB_USER_RD;
+			}
 		}
 	}
-
 	idx = evict_one_icplb();
 	addr &= PAGE_MASK;
 	icplb_tbl[idx].addr = addr;
@@ -250,7 +286,6 @@
 
 static noinline int dcplb_protection_fault(void)
 {
-	unsigned long addr = bfin_read_DCPLB_FAULT_ADDR();
 	int status = bfin_read_DCPLB_STATUS();
 
 	nr_dcplb_prot++;
@@ -280,8 +315,7 @@
 	case 0x26:
 		return dcplb_miss();
 	default:
-	    return 1;
-		panic_cplb_error(seqstat, regs);
+		return 1;
 	}
 }
 
@@ -299,7 +333,7 @@
 	enable_icplb();
 
 	disable_dcplb();
-	for (i = first_mask_dcplb; i < MAX_CPLBS; i++) {
+	for (i = first_switched_dcplb; i < MAX_CPLBS; i++) {
 		dcplb_tbl[i].data = 0;
 		bfin_write32(DCPLB_DATA0 + i * 4, 0);
 	}
@@ -319,7 +353,7 @@
 	d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB;
 #ifdef CONFIG_BFIN_DCACHE
 	d_data |= CPLB_L1_CHBL;
-#ifdef CONFIG_BLKFIN_WT
+#ifdef CONFIG_BFIN_WT
 	d_data |= CPLB_L1_AOW | CPLB_WT;
 #endif
 #endif
@@ -334,5 +368,3 @@
 	}
 	enable_dcplb();
 }
-
-#endif
diff --git a/arch/blackfin/kernel/cplb-nompu/cplbinfo.c b/arch/blackfin/kernel/cplb-nompu/cplbinfo.c
index a4f0b42..1e74f0b 100644
--- a/arch/blackfin/kernel/cplb-nompu/cplbinfo.c
+++ b/arch/blackfin/kernel/cplb-nompu/cplbinfo.c
@@ -33,9 +33,7 @@
 #include <linux/proc_fs.h>
 #include <linux/uaccess.h>
 
-#include <asm/current.h>
-#include <asm/system.h>
-#include <asm/cplb.h>
+#include <asm/cplbinit.h>
 #include <asm/blackfin.h>
 
 #define CPLB_I 1
@@ -174,16 +172,6 @@
 	return len;
 }
 
-static int cplbinfo_write_proc(struct file *file, const char __user *buffer,
-			       unsigned long count, void *data)
-{
-	printk(KERN_INFO "Reset the CPLB swap in/out counts.\n");
-	memset(ipdt_swapcount_table, 0, MAX_SWITCH_I_CPLBS * sizeof(unsigned long));
-	memset(dpdt_swapcount_table, 0, MAX_SWITCH_D_CPLBS * sizeof(unsigned long));
-
-	return count;
-}
-
 static int __init cplbinfo_init(void)
 {
 	struct proc_dir_entry *entry;
@@ -193,7 +181,6 @@
 		return -ENOMEM;
 
 	entry->read_proc = cplbinfo_read_proc;
-	entry->write_proc = cplbinfo_write_proc;
 	entry->data = NULL;
 
 	return 0;
diff --git a/arch/blackfin/kernel/cplb-nompu/cplbinit.c b/arch/blackfin/kernel/cplb-nompu/cplbinit.c
index 6320bc4..917325b 100644
--- a/arch/blackfin/kernel/cplb-nompu/cplbinit.c
+++ b/arch/blackfin/kernel/cplb-nompu/cplbinit.c
@@ -26,6 +26,35 @@
 #include <asm/cplb.h>
 #include <asm/cplbinit.h>
 
+#ifdef CONFIG_MAX_MEM_SIZE
+# define CPLB_MEM CONFIG_MAX_MEM_SIZE
+#else
+# define CPLB_MEM CONFIG_MEM_SIZE
+#endif
+
+/*
+* Number of required data CPLB switchtable entries
+* MEMSIZE / 4 (we mostly install 4M page size CPLBs
+* approx 16 for smaller 1MB page size CPLBs for allignment purposes
+* 1 for L1 Data Memory
+* possibly 1 for L2 Data Memory
+* 1 for CONFIG_DEBUG_HUNT_FOR_ZERO
+* 1 for ASYNC Memory
+*/
+#define MAX_SWITCH_D_CPLBS (((CPLB_MEM / 4) + 16 + 1 + 1 + 1 \
+				 + ASYNC_MEMORY_CPLB_COVERAGE) * 2)
+
+/*
+* Number of required instruction CPLB switchtable entries
+* MEMSIZE / 4 (we mostly install 4M page size CPLBs
+* approx 12 for smaller 1MB page size CPLBs for allignment purposes
+* 1 for L1 Instruction Memory
+* possibly 1 for L2 Instruction Memory
+* 1 for CONFIG_DEBUG_HUNT_FOR_ZERO
+*/
+#define MAX_SWITCH_I_CPLBS (((CPLB_MEM / 4) + 12 + 1 + 1 + 1) * 2)
+
+
 u_long icplb_table[MAX_CPLBS + 1];
 u_long dcplb_table[MAX_CPLBS + 1];
 
@@ -295,6 +324,8 @@
 	struct cplb_tab *t_d = NULL;
 	struct s_cplb cplb;
 
+	printk(KERN_INFO "NOMPU: setting up cplb tables for global access\n");
+
 	cplb.init_i.size = MAX_CPLBS;
 	cplb.init_d.size = MAX_CPLBS;
 	cplb.switch_i.size = MAX_SWITCH_I_CPLBS;
diff --git a/arch/blackfin/kernel/dma-mapping.c b/arch/blackfin/kernel/dma-mapping.c
index d6b61d5..2f62a9f 100644
--- a/arch/blackfin/kernel/dma-mapping.c
+++ b/arch/blackfin/kernel/dma-mapping.c
@@ -59,7 +59,7 @@
 	memset((void *)dma_base, 0, DMA_UNCACHED_REGION);
 	dma_initialized = 1;
 
-	printk(KERN_INFO "%s: dma_page @ 0x%p - %d pages at 0x%08lx\n", __FUNCTION__,
+	printk(KERN_INFO "%s: dma_page @ 0x%p - %d pages at 0x%08lx\n", __func__,
 	       dma_page, dma_pages, dma_base);
 }
 
@@ -100,7 +100,7 @@
 	int i;
 
 	if ((page + pages) > dma_pages) {
-		printk(KERN_ERR "%s: freeing outside range.\n", __FUNCTION__);
+		printk(KERN_ERR "%s: freeing outside range.\n", __func__);
 		BUG();
 	}
 
diff --git a/arch/blackfin/kernel/gptimers.c b/arch/blackfin/kernel/gptimers.c
index 1904d8b..e698554 100644
--- a/arch/blackfin/kernel/gptimers.c
+++ b/arch/blackfin/kernel/gptimers.c
@@ -52,12 +52,14 @@
 	(GPTIMER_timer_regs *)TIMER5_CONFIG,
 	(GPTIMER_timer_regs *)TIMER6_CONFIG,
 	(GPTIMER_timer_regs *)TIMER7_CONFIG,
-#endif
-#if (MAX_BLACKFIN_GPTIMERS > 8)
+# if (MAX_BLACKFIN_GPTIMERS > 8)
 	(GPTIMER_timer_regs *)TIMER8_CONFIG,
 	(GPTIMER_timer_regs *)TIMER9_CONFIG,
 	(GPTIMER_timer_regs *)TIMER10_CONFIG,
+#  if (MAX_BLACKFIN_GPTIMERS > 11)
 	(GPTIMER_timer_regs *)TIMER11_CONFIG,
+#  endif
+# endif
 #endif
 };
 
@@ -80,12 +82,14 @@
 	TIMER_STATUS_TRUN5,
 	TIMER_STATUS_TRUN6,
 	TIMER_STATUS_TRUN7,
-#endif
-#if (MAX_BLACKFIN_GPTIMERS > 8)
+# if (MAX_BLACKFIN_GPTIMERS > 8)
 	TIMER_STATUS_TRUN8,
 	TIMER_STATUS_TRUN9,
 	TIMER_STATUS_TRUN10,
+#  if (MAX_BLACKFIN_GPTIMERS > 11)
 	TIMER_STATUS_TRUN11,
+#  endif
+# endif
 #endif
 };
 
@@ -100,12 +104,14 @@
 	TIMER_STATUS_TOVF5,
 	TIMER_STATUS_TOVF6,
 	TIMER_STATUS_TOVF7,
-#endif
-#if (MAX_BLACKFIN_GPTIMERS > 8)
+# if (MAX_BLACKFIN_GPTIMERS > 8)
 	TIMER_STATUS_TOVF8,
 	TIMER_STATUS_TOVF9,
 	TIMER_STATUS_TOVF10,
+#  if (MAX_BLACKFIN_GPTIMERS > 11)
 	TIMER_STATUS_TOVF11,
+#  endif
+# endif
 #endif
 };
 
@@ -120,12 +126,14 @@
 	TIMER_STATUS_TIMIL5,
 	TIMER_STATUS_TIMIL6,
 	TIMER_STATUS_TIMIL7,
-#endif
-#if (MAX_BLACKFIN_GPTIMERS > 8)
+# if (MAX_BLACKFIN_GPTIMERS > 8)
 	TIMER_STATUS_TIMIL8,
 	TIMER_STATUS_TIMIL9,
 	TIMER_STATUS_TIMIL10,
+#  if (MAX_BLACKFIN_GPTIMERS > 11)
 	TIMER_STATUS_TIMIL11,
+#  endif
+# endif
 #endif
 };
 
diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c
index 6b8459c6..be9fdd0 100644
--- a/arch/blackfin/kernel/process.c
+++ b/arch/blackfin/kernel/process.c
@@ -32,6 +32,8 @@
 #include <linux/unistd.h>
 #include <linux/user.h>
 #include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/tick.h>
 #include <linux/fs.h>
 #include <linux/err.h>
 
@@ -69,33 +71,44 @@
  * The idle loop on BFIN
  */
 #ifdef CONFIG_IDLE_L1
-void default_idle(void)__attribute__((l1_text));
+static void default_idle(void)__attribute__((l1_text));
 void cpu_idle(void)__attribute__((l1_text));
 #endif
 
-void default_idle(void)
+/*
+ * This is our default idle handler.  We need to disable
+ * interrupts here to ensure we don't miss a wakeup call.
+ */
+static void default_idle(void)
 {
-	while (!need_resched()) {
-		local_irq_disable();
-		if (likely(!need_resched()))
-			idle_with_irq_disabled();
-		local_irq_enable();
-	}
+	local_irq_disable();
+	if (!need_resched())
+		idle_with_irq_disabled();
+
+	local_irq_enable();
 }
 
-void (*idle)(void) = default_idle;
-
 /*
- * The idle thread. There's no useful work to be
- * done, so just try to conserve power and have a
- * low exit latency (ie sit in a loop waiting for
- * somebody to say that they'd like to reschedule)
+ * The idle thread.  We try to conserve power, while trying to keep
+ * overall latency low.  The architecture specific idle is passed
+ * a value to indicate the level of "idleness" of the system.
  */
 void cpu_idle(void)
 {
 	/* endless idle loop with no priority at all */
 	while (1) {
-		idle();
+		void (*idle)(void) = pm_idle;
+
+#ifdef CONFIG_HOTPLUG_CPU
+		if (cpu_is_offline(smp_processor_id()))
+			cpu_die();
+#endif
+		if (!idle)
+			idle = default_idle;
+		tick_nohz_stop_sched_tick();
+		while (!need_resched())
+			idle();
+		tick_nohz_restart_sched_tick();
 		preempt_enable_no_resched();
 		schedule();
 		preempt_disable();
@@ -189,7 +202,7 @@
  * sys_execve() executes a new program.
  */
 
-asmlinkage int sys_execve(char *name, char **argv, char **envp)
+asmlinkage int sys_execve(char __user *name, char __user * __user *argv, char __user * __user *envp)
 {
 	int error;
 	char *filename;
@@ -232,23 +245,25 @@
 
 void finish_atomic_sections (struct pt_regs *regs)
 {
+	int __user *up0 = (int __user *)&regs->p0;
+
 	if (regs->pc < ATOMIC_SEQS_START || regs->pc >= ATOMIC_SEQS_END)
 		return;
 
 	switch (regs->pc) {
 	case ATOMIC_XCHG32 + 2:
-		put_user(regs->r1, (int *)regs->p0);
+		put_user(regs->r1, up0);
 		regs->pc += 2;
 		break;
 
 	case ATOMIC_CAS32 + 2:
 	case ATOMIC_CAS32 + 4:
 		if (regs->r0 == regs->r1)
-			put_user(regs->r2, (int *)regs->p0);
+			put_user(regs->r2, up0);
 		regs->pc = ATOMIC_CAS32 + 8;
 		break;
 	case ATOMIC_CAS32 + 6:
-		put_user(regs->r2, (int *)regs->p0);
+		put_user(regs->r2, up0);
 		regs->pc += 2;
 		break;
 
@@ -256,7 +271,7 @@
 		regs->r0 = regs->r1 + regs->r0;
 		/* fall through */
 	case ATOMIC_ADD32 + 4:
-		put_user(regs->r0, (int *)regs->p0);
+		put_user(regs->r0, up0);
 		regs->pc = ATOMIC_ADD32 + 6;
 		break;
 
@@ -264,7 +279,7 @@
 		regs->r0 = regs->r1 - regs->r0;
 		/* fall through */
 	case ATOMIC_SUB32 + 4:
-		put_user(regs->r0, (int *)regs->p0);
+		put_user(regs->r0, up0);
 		regs->pc = ATOMIC_SUB32 + 6;
 		break;
 
@@ -272,7 +287,7 @@
 		regs->r0 = regs->r1 | regs->r0;
 		/* fall through */
 	case ATOMIC_IOR32 + 4:
-		put_user(regs->r0, (int *)regs->p0);
+		put_user(regs->r0, up0);
 		regs->pc = ATOMIC_IOR32 + 6;
 		break;
 
@@ -280,7 +295,7 @@
 		regs->r0 = regs->r1 & regs->r0;
 		/* fall through */
 	case ATOMIC_AND32 + 4:
-		put_user(regs->r0, (int *)regs->p0);
+		put_user(regs->r0, up0);
 		regs->pc = ATOMIC_AND32 + 6;
 		break;
 
@@ -288,7 +303,7 @@
 		regs->r0 = regs->r1 ^ regs->r0;
 		/* fall through */
 	case ATOMIC_XOR32 + 4:
-		put_user(regs->r0, (int *)regs->p0);
+		put_user(regs->r0, up0);
 		regs->pc = ATOMIC_XOR32 + 6;
 		break;
 	}
@@ -309,6 +324,12 @@
 		return 1;
 	if (addr >= memory_mtd_end && (addr + size) <= physical_mem_end)
 		return 1;
+
+#ifdef CONFIG_ROMFS_MTD_FS
+	/* For XIP, allow user space to use pointers within the ROMFS.  */
+	if (addr >= memory_mtd_start && (addr + size) <= memory_mtd_end)
+		return 1;
+#endif
 #else
 	if (addr >= memory_start && (addr + size) <= physical_mem_end)
 		return 1;
diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c
index 85caf9b..b4f062c 100644
--- a/arch/blackfin/kernel/ptrace.c
+++ b/arch/blackfin/kernel/ptrace.c
@@ -193,6 +193,7 @@
 {
 	int ret;
 	int add = 0;
+	unsigned long __user *datap = (unsigned long __user *)data;
 
 	switch (request) {
 		/* when I and D space are separate, these will need to be fixed. */
@@ -229,7 +230,7 @@
 			pr_debug("ptrace: copied size %d [0x%08lx]\n", copied, tmp);
 			if (copied != sizeof(tmp))
 				break;
-			ret = put_user(tmp, (unsigned long *)data);
+			ret = put_user(tmp, datap);
 			break;
 		}
 
@@ -263,7 +264,7 @@
 			} else {
 				tmp = get_reg(child, addr);
 			}
-			ret = put_user(tmp, (unsigned long *)data);
+			ret = put_user(tmp, datap);
 			break;
 		}
 
@@ -389,7 +390,7 @@
 		{
 
 			/* Get all gp regs from the child. */
-			ret = ptrace_getregs(child, (void __user *)data);
+			ret = ptrace_getregs(child, datap);
 			break;
 		}
 
diff --git a/arch/blackfin/kernel/reboot.c b/arch/blackfin/kernel/reboot.c
index 483f93d..367e2dc 100644
--- a/arch/blackfin/kernel/reboot.c
+++ b/arch/blackfin/kernel/reboot.c
@@ -11,45 +11,56 @@
 #include <asm/reboot.h>
 #include <asm/system.h>
 
-#if defined(BF537_FAMILY) || defined(BF533_FAMILY) || defined(BF527_FAMILY)
-#define SYSCR_VAL 	0x0
-#elif defined(BF561_FAMILY)
-#define SYSCR_VAL 	0x20
-#elif defined(BF548_FAMILY)
-#define SYSCR_VAL 	0x10
-#endif
-
-/*
- * Delay min 5 SCLK cycles using worst case CCLK/SCLK ratio (15)
- */
-#define SWRST_DELAY	(5 * 15)
-
-/* A system soft reset makes external memory unusable
- * so force this function into L1.
+/* A system soft reset makes external memory unusable so force
+ * this function into L1.  We use the compiler ssync here rather
+ * than SSYNC() because it's safe (no interrupts and such) and
+ * we save some L1.  We do not need to force sanity in the SYSCR
+ * register as the BMODE selection bit is cleared by the soft
+ * reset while the Core B bit (on dual core parts) is cleared by
+ * the core reset.
  */
 __attribute__((l1_text))
 void bfin_reset(void)
 {
-	/* force BMODE and disable Core B (as needed) */
-	bfin_write_SYSCR(SYSCR_VAL);
-
-	/* we use asm ssync here because it's save and we save some L1 */
-	asm("ssync;");
+	/* Wait for completion of "system" events such as cache line
+	 * line fills so that we avoid infinite stalls later on as
+	 * much as possible.  This code is in L1, so it won't trigger
+	 * any such event after this point in time.
+	 */
+	__builtin_bfin_ssync();
 
 	while (1) {
-		/* initiate system soft reset with magic 0x7 */
+		/* Initiate System software reset. */
 		bfin_write_SWRST(0x7);
 
-		/* Wait for System reset to actually reset, needs to be 5 SCLKs, */
-		/* Assume CCLK / SCLK ratio is worst case (15), and use 5*15     */
+		/* Due to the way reset is handled in the hardware, we need
+		 * to delay for 7 SCLKS.  The only reliable way to do this is
+		 * to calculate the CCLK/SCLK ratio and multiply 7.  For now,
+		 * we'll assume worse case which is a 1:15 ratio.
+		 */
+		asm(
+			"LSETUP (1f, 1f) LC0 = %0\n"
+			"1: nop;"
+			:
+			: "a" (15 * 7)
+			: "LC0", "LB0", "LT0"
+		);
 
-		asm("LSETUP(.Lfoo,.Lfoo) LC0 = %0\n .Lfoo: NOP;\n"
-		 : : "a" (SWRST_DELAY) : "LC0", "LT0", "LB0");
-
-		/* clear system soft reset */
+		/* Clear System software reset */
 		bfin_write_SWRST(0);
-		asm("ssync;");
-		/* issue core reset */
+
+		/* Wait for the SWRST write to complete.  Cannot rely on SSYNC
+		 * though as the System state is all reset now.
+		 */
+		asm(
+			"LSETUP (1f, 1f) LC1 = %0\n"
+			"1: nop;"
+			:
+			: "a" (15 * 1)
+			: "LC1", "LB1", "LT1"
+		);
+
+		/* Issue core reset */
 		asm("raise 1");
 	}
 }
diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c
index 2255c28..8efea004a 100644
--- a/arch/blackfin/kernel/setup.c
+++ b/arch/blackfin/kernel/setup.c
@@ -35,6 +35,7 @@
 EXPORT_SYMBOL(_bfin_swrst);
 
 unsigned long memory_start, memory_end, physical_mem_end;
+unsigned long _rambase, _ramstart, _ramend;
 unsigned long reserved_mem_dcache_on;
 unsigned long reserved_mem_icache_on;
 EXPORT_SYMBOL(memory_start);
@@ -106,7 +107,7 @@
 
 	l1_code_length = _etext_l1 - _stext_l1;
 	if (l1_code_length > L1_CODE_LENGTH)
-		l1_code_length = L1_CODE_LENGTH;
+		panic("L1 Instruction SRAM Overflow\n");
 	/* cannot complain as printk is not available as yet.
 	 * But we can continue booting and complain later!
 	 */
@@ -116,19 +117,18 @@
 
 	l1_data_a_length = _ebss_l1 - _sdata_l1;
 	if (l1_data_a_length > L1_DATA_A_LENGTH)
-		l1_data_a_length = L1_DATA_A_LENGTH;
+		panic("L1 Data SRAM Bank A Overflow\n");
 
 	/* Copy _sdata_l1 to _ebss_l1 to L1 data bank A SRAM */
 	dma_memcpy(_sdata_l1, _l1_lma_start + l1_code_length, l1_data_a_length);
 
 	l1_data_b_length = _ebss_b_l1 - _sdata_b_l1;
 	if (l1_data_b_length > L1_DATA_B_LENGTH)
-		l1_data_b_length = L1_DATA_B_LENGTH;
+		panic("L1 Data SRAM Bank B Overflow\n");
 
 	/* Copy _sdata_b_l1 to _ebss_b_l1 to L1 data bank B SRAM */
 	dma_memcpy(_sdata_b_l1, _l1_lma_start + l1_code_length +
 			l1_data_a_length, l1_data_b_length);
-
 }
 
 /* add_memory_region to memmap */
@@ -547,11 +547,38 @@
 		);
 }
 
+/*
+ * Find the lowest, highest page frame number we have available
+ */
+void __init find_min_max_pfn(void)
+{
+	int i;
+
+	max_pfn = 0;
+	min_low_pfn = memory_end;
+
+	for (i = 0; i < bfin_memmap.nr_map; i++) {
+		unsigned long start, end;
+		/* RAM? */
+		if (bfin_memmap.map[i].type != BFIN_MEMMAP_RAM)
+			continue;
+		start = PFN_UP(bfin_memmap.map[i].addr);
+		end = PFN_DOWN(bfin_memmap.map[i].addr +
+				bfin_memmap.map[i].size);
+		if (start >= end)
+			continue;
+		if (end > max_pfn)
+			max_pfn = end;
+		if (start < min_low_pfn)
+			min_low_pfn = start;
+	}
+}
+
 static __init void setup_bootmem_allocator(void)
 {
 	int bootmap_size;
 	int i;
-	unsigned long min_pfn, max_pfn;
+	unsigned long start_pfn, end_pfn;
 	unsigned long curr_pfn, last_pfn, size;
 
 	/* mark memory between memory_start and memory_end usable */
@@ -561,8 +588,19 @@
 	sanitize_memmap(bfin_memmap.map, &bfin_memmap.nr_map);
 	print_memory_map("boot memmap");
 
-	min_pfn = PAGE_OFFSET >> PAGE_SHIFT;
-	max_pfn = memory_end >> PAGE_SHIFT;
+	/* intialize globals in linux/bootmem.h */
+	find_min_max_pfn();
+	/* pfn of the last usable page frame */
+	if (max_pfn > memory_end >> PAGE_SHIFT)
+		max_pfn = memory_end >> PAGE_SHIFT;
+	/* pfn of last page frame directly mapped by kernel */
+	max_low_pfn = max_pfn;
+	/* pfn of the first usable page frame after kernel image*/
+	if (min_low_pfn < memory_start >> PAGE_SHIFT)
+		min_low_pfn = memory_start >> PAGE_SHIFT;
+
+	start_pfn = PAGE_OFFSET >> PAGE_SHIFT;
+	end_pfn = memory_end >> PAGE_SHIFT;
 
 	/*
 	 * give all the memory to the bootmap allocator,  tell it to put the
@@ -570,7 +608,7 @@
 	 */
 	bootmap_size = init_bootmem_node(NODE_DATA(0),
 			memory_start >> PAGE_SHIFT,	/* map goes here */
-			min_pfn, max_pfn);
+			start_pfn, end_pfn);
 
 	/* register the memmap regions with the bootmem allocator */
 	for (i = 0; i < bfin_memmap.nr_map; i++) {
@@ -583,7 +621,7 @@
 		 * We are rounding up the start address of usable memory:
 		 */
 		curr_pfn = PFN_UP(bfin_memmap.map[i].addr);
-		if (curr_pfn >= max_pfn)
+		if (curr_pfn >= end_pfn)
 			continue;
 		/*
 		 * ... and at the end of the usable range downwards:
@@ -591,8 +629,8 @@
 		last_pfn = PFN_DOWN(bfin_memmap.map[i].addr +
 					 bfin_memmap.map[i].size);
 
-		if (last_pfn > max_pfn)
-			last_pfn = max_pfn;
+		if (last_pfn > end_pfn)
+			last_pfn = end_pfn;
 
 		/*
 		 * .. finally, did all the rounding and playing
@@ -611,9 +649,59 @@
 		BOOTMEM_DEFAULT);
 }
 
+#define EBSZ_TO_MEG(ebsz) \
+({ \
+	int meg = 0; \
+	switch (ebsz & 0xf) { \
+		case 0x1: meg =  16; break; \
+		case 0x3: meg =  32; break; \
+		case 0x5: meg =  64; break; \
+		case 0x7: meg = 128; break; \
+		case 0x9: meg = 256; break; \
+		case 0xb: meg = 512; break; \
+	} \
+	meg; \
+})
+static inline int __init get_mem_size(void)
+{
+#ifdef CONFIG_MEM_SIZE
+	return CONFIG_MEM_SIZE;
+#else
+# if defined(EBIU_SDBCTL)
+#  if defined(BF561_FAMILY)
+	int ret = 0;
+	u32 sdbctl = bfin_read_EBIU_SDBCTL();
+	ret += EBSZ_TO_MEG(sdbctl >>  0);
+	ret += EBSZ_TO_MEG(sdbctl >>  8);
+	ret += EBSZ_TO_MEG(sdbctl >> 16);
+	ret += EBSZ_TO_MEG(sdbctl >> 24);
+	return ret;
+#  else
+	return EBSZ_TO_MEG(bfin_read_EBIU_SDBCTL());
+#  endif
+# elif defined(EBIU_DDRCTL1)
+	u32 ddrctl = bfin_read_EBIU_DDRCTL1();
+	int ret = 0;
+	switch (ddrctl & 0xc0000) {
+		case DEVSZ_64:  ret = 64 / 8;
+		case DEVSZ_128: ret = 128 / 8;
+		case DEVSZ_256: ret = 256 / 8;
+		case DEVSZ_512: ret = 512 / 8;
+	}
+	switch (ddrctl & 0x30000) {
+		case DEVWD_4:  ret *= 2;
+		case DEVWD_8:  ret *= 2;
+		case DEVWD_16: break;
+	}
+	return ret;
+# endif
+#endif
+	BUG();
+}
+
 void __init setup_arch(char **cmdline_p)
 {
-	unsigned long l1_length, sclk, cclk;
+	unsigned long sclk, cclk;
 
 #ifdef CONFIG_DUMMY_CONSOLE
 	conswitchp = &dummy_con;
@@ -631,7 +719,7 @@
 
 	/* setup memory defaults from the user config */
 	physical_mem_end = 0;
-	_ramend = CONFIG_MEM_SIZE * 1024 * 1024;
+	_ramend = get_mem_size() * 1024 * 1024;
 
 	memset(&bfin_memmap, 0, sizeof(bfin_memmap));
 
@@ -712,15 +800,6 @@
 
 	paging_init();
 
-	/* check the size of the l1 area */
-	l1_length = _etext_l1 - _stext_l1;
-	if (l1_length > L1_CODE_LENGTH)
-		panic("L1 code memory overflow\n");
-
-	l1_length = _ebss_l1 - _sdata_l1;
-	if (l1_length > L1_DATA_A_LENGTH)
-		panic("L1 data memory overflow\n");
-
 	/* Copy atomic sequences to their fixed location, and sanity check that
 	   these locations are the ones that we advertise to userspace.  */
 	memcpy((void *)FIXED_CODE_START, &fixed_code_start,
@@ -859,12 +938,17 @@
 	seq_printf(m, "processor\t: %d\n"
 		"vendor_id\t: %s\n"
 		"cpu family\t: 0x%x\n"
-		"model name\t: ADSP-%s %lu(MHz CCLK) %lu(MHz SCLK)\n"
+		"model name\t: ADSP-%s %lu(MHz CCLK) %lu(MHz SCLK) (%s)\n"
 		"stepping\t: %d\n",
 		0,
 		vendor,
 		(bfin_read_CHIPID() & CHIPID_FAMILY),
 		cpu, cclk/1000000, sclk/1000000,
+#ifdef CONFIG_MPU
+		"mpu on",
+#else
+		"mpu off",
+#endif
 		revid);
 
 	seq_printf(m, "cpu MHz\t\t: %lu.%03lu/%lu.%03lu\n",
@@ -973,7 +1057,6 @@
 		seq_printf(m, "No Ways are locked\n");
 	}
 #endif
-
 	seq_printf(m, "board name\t: %s\n", bfin_board_name);
 	seq_printf(m, "board memory\t: %ld kB (0x%p -> 0x%p)\n",
 		 physical_mem_end >> 10, (void *)0, (void *)physical_mem_end);
diff --git a/arch/blackfin/kernel/signal.c b/arch/blackfin/kernel/signal.c
index 5564c95..d1fa244 100644
--- a/arch/blackfin/kernel/signal.c
+++ b/arch/blackfin/kernel/signal.c
@@ -38,6 +38,7 @@
 
 #include <asm/cacheflush.h>
 #include <asm/ucontext.h>
+#include <asm/fixed_code.h>
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
@@ -50,18 +51,20 @@
 	int sig;
 	struct siginfo *pinfo;
 	void *puc;
+	/* This is no longer needed by the kernel, but unfortunately userspace
+	 * code expects it to be there.  */
 	char retcode[8];
 	struct siginfo info;
 	struct ucontext uc;
 };
 
-asmlinkage int sys_sigaltstack(const stack_t * uss, stack_t * uoss)
+asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
 {
 	return do_sigaltstack(uss, uoss, rdusp());
 }
 
 static inline int
-rt_restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *pr0)
+rt_restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *pr0)
 {
 	unsigned long usp = 0;
 	int err = 0;
@@ -159,11 +162,6 @@
 	return err;
 }
 
-static inline void push_cache(unsigned long vaddr, unsigned int len)
-{
-	flush_icache_range(vaddr, vaddr + len);
-}
-
 static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
 				 size_t frame_size)
 {
@@ -209,19 +207,9 @@
 	err |= rt_setup_sigcontext(&frame->uc.uc_mcontext, regs);
 	err |= copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 
-	/* Set up to return from userspace.  */
-	err |= __put_user(0x28, &(frame->retcode[0]));
-	err |= __put_user(0xe1, &(frame->retcode[1]));
-	err |= __put_user(0xad, &(frame->retcode[2]));
-	err |= __put_user(0x00, &(frame->retcode[3]));
-	err |= __put_user(0xa0, &(frame->retcode[4]));
-	err |= __put_user(0x00, &(frame->retcode[5]));
-
 	if (err)
 		goto give_sigsegv;
 
-	push_cache((unsigned long)&frame->retcode, sizeof(frame->retcode));
-
 	/* Set up registers for signal handler */
 	wrusp((unsigned long)frame);
 	if (get_personality & FDPIC_FUNCPTRS) {
@@ -231,7 +219,7 @@
 		__get_user(regs->p3, &funcptr->GOT);
 	} else
 		regs->pc = (unsigned long)ka->sa.sa_handler;
-	regs->rets = (unsigned long)(frame->retcode);
+	regs->rets = SIGRETURN_STUB;
 
 	regs->r0 = frame->sig;
 	regs->r1 = (unsigned long)(&frame->info);
diff --git a/arch/blackfin/kernel/sys_bfin.c b/arch/blackfin/kernel/sys_bfin.c
index abcd148..efb7b25 100644
--- a/arch/blackfin/kernel/sys_bfin.c
+++ b/arch/blackfin/kernel/sys_bfin.c
@@ -49,7 +49,7 @@
  * sys_pipe() is the normal C calling standard for creating
  * a pipe. It's not the way unix traditionally does this, though.
  */
-asmlinkage int sys_pipe(unsigned long *fildes)
+asmlinkage int sys_pipe(unsigned long __user *fildes)
 {
 	int fd[2];
 	int error;
diff --git a/arch/blackfin/kernel/time-ts.c b/arch/blackfin/kernel/time-ts.c
new file mode 100644
index 0000000..4482c47
--- /dev/null
+++ b/arch/blackfin/kernel/time-ts.c
@@ -0,0 +1,219 @@
+/*
+ * linux/arch/kernel/time-ts.c
+ *
+ * Based on arm clockevents implementation and old bfin time tick.
+ *
+ * Copyright(C) 2008, GeoTechnologies, Vitja Makarov
+ *
+ * This code is licenced under the GPL version 2. For details see
+ * kernel-base/COPYING.
+ */
+#include <linux/module.h>
+#include <linux/profile.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/timex.h>
+#include <linux/irq.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/cpufreq.h>
+
+#include <asm/blackfin.h>
+#include <asm/time.h>
+
+#ifdef CONFIG_CYCLES_CLOCKSOURCE
+
+/* Accelerators for sched_clock()
+ * convert from cycles(64bits) => nanoseconds (64bits)
+ *  basic equation:
+ *		ns = cycles / (freq / ns_per_sec)
+ *		ns = cycles * (ns_per_sec / freq)
+ *		ns = cycles * (10^9 / (cpu_khz * 10^3))
+ *		ns = cycles * (10^6 / cpu_khz)
+ *
+ *	Then we use scaling math (suggested by george@mvista.com) to get:
+ *		ns = cycles * (10^6 * SC / cpu_khz) / SC
+ *		ns = cycles * cyc2ns_scale / SC
+ *
+ *	And since SC is a constant power of two, we can convert the div
+ *  into a shift.
+ *
+ *  We can use khz divisor instead of mhz to keep a better precision, since
+ *  cyc2ns_scale is limited to 10^6 * 2^10, which fits in 32 bits.
+ *  (mathieu.desnoyers@polymtl.ca)
+ *
+ *			-johnstul@us.ibm.com "math is hard, lets go shopping!"
+ */
+
+static unsigned long cyc2ns_scale;
+#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
+
+static inline void set_cyc2ns_scale(unsigned long cpu_khz)
+{
+	cyc2ns_scale = (1000000 << CYC2NS_SCALE_FACTOR) / cpu_khz;
+}
+
+static inline unsigned long long cycles_2_ns(cycle_t cyc)
+{
+	return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
+}
+
+static cycle_t read_cycles(void)
+{
+	return get_cycles();
+}
+
+unsigned long long sched_clock(void)
+{
+	return cycles_2_ns(read_cycles());
+}
+
+static struct clocksource clocksource_bfin = {
+	.name		= "bfin_cycles",
+	.rating		= 350,
+	.read		= read_cycles,
+	.mask		= CLOCKSOURCE_MASK(64),
+	.shift		= 22,
+	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static int __init bfin_clocksource_init(void)
+{
+	set_cyc2ns_scale(get_cclk() / 1000);
+
+	clocksource_bfin.mult = clocksource_hz2mult(get_cclk(), clocksource_bfin.shift);
+
+	if (clocksource_register(&clocksource_bfin))
+		panic("failed to register clocksource");
+
+	return 0;
+}
+
+#else
+# define bfin_clocksource_init()
+#endif
+
+static int bfin_timer_set_next_event(unsigned long cycles,
+                                     struct clock_event_device *evt)
+{
+	bfin_write_TCOUNT(cycles);
+	CSYNC();
+	return 0;
+}
+
+static void bfin_timer_set_mode(enum clock_event_mode mode,
+                                struct clock_event_device *evt)
+{
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC: {
+		unsigned long tcount = ((get_cclk() / (HZ * TIME_SCALE)) - 1);
+		bfin_write_TCNTL(TMPWR);
+		bfin_write_TSCALE(TIME_SCALE - 1);
+		CSYNC();
+		bfin_write_TPERIOD(tcount);
+		bfin_write_TCOUNT(tcount);
+		bfin_write_TCNTL(TMPWR | TMREN | TAUTORLD);
+		CSYNC();
+		break;
+	}
+	case CLOCK_EVT_MODE_ONESHOT:
+		bfin_write_TSCALE(0);
+		bfin_write_TCOUNT(0);
+		bfin_write_TCNTL(TMPWR | TMREN);
+		CSYNC();
+		break;
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		bfin_write_TCNTL(0);
+		CSYNC();
+		break;
+	case CLOCK_EVT_MODE_RESUME:
+		break;
+	}
+}
+
+static void __init bfin_timer_init(void)
+{
+	/* power up the timer, but don't enable it just yet */
+	bfin_write_TCNTL(TMPWR);
+	CSYNC();
+
+	/*
+	 * the TSCALE prescaler counter.
+	 */
+	bfin_write_TSCALE(TIME_SCALE - 1);
+	bfin_write_TPERIOD(0);
+	bfin_write_TCOUNT(0);
+
+	/* now enable the timer */
+	CSYNC();
+}
+
+/*
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ */
+#ifdef CONFIG_CORE_TIMER_IRQ_L1
+__attribute__((l1_text))
+#endif
+irqreturn_t timer_interrupt(int irq, void *dev_id);
+
+static struct clock_event_device clockevent_bfin = {
+	.name		= "bfin_core_timer",
+	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+	.shift		= 32,
+	.cpumask	= CPU_MASK_CPU0,
+	.set_next_event = bfin_timer_set_next_event,
+	.set_mode	= bfin_timer_set_mode,
+};
+
+static struct irqaction bfin_timer_irq = {
+	.name		= "Blackfin Core Timer",
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+	.handler	= timer_interrupt,
+	.dev_id		= &clockevent_bfin,
+};
+
+irqreturn_t timer_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *evt = dev_id;
+	evt->event_handler(evt);
+	return IRQ_HANDLED;
+}
+
+static int __init bfin_clockevent_init(void)
+{
+	setup_irq(IRQ_CORETMR, &bfin_timer_irq);
+	bfin_timer_init();
+
+	clockevent_bfin.mult = div_sc(get_cclk(), NSEC_PER_SEC, clockevent_bfin.shift);
+	clockevent_bfin.max_delta_ns = clockevent_delta2ns(-1, &clockevent_bfin);
+	clockevent_bfin.min_delta_ns = clockevent_delta2ns(100, &clockevent_bfin);
+	clockevents_register_device(&clockevent_bfin);
+
+	return 0;
+}
+
+void __init time_init(void)
+{
+	time_t secs_since_1970 = (365 * 37 + 9) * 24 * 60 * 60;	/* 1 Jan 2007 */
+
+#ifdef CONFIG_RTC_DRV_BFIN
+	/* [#2663] hack to filter junk RTC values that would cause
+	 * userspace to have to deal with time values greater than
+	 * 2^31 seconds (which uClibc cannot cope with yet)
+	 */
+	if ((bfin_read_RTC_STAT() & 0xC0000000) == 0xC0000000) {
+		printk(KERN_NOTICE "bfin-rtc: invalid date; resetting\n");
+		bfin_write_RTC_STAT(0);
+	}
+#endif
+
+	/* Initialize xtime. From now on, xtime is updated with timer interrupts */
+	xtime.tv_sec = secs_since_1970;
+	xtime.tv_nsec = 0;
+	set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec);
+
+	bfin_clocksource_init();
+	bfin_clockevent_init();
+}
diff --git a/arch/blackfin/kernel/time.c b/arch/blackfin/kernel/time.c
index 715b394..eb23523 100644
--- a/arch/blackfin/kernel/time.c
+++ b/arch/blackfin/kernel/time.c
@@ -6,9 +6,10 @@
  * Created:
  * Description:  This file contains the bfin-specific time handling details.
  *               Most of the stuff is located in the machine specific files.
+ *		 FIXME: (This file is subject for removal)
  *
  * Modified:
- *               Copyright 2004-2006 Analog Devices Inc.
+ *               Copyright 2004-2008 Analog Devices Inc.
  *
  * Bugs:         Enter bugs at http://blackfin.uclinux.org/
  *
@@ -35,6 +36,7 @@
 #include <linux/irq.h>
 
 #include <asm/blackfin.h>
+#include <asm/time.h>
 
 /* This is an NTP setting */
 #define	TICK_SIZE (tick_nsec / 1000)
@@ -47,21 +49,6 @@
 	.flags = IRQF_DISABLED
 };
 
-/*
- * The way that the Blackfin core timer works is:
- *  - CCLK is divided by a programmable 8-bit pre-scaler (TSCALE)
- *  - Every time TSCALE ticks, a 32bit is counted down (TCOUNT)
- *
- * If you take the fastest clock (1ns, or 1GHz to make the math work easier)
- *    10ms is 10,000,000 clock ticks, which fits easy into a 32-bit counter
- *    (32 bit counter is 4,294,967,296ns or 4.2 seconds) so, we don't need
- *    to use TSCALE, and program it to zero (which is pass CCLK through).
- *    If you feel like using it, try to keep HZ * TIMESCALE to some
- *    value that divides easy (like power of 2).
- */
-
-#define TIME_SCALE 1
-
 static void
 time_sched_init(irq_handler_t timer_routine)
 {
diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c
index 56a67ab..5b84707 100644
--- a/arch/blackfin/kernel/traps.c
+++ b/arch/blackfin/kernel/traps.c
@@ -67,6 +67,8 @@
 	CSYNC();
 }
 
+void *saved_icplb_fault_addr, *saved_dcplb_fault_addr;
+
 int kstack_depth_to_print = 48;
 
 static void decode_address(char *buf, unsigned long address)
@@ -75,7 +77,7 @@
 	struct task_struct *p;
 	struct mm_struct *mm;
 	unsigned long flags, offset;
-	unsigned int in_exception = bfin_read_IPEND() & 0x10;
+	unsigned char in_atomic = (bfin_read_IPEND() & 0x10) || in_atomic();
 
 #ifdef CONFIG_KALLSYMS
 	unsigned long symsize;
@@ -117,7 +119,7 @@
 	 */
 	write_lock_irqsave(&tasklist_lock, flags);
 	for_each_process(p) {
-		mm = (in_exception ? p->mm : get_task_mm(p));
+		mm = (in_atomic ? p->mm : get_task_mm(p));
 		if (!mm)
 			continue;
 
@@ -137,23 +139,36 @@
 				/* FLAT does not have its text aligned to the start of
 				 * the map while FDPIC ELF does ...
 				 */
-				if (current->mm &&
-				    (address > current->mm->start_code) &&
-				    (address < current->mm->end_code))
-					offset = address - current->mm->start_code;
-				else
-					offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
 
-				sprintf(buf, "<0x%p> [ %s + 0x%lx ]",
-					(void *)address, name, offset);
-				if (!in_exception)
+				/* before we can check flat/fdpic, we need to
+				 * make sure current is valid
+				 */
+				if ((unsigned long)current >= FIXED_CODE_START &&
+				    !((unsigned long)current & 0x3)) {
+					if (current->mm &&
+					    (address > current->mm->start_code) &&
+					    (address < current->mm->end_code))
+						offset = address - current->mm->start_code;
+					else
+						offset = (address - vma->vm_start) +
+							 (vma->vm_pgoff << PAGE_SHIFT);
+
+					sprintf(buf, "<0x%p> [ %s + 0x%lx ]",
+						(void *)address, name, offset);
+				} else
+					sprintf(buf, "<0x%p> [ %s vma:0x%lx-0x%lx]",
+						(void *)address, name,
+						vma->vm_start, vma->vm_end);
+
+				if (!in_atomic)
 					mmput(mm);
+
 				goto done;
 			}
 
 			vml = vml->next;
 		}
-		if (!in_exception)
+		if (!in_atomic)
 			mmput(mm);
 	}
 
@@ -506,7 +521,7 @@
 
 	info.si_signo = sig;
 	info.si_errno = 0;
-	info.si_addr = (void *)fp->pc;
+	info.si_addr = (void __user *)fp->pc;
 	force_sig_info(sig, &info, current);
 
 	trace_buffer_restore(j);
@@ -655,21 +670,31 @@
 	else if (context & 0x8000)
 		printk(KERN_NOTICE "Kernel process context\n");
 
-	if (current->pid && current->mm) {
+	/* Because we are crashing, and pointers could be bad, we check things
+	 * pretty closely before we use them
+	 */
+	if ((unsigned long)current >= FIXED_CODE_START &&
+	    !((unsigned long)current & 0x3) && current->pid) {
 		printk(KERN_NOTICE "CURRENT PROCESS:\n");
-		printk(KERN_NOTICE "COMM=%s PID=%d\n",
-			current->comm, current->pid);
+		if (current->comm >= (char *)FIXED_CODE_START)
+			printk(KERN_NOTICE "COMM=%s PID=%d\n",
+				current->comm, current->pid);
+		else
+			printk(KERN_NOTICE "COMM= invalid\n");
 
-		printk(KERN_NOTICE "TEXT = 0x%p-0x%p  DATA = 0x%p-0x%p\n"
-			KERN_NOTICE "BSS = 0x%p-0x%p   USER-STACK = 0x%p\n"
-			KERN_NOTICE "\n",
-			(void *)current->mm->start_code,
-			(void *)current->mm->end_code,
-			(void *)current->mm->start_data,
-			(void *)current->mm->end_data,
-			(void *)current->mm->end_data,
-			(void *)current->mm->brk,
-			(void *)current->mm->start_stack);
+		if (!((unsigned long)current->mm & 0x3) && (unsigned long)current->mm >= FIXED_CODE_START)
+			printk(KERN_NOTICE  "TEXT = 0x%p-0x%p        DATA = 0x%p-0x%p\n"
+				KERN_NOTICE " BSS = 0x%p-0x%p  USER-STACK = 0x%p\n"
+				KERN_NOTICE "\n",
+				(void *)current->mm->start_code,
+				(void *)current->mm->end_code,
+				(void *)current->mm->start_data,
+				(void *)current->mm->end_data,
+				(void *)current->mm->end_data,
+				(void *)current->mm->brk,
+				(void *)current->mm->start_stack);
+		else
+			printk(KERN_NOTICE "invalid mm\n");
 	} else
 		printk(KERN_NOTICE "\n" KERN_NOTICE
 		     "No Valid process in current context\n");
@@ -680,10 +705,7 @@
 	unsigned short *addr, *erraddr, val = 0, err = 0;
 	char sti = 0, buf[6];
 
-	if (unlikely((fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR))
-		erraddr = (void *)fp->pc;
-	else
-		erraddr = (void *)fp->retx;
+	erraddr = (void *)fp->pc;
 
 	printk(KERN_NOTICE "return address: [0x%p]; contents of:", erraddr);
 
@@ -807,9 +829,9 @@
 
 	if (((long)fp->seqstat &  SEQSTAT_EXCAUSE) &&
 	    (((long)fp->seqstat & SEQSTAT_EXCAUSE) != VEC_HWERR)) {
-		decode_address(buf, bfin_read_DCPLB_FAULT_ADDR());
+		decode_address(buf, saved_dcplb_fault_addr);
 		printk(KERN_NOTICE "DCPLB_FAULT_ADDR: %s\n", buf);
-		decode_address(buf, bfin_read_ICPLB_FAULT_ADDR());
+		decode_address(buf, saved_icplb_fault_addr);
 		printk(KERN_NOTICE "ICPLB_FAULT_ADDR: %s\n", buf);
 	}
 
@@ -917,8 +939,8 @@
 
 	oops_in_progress = 1;
 
-	printk(KERN_EMERG "DCPLB_FAULT_ADDR=%p\n", (void *)bfin_read_DCPLB_FAULT_ADDR());
-	printk(KERN_EMERG "ICPLB_FAULT_ADDR=%p\n", (void *)bfin_read_ICPLB_FAULT_ADDR());
+	printk(KERN_EMERG "DCPLB_FAULT_ADDR=%p\n", saved_dcplb_fault_addr);
+	printk(KERN_EMERG "ICPLB_FAULT_ADDR=%p\n", saved_icplb_fault_addr);
 	dump_bfin_process(fp);
 	dump_bfin_mem(fp);
 	show_regs(fp);
diff --git a/arch/blackfin/kernel/vmlinux.lds.S b/arch/blackfin/kernel/vmlinux.lds.S
index cb01a9d..3ecc64c 100644
--- a/arch/blackfin/kernel/vmlinux.lds.S
+++ b/arch/blackfin/kernel/vmlinux.lds.S
@@ -56,6 +56,10 @@
 		*(.text.*)
 		*(.fixup)
 
+#if !L1_CODE_LENGTH
+		*(.l1.text)
+#endif
+
 		. = ALIGN(16);
 		___start___ex_table = .;
 		*(__ex_table)
@@ -73,6 +77,12 @@
 		___bss_start = .;
 		*(.bss .bss.*)
 		*(COMMON)
+#if !L1_DATA_A_LENGTH
+		*(.l1.bss)
+#endif
+#if !L1_DATA_B_LENGTH
+		*(.l1.bss.B)
+#endif
 		___bss_stop = .;
 	}
 
@@ -83,6 +93,15 @@
 		. = ALIGN(32);
 		*(.data.cacheline_aligned)
 
+#if !L1_DATA_A_LENGTH
+		. = ALIGN(32);
+		*(.data_l1.cacheline_aligned)
+		*(.l1.data)
+#endif
+#if !L1_DATA_B_LENGTH
+		*(.l1.data.B)
+#endif
+
 		DATA_DATA
 		*(.data.*)
 		CONSTRUCTORS
@@ -147,64 +166,43 @@
 
 	__l1_lma_start = .;
 
-#if L1_CODE_LENGTH
-# define LDS_L1_CODE *(.l1.text)
-#else
-# define LDS_L1_CODE
-#endif
 	.text_l1 L1_CODE_START : AT(LOADADDR(.init.ramfs) + SIZEOF(.init.ramfs))
 	{
 		. = ALIGN(4);
 		__stext_l1 = .;
-		LDS_L1_CODE
+		*(.l1.text)
 		. = ALIGN(4);
 		__etext_l1 = .;
 	}
 
-#if L1_DATA_A_LENGTH
-# define LDS_L1_A_DATA  *(.l1.data)
-# define LDS_L1_A_BSS   *(.l1.bss)
-# define LDS_L1_A_CACHE *(.data_l1.cacheline_aligned)
-#else
-# define LDS_L1_A_DATA
-# define LDS_L1_A_BSS
-# define LDS_L1_A_CACHE
-#endif
 	.data_l1 L1_DATA_A_START : AT(LOADADDR(.text_l1) + SIZEOF(.text_l1))
 	{
 		. = ALIGN(4);
 		__sdata_l1 = .;
-		LDS_L1_A_DATA
+		*(.l1.data)
 		__edata_l1 = .;
 
 		. = ALIGN(4);
 		__sbss_l1 = .;
-		LDS_L1_A_BSS
+		*(.l1.bss)
 
 		. = ALIGN(32);
-		LDS_L1_A_CACHE
+		*(.data_l1.cacheline_aligned)
 
 		. = ALIGN(4);
 		__ebss_l1 = .;
 	}
 
-#if L1_DATA_B_LENGTH
-# define LDS_L1_B_DATA  *(.l1.data.B)
-# define LDS_L1_B_BSS   *(.l1.bss.B)
-#else
-# define LDS_L1_B_DATA
-# define LDS_L1_B_BSS
-#endif
 	.data_b_l1 L1_DATA_B_START : AT(LOADADDR(.data_l1) + SIZEOF(.data_l1))
 	{
 		. = ALIGN(4);
 		__sdata_b_l1 = .;
-		LDS_L1_B_DATA
+		*(.l1.data.B)
 		__edata_b_l1 = .;
 
 		. = ALIGN(4);
 		__sbss_b_l1 = .;
-		LDS_L1_B_BSS
+		*(.l1.bss.B)
 
 		. = ALIGN(4);
 		__ebss_b_l1 = .;
@@ -223,8 +221,6 @@
 
 	DWARF_DEBUG
 
-	NOTES
-
 	/DISCARD/ :
 	{
 		EXIT_TEXT
diff --git a/arch/blackfin/mach-bf527/Makefile b/arch/blackfin/mach-bf527/Makefile
index 9f99f5d..4eddb58 100644
--- a/arch/blackfin/mach-bf527/Makefile
+++ b/arch/blackfin/mach-bf527/Makefile
@@ -5,5 +5,3 @@
 extra-y := head.o
 
 obj-y := ints-priority.o dma.o
-
-obj-$(CONFIG_CPU_FREQ)   += cpu.o
diff --git a/arch/blackfin/mach-bf527/boards/ezkit.c b/arch/blackfin/mach-bf527/boards/ezkit.c
index cf4bc0d..583d538 100644
--- a/arch/blackfin/mach-bf527/boards/ezkit.c
+++ b/arch/blackfin/mach-bf527/boards/ezkit.c
@@ -94,7 +94,7 @@
 {
 	unsigned int num_devices = ARRAY_SIZE(bfin_isp1761_devices);
 
-	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	printk(KERN_INFO "%s(): registering device resources\n", __func__);
 	set_irq_type(ISP1761_IRQ, IRQF_TRIGGER_FALLING);
 
 	return platform_add_devices(bfin_isp1761_devices, num_devices);
@@ -416,7 +416,7 @@
 static struct mtd_partition bfin_spi_flash_partitions[] = {
 	{
 		.name = "bootloader",
-		.size = 0x00020000,
+		.size = 0x00040000,
 		.offset = 0,
 		.mask_flags = MTD_CAP_ROM
 	}, {
@@ -707,6 +707,32 @@
 };
 #endif
 
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+static struct resource bfin_sir_resources[] = {
+#ifdef CONFIG_BFIN_SIR0
+	{
+		.start = 0xFFC00400,
+		.end = 0xFFC004FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+#ifdef CONFIG_BFIN_SIR1
+	{
+		.start = 0xFFC02000,
+		.end = 0xFFC020FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+};
+
+static struct platform_device bfin_sir_device = {
+	.name = "bfin_sir",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bfin_sir_resources),
+	.resource = bfin_sir_resources,
+};
+#endif
+
 #if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
 static struct resource bfin_twi0_resource[] = {
 	[0] = {
@@ -874,6 +900,10 @@
 	&bfin_uart_device,
 #endif
 
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+	&bfin_sir_device,
+#endif
+
 #if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
 	&i2c_bfin_twi_device,
 #endif
@@ -896,7 +926,7 @@
 
 static int __init stamp_init(void)
 {
-	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	printk(KERN_INFO "%s(): registering device resources\n", __func__);
 	platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
 	spi_register_board_info(bfin_spi_board_info,
diff --git a/arch/blackfin/mach-bf527/cpu.c b/arch/blackfin/mach-bf527/cpu.c
deleted file mode 100644
index 1975402..0000000
--- a/arch/blackfin/mach-bf527/cpu.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * File:         arch/blackfin/mach-bf527/cpu.c
- * Based on:	arch/blackfin/mach-bf537/cpu.c
- * Author:       michael.kang@analog.com
- *
- * Created:
- * Description:  clock scaling for the bf527
- *
- * Modified:
- *               Copyright 2004-2007 Analog Devices Inc.
- *
- * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/cpufreq.h>
-#include <asm/dpmc.h>
-#include <linux/fs.h>
-#include <asm/bfin-global.h>
-
-/* CONFIG_CLKIN_HZ=11059200 */
-#define VCO5 (CONFIG_CLKIN_HZ*45)	/*497664000 */
-#define VCO4 (CONFIG_CLKIN_HZ*36)	/*398131200 */
-#define VCO3 (CONFIG_CLKIN_HZ*27)	/*298598400 */
-#define VCO2 (CONFIG_CLKIN_HZ*18)	/*199065600 */
-#define VCO1 (CONFIG_CLKIN_HZ*9)	/*99532800 */
-#define VCO(x) VCO##x
-
-#define MFREQ(x) {VCO(x), VCO(x)/4}, {VCO(x), VCO(x)/2}, {VCO(x), VCO(x)}
-/* frequency */
-static struct cpufreq_frequency_table bf527_freq_table[] = {
-	MFREQ(1),
-	MFREQ(3),
-	{VCO4, VCO4 / 2}, {VCO4, VCO4},
-	MFREQ(5),
-	{0, CPUFREQ_TABLE_END},
-};
-
-/*
- * dpmc_fops->ioctl()
- * static int dpmc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
- */
-static int bf527_getfreq(unsigned int cpu)
-{
-	unsigned long cclk_mhz;
-
-	/* The driver only support single cpu */
-	if (cpu == 0)
-		dpmc_fops.ioctl(NULL, NULL, IOCTL_GET_CORECLOCK, &cclk_mhz);
-	else
-		cclk_mhz = -1;
-
-	return cclk_mhz;
-}
-
-static int bf527_target(struct cpufreq_policy *policy,
-			unsigned int target_freq, unsigned int relation)
-{
-	unsigned long cclk_mhz;
-	unsigned long vco_mhz;
-	unsigned long flags;
-	unsigned int index;
-	struct cpufreq_freqs freqs;
-
-	if (cpufreq_frequency_table_target
-	    (policy, bf527_freq_table, target_freq, relation, &index))
-		return -EINVAL;
-
-	cclk_mhz = bf527_freq_table[index].frequency;
-	vco_mhz = bf527_freq_table[index].index;
-
-	dpmc_fops.ioctl(NULL, NULL, IOCTL_CHANGE_FREQUENCY, &vco_mhz);
-	freqs.old = bf527_getfreq(0);
-	freqs.new = cclk_mhz;
-	freqs.cpu = 0;
-
-	pr_debug
-	    ("cclk begin change to cclk %d,vco=%d,index=%d,target=%d,oldfreq=%d\n",
-	     cclk_mhz, vco_mhz, index, target_freq, freqs.old);
-
-	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-	local_irq_save(flags);
-	dpmc_fops.ioctl(NULL, NULL, IOCTL_SET_CCLK, &cclk_mhz);
-	local_irq_restore(flags);
-	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-
-	vco_mhz = get_vco();
-	cclk_mhz = get_cclk();
-	return 0;
-}
-
-/* make sure that only the "userspace" governor is run -- anything else wouldn't make sense on
- * this platform, anyway.
- */
-static int bf527_verify_speed(struct cpufreq_policy *policy)
-{
-	return cpufreq_frequency_table_verify(policy, &bf527_freq_table);
-}
-
-static int __init __bf527_cpu_init(struct cpufreq_policy *policy)
-{
-	if (policy->cpu != 0)
-		return -EINVAL;
-
-	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-
-	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
-	/*Now ,only support one cpu */
-	policy->cur = bf527_getfreq(0);
-	cpufreq_frequency_table_get_attr(bf527_freq_table, policy->cpu);
-	return cpufreq_frequency_table_cpuinfo(policy, bf527_freq_table);
-}
-
-static struct freq_attr *bf527_freq_attr[] = {
-	&cpufreq_freq_attr_scaling_available_freqs,
-	NULL,
-};
-
-static struct cpufreq_driver bf527_driver = {
-	.verify = bf527_verify_speed,
-	.target = bf527_target,
-	.get = bf527_getfreq,
-	.init = __bf527_cpu_init,
-	.name = "bf527",
-	.owner = THIS_MODULE,
-	.attr = bf527_freq_attr,
-};
-
-static int __init bf527_cpu_init(void)
-{
-	return cpufreq_register_driver(&bf527_driver);
-}
-
-static void __exit bf527_cpu_exit(void)
-{
-	cpufreq_unregister_driver(&bf527_driver);
-}
-
-MODULE_AUTHOR("Mickael Kang");
-MODULE_DESCRIPTION("cpufreq driver for bf527 CPU");
-MODULE_LICENSE("GPL");
-
-module_init(bf527_cpu_init);
-module_exit(bf527_cpu_exit);
diff --git a/arch/blackfin/mach-bf527/dma.c b/arch/blackfin/mach-bf527/dma.c
index 522de24..dfd080c 100644
--- a/arch/blackfin/mach-bf527/dma.c
+++ b/arch/blackfin/mach-bf527/dma.c
@@ -26,10 +26,12 @@
  * to the Free Software Foundation, Inc.,
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
+#include <linux/module.h>
+
 #include <asm/blackfin.h>
 #include <asm/dma.h>
 
-struct dma_register *base_addr[MAX_BLACKFIN_DMA_CHANNEL] = {
+struct dma_register *dma_io_base_addr[MAX_BLACKFIN_DMA_CHANNEL] = {
 	(struct dma_register *) DMA0_NEXT_DESC_PTR,
 	(struct dma_register *) DMA1_NEXT_DESC_PTR,
 	(struct dma_register *) DMA2_NEXT_DESC_PTR,
@@ -47,6 +49,7 @@
 	(struct dma_register *) MDMA_D1_NEXT_DESC_PTR,
 	(struct dma_register *) MDMA_S1_NEXT_DESC_PTR,
 };
+EXPORT_SYMBOL(dma_io_base_addr);
 
 int channel2irq(unsigned int channel)
 {
diff --git a/arch/blackfin/mach-bf527/head.S b/arch/blackfin/mach-bf527/head.S
index cdb00a0..57bdb3b 100644
--- a/arch/blackfin/mach-bf527/head.S
+++ b/arch/blackfin/mach-bf527/head.S
@@ -37,9 +37,6 @@
 #include <asm/mach/mem_init.h>
 #endif
 
-.global __rambase
-.global __ramstart
-.global __ramend
 .extern ___bss_stop
 .extern ___bss_start
 .extern _bf53x_relocate_l1_mem
@@ -439,18 +436,3 @@
 	RTS;
 ENDPROC(_start_dma_code)
 #endif /* CONFIG_BFIN_KERNEL_CLOCK */
-
-.data
-
-/*
- * Set up the usable of RAM stuff. Size of RAM is determined then
- * an initial stack set up at the end.
- */
-
-.align 4
-__rambase:
-.long   0
-__ramstart:
-.long   0
-__ramend:
-.long   0
diff --git a/arch/blackfin/mach-bf533/Makefile b/arch/blackfin/mach-bf533/Makefile
index 8cce173..aa9f264 100644
--- a/arch/blackfin/mach-bf533/Makefile
+++ b/arch/blackfin/mach-bf533/Makefile
@@ -5,5 +5,3 @@
 extra-y := head.o
 
 obj-y := ints-priority.o dma.o
-
-obj-$(CONFIG_CPU_FREQ)   += cpu.o
diff --git a/arch/blackfin/mach-bf533/boards/H8606.c b/arch/blackfin/mach-bf533/boards/H8606.c
index 97378b0..7cc4864 100644
--- a/arch/blackfin/mach-bf533/boards/H8606.c
+++ b/arch/blackfin/mach-bf533/boards/H8606.c
@@ -304,6 +304,25 @@
 };
 #endif
 
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+static struct resource bfin_sir_resources[] = {
+#ifdef CONFIG_BFIN_SIR0
+	{
+		.start = 0xFFC00400,
+		.end = 0xFFC004FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+};
+
+static struct platform_device bfin_sir_device = {
+	.name = "bfin_sir",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bfin_sir_resources),
+	.resource = bfin_sir_resources,
+};
+#endif
+
 #if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
 
 #include <linux/serial_8250.h>
@@ -403,6 +422,10 @@
 	&serial8250_device,
 #endif
 
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+	&bfin_sir_device,
+#endif
+
 #if defined(CONFIG_KEYBOARD_OPENCORES) || defined(CONFIG_KEYBOARD_OPENCORES_MODULE)
 	&opencores_kbd_device,
 #endif
@@ -411,7 +434,7 @@
 static int __init H8606_init(void)
 {
 	printk(KERN_INFO "HV Sistemas H8606 board support by http://www.hvsistemas.com\n");
-	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	printk(KERN_INFO "%s(): registering device resources\n", __func__);
 	platform_add_devices(h8606_devices, ARRAY_SIZE(h8606_devices));
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
 	spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
diff --git a/arch/blackfin/mach-bf533/boards/Kconfig b/arch/blackfin/mach-bf533/boards/Kconfig
index 751de51..8400592 100644
--- a/arch/blackfin/mach-bf533/boards/Kconfig
+++ b/arch/blackfin/mach-bf533/boards/Kconfig
@@ -26,6 +26,12 @@
 	help
 	  HV Sistemas H8606 board support.
 
+config BFIN532_IP0X
+	bool "IP04/IP08 IP-PBX"
+	depends on (BF532)
+	help
+	  Core support for IP04/IP04 open hardware IP-PBX.
+
 config GENERIC_BF533_BOARD
 	bool "Generic"
 	help
diff --git a/arch/blackfin/mach-bf533/boards/Makefile b/arch/blackfin/mach-bf533/boards/Makefile
index 54f57fb..b7a1a1d 100644
--- a/arch/blackfin/mach-bf533/boards/Makefile
+++ b/arch/blackfin/mach-bf533/boards/Makefile
@@ -4,6 +4,7 @@
 
 obj-$(CONFIG_GENERIC_BF533_BOARD)      += generic_board.o
 obj-$(CONFIG_BFIN533_STAMP)            += stamp.o
+obj-$(CONFIG_BFIN532_IP0X)             += ip0x.o
 obj-$(CONFIG_BFIN533_EZKIT)            += ezkit.o
 obj-$(CONFIG_BFIN533_BLUETECHNIX_CM)   += cm_bf533.o
 obj-$(CONFIG_H8606_HVSISTEMAS)         += H8606.o
diff --git a/arch/blackfin/mach-bf533/boards/cm_bf533.c b/arch/blackfin/mach-bf533/boards/cm_bf533.c
index 886f260..a03149c 100644
--- a/arch/blackfin/mach-bf533/boards/cm_bf533.c
+++ b/arch/blackfin/mach-bf533/boards/cm_bf533.c
@@ -234,6 +234,25 @@
 };
 #endif
 
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+static struct resource bfin_sir_resources[] = {
+#ifdef CONFIG_BFIN_SIR0
+	{
+		.start = 0xFFC00400,
+		.end = 0xFFC004FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+};
+
+static struct platform_device bfin_sir_device = {
+	.name = "bfin_sir",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bfin_sir_resources),
+	.resource = bfin_sir_resources,
+};
+#endif
+
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
 static struct platform_device bfin_sport0_uart_device = {
 	.name = "bfin-sport-uart",
@@ -327,6 +346,10 @@
 	&bfin_uart_device,
 #endif
 
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+	&bfin_sir_device,
+#endif
+
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
 	&bfin_sport0_uart_device,
 	&bfin_sport1_uart_device,
@@ -355,7 +378,7 @@
 
 static int __init cm_bf533_init(void)
 {
-	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	printk(KERN_INFO "%s(): registering device resources\n", __func__);
 	platform_add_devices(cm_bf533_devices, ARRAY_SIZE(cm_bf533_devices));
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
 	spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
diff --git a/arch/blackfin/mach-bf533/boards/ezkit.c b/arch/blackfin/mach-bf533/boards/ezkit.c
index 241b5a2..08a7943 100644
--- a/arch/blackfin/mach-bf533/boards/ezkit.c
+++ b/arch/blackfin/mach-bf533/boards/ezkit.c
@@ -237,6 +237,25 @@
 };
 #endif
 
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+static struct resource bfin_sir_resources[] = {
+#ifdef CONFIG_BFIN_SIR0
+	{
+		.start = 0xFFC00400,
+		.end = 0xFFC004FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+};
+
+static struct platform_device bfin_sir_device = {
+	.name = "bfin_sir",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bfin_sir_resources),
+	.resource = bfin_sir_resources,
+};
+#endif
+
 #if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
 #define PATA_INT	55
 
@@ -352,6 +371,10 @@
 	&bfin_uart_device,
 #endif
 
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+	&bfin_sir_device,
+#endif
+
 #if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
 	&bfin_pata_device,
 #endif
@@ -369,7 +392,7 @@
 
 static int __init ezkit_init(void)
 {
-	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	printk(KERN_INFO "%s(): registering device resources\n", __func__);
 	platform_add_devices(ezkit_devices, ARRAY_SIZE(ezkit_devices));
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
 	spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
diff --git a/arch/blackfin/mach-bf533/boards/generic_board.c b/arch/blackfin/mach-bf533/boards/generic_board.c
index e359a0d..82b1f6a 100644
--- a/arch/blackfin/mach-bf533/boards/generic_board.c
+++ b/arch/blackfin/mach-bf533/boards/generic_board.c
@@ -84,7 +84,7 @@
 
 static int __init generic_board_init(void)
 {
-	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	printk(KERN_INFO "%s(): registering device resources\n", __func__);
 	return platform_add_devices(generic_board_devices, ARRAY_SIZE(generic_board_devices));
 }
 
diff --git a/arch/blackfin/mach-bf533/boards/ip0x.c b/arch/blackfin/mach-bf533/boards/ip0x.c
new file mode 100644
index 0000000..5864892
--- /dev/null
+++ b/arch/blackfin/mach-bf533/boards/ip0x.c
@@ -0,0 +1,303 @@
+/*
+ * File:         arch/blackfin/mach-bf533/ip0x.c
+ * Based on:     arch/blackfin/mach-bf533/bf1.c
+ * Based on:     arch/blackfin/mach-bf533/stamp.c
+ * Author:       Ivan Danov <idanov@gmail.com>
+ *               Modified for IP0X David Rowe
+ *
+ * Created:      2007
+ * Description:  Board info file for the IP04/IP08 boards, which
+ *               are derived from the BlackfinOne V2.0 boards.
+ *
+ * Modified:
+ *               COpyright 2007 David Rowe
+ *               Copyright 2006 Intratrade Ltd.
+ *               Copyright 2005 National ICT Australia (NICTA)
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+#include <linux/usb/isp1362.h>
+#endif
+#include <asm/irq.h>
+#include <asm/bfin5xx_spi.h>
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+const char bfin_board_name[] = "IP04/IP08";
+
+/*
+ *  Driver needs to know address, irq and flag pin.
+ */
+#if defined(CONFIG_BFIN532_IP0X)
+#if defined(CONFIG_DM9000) || defined(CONFIG_DM9000_MODULE)
+
+#include <linux/dm9000.h>
+
+static struct resource dm9000_resource1[] = {
+	{
+		.start = 0x20100000,
+		.end   = 0x20100000 + 1,
+		.flags = IORESOURCE_MEM
+	},{
+		.start = 0x20100000 + 2,
+		.end   = 0x20100000 + 3,
+		.flags = IORESOURCE_MEM
+	},{
+		.start = IRQ_PF15,
+		.end   = IRQ_PF15,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE
+	}
+};
+
+static struct resource dm9000_resource2[] = {
+	{
+		.start = 0x20200000,
+		.end   = 0x20200000 + 1,
+		.flags = IORESOURCE_MEM
+	},{
+		.start = 0x20200000 + 2,
+		.end   = 0x20200000 + 3,
+		.flags = IORESOURCE_MEM
+	},{
+		.start = IRQ_PF14,
+		.end   = IRQ_PF14,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE
+	}
+};
+
+/*
+* for the moment we limit ourselves to 16bit IO until some
+* better IO routines can be written and tested
+*/
+static struct dm9000_plat_data dm9000_platdata1 = {
+	.flags          = DM9000_PLATF_16BITONLY,
+};
+
+static struct platform_device dm9000_device1 = {
+	.name           = "dm9000",
+	.id             = 0,
+	.num_resources  = ARRAY_SIZE(dm9000_resource1),
+	.resource       = dm9000_resource1,
+	.dev            = {
+		.platform_data = &dm9000_platdata1,
+	}
+};
+
+static struct dm9000_plat_data dm9000_platdata2 = {
+	.flags          = DM9000_PLATF_16BITONLY,
+};
+
+static struct platform_device dm9000_device2 = {
+	.name           = "dm9000",
+	.id             = 1,
+	.num_resources  = ARRAY_SIZE(dm9000_resource2),
+	.resource       = dm9000_resource2,
+	.dev            = {
+		.platform_data = &dm9000_platdata2,
+	}
+};
+
+#endif
+#endif
+
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+/* all SPI peripherals info goes here */
+
+#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
+static struct bfin5xx_spi_chip spi_mmc_chip_info = {
+/*
+ * CPOL (Clock Polarity)
+ *  0 - Active high SCK
+ *  1 - Active low SCK
+ *  CPHA (Clock Phase) Selects transfer format and operation mode
+ *  0 - SCLK toggles from middle of the first data bit, slave select
+ *      pins controlled by hardware.
+ *  1 - SCLK toggles from beginning of first data bit, slave select
+ *      pins controller by user software.
+ * 	.ctl_reg = 0x1c00,		 *  CPOL=1,CPHA=1,Sandisk 1G work
+ * NO NO	.ctl_reg = 0x1800,		 *  CPOL=1,CPHA=0
+ * NO NO	.ctl_reg = 0x1400,		 *  CPOL=0,CPHA=1
+ */
+	.ctl_reg = 0x1000,		/* CPOL=0,CPHA=0,Sandisk 1G work */
+	.enable_dma = 0,		/* if 1 - block!!! */
+	.bits_per_word = 8,
+	.cs_change_per_word = 0,
+};
+#endif
+
+/* Notice: for blackfin, the speed_hz is the value of register
+ * SPI_BAUD, not the real baudrate */
+static struct spi_board_info bfin_spi_board_info[] __initdata = {
+#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
+	{
+		.modalias = "spi_mmc",
+		.max_speed_hz = 2,
+		.bus_num = 1,
+		.chip_select = CONFIG_SPI_MMC_CS_CHAN,
+		.platform_data = NULL,
+		.controller_data = &spi_mmc_chip_info,
+	},
+#endif
+};
+
+/* SPI controller data */
+static struct bfin5xx_spi_master spi_bfin_master_info = {
+	.num_chipselect = 8,
+	.enable_dma = 1,  /* master has the ability to do dma transfer */
+};
+
+static struct platform_device spi_bfin_master_device = {
+	.name = "bfin-spi-master",
+	.id = 1, /* Bus number */
+	.dev = {
+		.platform_data = &spi_bfin_master_info, /* Passed to driver */
+	},
+};
+#endif  /* spi master and devices */
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+static struct resource bfin_uart_resources[] = {
+	{
+		.start = 0xFFC00400,
+		.end = 0xFFC004FF,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device bfin_uart_device = {
+	.name = "bfin-uart",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(bfin_uart_resources),
+	.resource = bfin_uart_resources,
+};
+#endif
+
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+static struct resource bfin_sir_resources[] = {
+#ifdef CONFIG_BFIN_SIR0
+	{
+		.start = 0xFFC00400,
+		.end = 0xFFC004FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+};
+
+static struct platform_device bfin_sir_device = {
+	.name = "bfin_sir",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bfin_sir_resources),
+	.resource = bfin_sir_resources,
+};
+#endif
+
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+static struct resource isp1362_hcd_resources[] = {
+	{
+		.start = 0x20300000,
+		.end   = 0x20300000 + 1,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = 0x20300000 + 2,
+		.end   = 0x20300000 + 3,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = IRQ_PF11,
+		.end   = IRQ_PF11,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+};
+
+static struct isp1362_platform_data isp1362_priv = {
+	.sel15Kres = 1,
+	.clknotstop = 0,
+	.oc_enable = 0,		/* external OC */
+	.int_act_high = 0,
+	.int_edge_triggered = 0,
+	.remote_wakeup_connected = 0,
+	.no_power_switching = 1,
+	.power_switching_mode = 0,
+};
+
+static struct platform_device isp1362_hcd_device = {
+	.name = "isp1362-hcd",
+	.id = 0,
+	.dev = {
+		.platform_data = &isp1362_priv,
+	},
+	.num_resources = ARRAY_SIZE(isp1362_hcd_resources),
+	.resource = isp1362_hcd_resources,
+};
+#endif
+
+
+static struct platform_device *ip0x_devices[] __initdata = {
+#if defined(CONFIG_BFIN532_IP0X)
+#if defined(CONFIG_DM9000) || defined(CONFIG_DM9000_MODULE)
+	&dm9000_device1,
+	&dm9000_device2,
+#endif
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+	&spi_bfin_master_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+	&bfin_uart_device,
+#endif
+
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+	&bfin_sir_device,
+#endif
+
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+	&isp1362_hcd_device,
+#endif
+};
+
+static int __init ip0x_init(void)
+{
+	int i;
+
+	printk(KERN_INFO "%s(): registering device resources\n", __func__);
+	platform_add_devices(ip0x_devices, ARRAY_SIZE(ip0x_devices));
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+	for (i = 0; i < ARRAY_SIZE(bfin_spi_board_info); ++i) {
+		int j = 1 << bfin_spi_board_info[i].chip_select;
+		/* set spi cs to 1 */
+		bfin_write_FIO_DIR(bfin_read_FIO_DIR() | j);
+		bfin_write_FIO_FLAG_S(j);
+	}
+	spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
+#endif
+
+	return 0;
+}
+
+arch_initcall(ip0x_init);
diff --git a/arch/blackfin/mach-bf533/boards/stamp.c b/arch/blackfin/mach-bf533/boards/stamp.c
index b2ac481..fddce32 100644
--- a/arch/blackfin/mach-bf533/boards/stamp.c
+++ b/arch/blackfin/mach-bf533/boards/stamp.c
@@ -40,6 +40,7 @@
 #endif
 #include <linux/ata_platform.h>
 #include <linux/irq.h>
+#include <linux/i2c.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/reboot.h>
@@ -109,6 +110,7 @@
 };
 #endif
 
+#if defined(CONFIG_MTD_BF5xx) || defined(CONFIG_MTD_BF5xx_MODULE)
 static struct mtd_partition stamp_partitions[] = {
 	{
 		.name   = "Bootloader",
@@ -152,6 +154,7 @@
 	.num_resources = ARRAY_SIZE(stamp_flash_resource),
 	.resource      = stamp_flash_resource,
 };
+#endif
 
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
 /* all SPI peripherals info goes here */
@@ -367,6 +370,25 @@
 };
 #endif
 
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+static struct resource bfin_sir_resources[] = {
+#ifdef CONFIG_BFIN_SIR0
+	{
+		.start = 0xFFC00400,
+		.end = 0xFFC004FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+};
+
+static struct platform_device bfin_sir_device = {
+	.name = "bfin_sir",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bfin_sir_resources),
+	.resource = bfin_sir_resources,
+};
+#endif
+
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
 static struct platform_device bfin_sport0_uart_device = {
 	.name = "bfin-sport-uart",
@@ -472,6 +494,31 @@
 };
 #endif
 
+#ifdef CONFIG_I2C_BOARDINFO
+static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
+#if defined(CONFIG_JOYSTICK_AD7142) || defined(CONFIG_JOYSTICK_AD7142_MODULE)
+	{
+		I2C_BOARD_INFO("ad7142_joystick", 0x2C),
+		.type = "ad7142_joystick",
+		.irq = 39,
+	},
+#endif
+#if defined(CONFIG_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
+	{
+		I2C_BOARD_INFO("pcf8574_lcd", 0x22),
+		.type = "pcf8574_lcd",
+	},
+#endif
+#if defined(CONFIG_TWI_KEYPAD) || defined(CONFIG_TWI_KEYPAD_MODULE)
+	{
+		I2C_BOARD_INFO("pcf8574_keypad", 0x27),
+		.type = "pcf8574_keypad",
+		.irq = 39,
+	},
+#endif
+};
+#endif
+
 static struct platform_device *stamp_devices[] __initdata = {
 #if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
 	&rtc_device,
@@ -497,6 +544,10 @@
 	&bfin_uart_device,
 #endif
 
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+	&bfin_sir_device,
+#endif
+
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
 	&bfin_sport0_uart_device,
 	&bfin_sport1_uart_device,
@@ -515,14 +566,23 @@
 #endif
 
 	&bfin_gpios_device,
+
+#if defined(CONFIG_MTD_BF5xx) || defined(CONFIG_MTD_BF5xx_MODULE)
 	&stamp_flash_device,
+#endif
 };
 
 static int __init stamp_init(void)
 {
 	int ret;
 
-	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	printk(KERN_INFO "%s(): registering device resources\n", __func__);
+
+#ifdef CONFIG_I2C_BOARDINFO
+	i2c_register_board_info(0, bfin_i2c_board_info,
+				ARRAY_SIZE(bfin_i2c_board_info));
+#endif
+
 	ret = platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
 	if (ret < 0)
 		return ret;
diff --git a/arch/blackfin/mach-bf533/cpu.c b/arch/blackfin/mach-bf533/cpu.c
deleted file mode 100644
index b7a0e0f..0000000
--- a/arch/blackfin/mach-bf533/cpu.c
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * File:         arch/blackfin/mach-bf533/cpu.c
- * Based on:
- * Author:       michael.kang@analog.com
- *
- * Created:
- * Description:  clock scaling for the bf533
- *
- * Modified:
- *               Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/cpufreq.h>
-#include <asm/dpmc.h>
-#include <linux/fs.h>
-#include <asm/bfin-global.h>
-
-/* CONFIG_CLKIN_HZ=11059200 */
-#define VCO5 (CONFIG_CLKIN_HZ*45)	/*497664000 */
-#define VCO4 (CONFIG_CLKIN_HZ*36)	/*398131200 */
-#define VCO3 (CONFIG_CLKIN_HZ*27)	/*298598400 */
-#define VCO2 (CONFIG_CLKIN_HZ*18)	/*199065600 */
-#define VCO1 (CONFIG_CLKIN_HZ*9)	/*99532800 */
-#define VCO(x) VCO##x
-
-#define FREQ(x) {VCO(x),VCO(x)/4},{VCO(x),VCO(x)/2},{VCO(x),VCO(x)}
-/* frequency */
-static struct cpufreq_frequency_table bf533_freq_table[] = {
-	FREQ(1),
-	FREQ(3),
-	{VCO4, VCO4 / 2}, {VCO4, VCO4},
-	FREQ(5),
-	{0, CPUFREQ_TABLE_END},
-};
-
-/*
- * dpmc_fops->ioctl()
- * static int dpmc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
- */
-static int bf533_getfreq(unsigned int cpu)
-{
-	unsigned long cclk_mhz, vco_mhz;
-
-	/* The driver only support single cpu */
-	if (cpu == 0)
-		dpmc_fops.ioctl(NULL, NULL, IOCTL_GET_CORECLOCK, &cclk_mhz);
-	else
-		cclk_mhz = -1;
-	return cclk_mhz;
-}
-
-static int bf533_target(struct cpufreq_policy *policy,
-			    unsigned int target_freq, unsigned int relation)
-{
-	unsigned long cclk_mhz;
-	unsigned long vco_mhz;
-	unsigned long flags;
-	unsigned int index, vco_index;
-	int i;
-
-	struct cpufreq_freqs freqs;
-	if (cpufreq_frequency_table_target(policy, bf533_freq_table, target_freq, relation, &index))
-		return -EINVAL;
-	cclk_mhz = bf533_freq_table[index].frequency;
-	vco_mhz = bf533_freq_table[index].index;
-
-	dpmc_fops.ioctl(NULL, NULL, IOCTL_CHANGE_FREQUENCY, &vco_mhz);
-	freqs.old = bf533_getfreq(0);
-	freqs.new = cclk_mhz;
-	freqs.cpu = 0;
-
-	pr_debug("cclk begin change to cclk %d,vco=%d,index=%d,target=%d,oldfreq=%d\n",
-	         cclk_mhz, vco_mhz, index, target_freq, freqs.old);
-
-	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-	local_irq_save(flags);
-	dpmc_fops.ioctl(NULL, NULL, IOCTL_SET_CCLK, &cclk_mhz);
-	local_irq_restore(flags);
-	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-
-	vco_mhz = get_vco();
-	cclk_mhz = get_cclk();
-	return 0;
-}
-
-/* make sure that only the "userspace" governor is run -- anything else wouldn't make sense on
- * this platform, anyway.
- */
-static int bf533_verify_speed(struct cpufreq_policy *policy)
-{
-	return cpufreq_frequency_table_verify(policy, &bf533_freq_table);
-}
-
-static int __init __bf533_cpu_init(struct cpufreq_policy *policy)
-{
-	int result;
-
-	if (policy->cpu != 0)
-		return -EINVAL;
-
-	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
-	/*Now ,only support one cpu */
-	policy->cur = bf533_getfreq(0);
-	cpufreq_frequency_table_get_attr(bf533_freq_table, policy->cpu);
-	return cpufreq_frequency_table_cpuinfo(policy, bf533_freq_table);
-}
-
-static struct freq_attr *bf533_freq_attr[] = {
-	&cpufreq_freq_attr_scaling_available_freqs,
-	NULL,
-};
-
-static struct cpufreq_driver bf533_driver = {
-	.verify = bf533_verify_speed,
-	.target = bf533_target,
-	.get = bf533_getfreq,
-	.init = __bf533_cpu_init,
-	.name = "bf533",
-	.owner = THIS_MODULE,
-	.attr = bf533_freq_attr,
-};
-
-static int __init bf533_cpu_init(void)
-{
-	return cpufreq_register_driver(&bf533_driver);
-}
-
-static void __exit bf533_cpu_exit(void)
-{
-	cpufreq_unregister_driver(&bf533_driver);
-}
-
-MODULE_AUTHOR("Mickael Kang");
-MODULE_DESCRIPTION("cpufreq driver for BF533 CPU");
-MODULE_LICENSE("GPL");
-
-module_init(bf533_cpu_init);
-module_exit(bf533_cpu_exit);
diff --git a/arch/blackfin/mach-bf533/dma.c b/arch/blackfin/mach-bf533/dma.c
index 6c909cf..28655c1 100644
--- a/arch/blackfin/mach-bf533/dma.c
+++ b/arch/blackfin/mach-bf533/dma.c
@@ -26,10 +26,12 @@
  * to the Free Software Foundation, Inc.,
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
+#include <linux/module.h>
+
 #include <asm/blackfin.h>
 #include <asm/dma.h>
 
-struct dma_register *base_addr[MAX_BLACKFIN_DMA_CHANNEL] = {
+struct dma_register *dma_io_base_addr[MAX_BLACKFIN_DMA_CHANNEL] = {
 	(struct dma_register *) DMA0_NEXT_DESC_PTR,
 	(struct dma_register *) DMA1_NEXT_DESC_PTR,
 	(struct dma_register *) DMA2_NEXT_DESC_PTR,
@@ -43,6 +45,7 @@
 	(struct dma_register *) MDMA_D1_NEXT_DESC_PTR,
 	(struct dma_register *) MDMA_S1_NEXT_DESC_PTR,
 };
+EXPORT_SYMBOL(dma_io_base_addr);
 
 int channel2irq(unsigned int channel)
 {
diff --git a/arch/blackfin/mach-bf533/head.S b/arch/blackfin/mach-bf533/head.S
index 1ded945..1295dea 100644
--- a/arch/blackfin/mach-bf533/head.S
+++ b/arch/blackfin/mach-bf533/head.S
@@ -36,9 +36,6 @@
 #include <asm/mach/mem_init.h>
 #endif
 
-.global __rambase
-.global __ramstart
-.global __ramend
 .extern ___bss_stop
 .extern ___bss_start
 .extern _bf53x_relocate_l1_mem
@@ -151,26 +148,26 @@
 
 	/* Initialise UART - when booting from u-boot, the UART is not disabled
 	 * so if we dont initalize here, our serial console gets hosed */
-	p0.h = hi(UART_LCR);
-	p0.l = lo(UART_LCR);
+	p0.h = hi(BFIN_UART_LCR);
+	p0.l = lo(BFIN_UART_LCR);
 	r0 = 0x0(Z);
 	w[p0] = r0.L;	/* To enable DLL writes */
 	ssync;
 
-	p0.h = hi(UART_DLL);
-	p0.l = lo(UART_DLL);
+	p0.h = hi(BFIN_UART_DLL);
+	p0.l = lo(BFIN_UART_DLL);
 	r0 = 0x0(Z);
 	w[p0] = r0.L;
 	ssync;
 
-	p0.h = hi(UART_DLH);
-	p0.l = lo(UART_DLH);
+	p0.h = hi(BFIN_UART_DLH);
+	p0.l = lo(BFIN_UART_DLH);
 	r0 = 0x00(Z);
 	w[p0] = r0.L;
 	ssync;
 
-	p0.h = hi(UART_GCTL);
-	p0.l = lo(UART_GCTL);
+	p0.h = hi(BFIN_UART_GCTL);
+	p0.l = lo(BFIN_UART_GCTL);
 	r0 = 0x0(Z);
 	w[p0] = r0.L;	/* To enable UART clock */
 	ssync;
@@ -431,18 +428,3 @@
 	RTS;
 ENDPROC(_start_dma_code)
 #endif /* CONFIG_BFIN_KERNEL_CLOCK */
-
-.data
-
-/*
- * Set up the usable of RAM stuff. Size of RAM is determined then
- * an initial stack set up at the end.
- */
-
-.align 4
-__rambase:
-.long   0
-__ramstart:
-.long   0
-__ramend:
-.long   0
diff --git a/arch/blackfin/mach-bf537/Makefile b/arch/blackfin/mach-bf537/Makefile
index 7e7c9c8..68e5478 100644
--- a/arch/blackfin/mach-bf537/Makefile
+++ b/arch/blackfin/mach-bf537/Makefile
@@ -5,5 +5,3 @@
 extra-y := head.o
 
 obj-y := ints-priority.o dma.o
-
-obj-$(CONFIG_CPU_FREQ)   += cpu.o
diff --git a/arch/blackfin/mach-bf537/boards/cm_bf537.c b/arch/blackfin/mach-bf537/boards/cm_bf537.c
index f7c1f96..d8a23cd 100644
--- a/arch/blackfin/mach-bf537/boards/cm_bf537.c
+++ b/arch/blackfin/mach-bf537/boards/cm_bf537.c
@@ -325,6 +325,54 @@
 };
 #endif
 
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+static struct resource bfin_sir_resources[] = {
+#ifdef CONFIG_BFIN_SIR0
+	{
+		.start = 0xFFC00400,
+		.end = 0xFFC004FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+#ifdef CONFIG_BFIN_SIR1
+	{
+		.start = 0xFFC02000,
+		.end = 0xFFC020FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+};
+
+static struct platform_device bfin_sir_device = {
+	.name = "bfin_sir",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bfin_sir_resources),
+	.resource = bfin_sir_resources,
+};
+#endif
+
+#if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
+static struct resource bfin_twi0_resource[] = {
+	[0] = {
+		.start = TWI0_REGBASE,
+		.end   = TWI0_REGBASE,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = IRQ_TWI,
+		.end   = IRQ_TWI,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device i2c_bfin_twi_device = {
+	.name = "i2c-bfin-twi",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bfin_twi0_resource),
+	.resource = bfin_twi0_resource,
+};
+#endif
+
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
 static struct platform_device bfin_sport0_uart_device = {
 	.name = "bfin-sport-uart",
@@ -393,6 +441,14 @@
 	&bfin_uart_device,
 #endif
 
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+	&bfin_sir_device,
+#endif
+
+#if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
+	&i2c_bfin_twi_device,
+#endif
+
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
 	&bfin_sport0_uart_device,
 	&bfin_sport1_uart_device,
@@ -425,7 +481,7 @@
 
 static int __init cm_bf537_init(void)
 {
-	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	printk(KERN_INFO "%s(): registering device resources\n", __func__);
 	platform_add_devices(cm_bf537_devices, ARRAY_SIZE(cm_bf537_devices));
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
 	spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
diff --git a/arch/blackfin/mach-bf537/boards/generic_board.c b/arch/blackfin/mach-bf537/boards/generic_board.c
index c95395b..7d25082 100644
--- a/arch/blackfin/mach-bf537/boards/generic_board.c
+++ b/arch/blackfin/mach-bf537/boards/generic_board.c
@@ -90,7 +90,7 @@
 {
 	unsigned int num_devices = ARRAY_SIZE(bfin_isp1761_devices);
 
-	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	printk(KERN_INFO "%s(): registering device resources\n", __func__);
 	set_irq_type(ISP1761_IRQ, IRQF_TRIGGER_FALLING);
 
 	return platform_add_devices(bfin_isp1761_devices, num_devices);
@@ -554,6 +554,32 @@
 };
 #endif
 
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+static struct resource bfin_sir_resources[] = {
+#ifdef CONFIG_BFIN_SIR0
+	{
+		.start = 0xFFC00400,
+		.end = 0xFFC004FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+#ifdef CONFIG_BFIN_SIR1
+	{
+		.start = 0xFFC02000,
+		.end = 0xFFC020FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+};
+
+static struct platform_device bfin_sir_device = {
+	.name = "bfin_sir",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bfin_sir_resources),
+	.resource = bfin_sir_resources,
+};
+#endif
+
 #if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
 static struct resource bfin_twi0_resource[] = {
 	[0] = {
@@ -674,6 +700,10 @@
 	&bfin_uart_device,
 #endif
 
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+	&bfin_sir_device,
+#endif
+
 #if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
 	&i2c_bfin_twi_device,
 #endif
@@ -690,7 +720,7 @@
 
 static int __init stamp_init(void)
 {
-	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	printk(KERN_INFO "%s(): registering device resources\n", __func__);
 	platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
 	spi_register_board_info(bfin_spi_board_info,
diff --git a/arch/blackfin/mach-bf537/boards/minotaur.c b/arch/blackfin/mach-bf537/boards/minotaur.c
index d71e0be..18ddf7a5 100644
--- a/arch/blackfin/mach-bf537/boards/minotaur.c
+++ b/arch/blackfin/mach-bf537/boards/minotaur.c
@@ -8,12 +8,12 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/flash.h>
 #if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
-#include <linux/usb_isp1362.h>
+#include <linux/usb/isp1362.h>
 #endif
 #include <linux/ata_platform.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
-#include <linux/usb_sl811.h>
+#include <linux/usb/sl811.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/reboot.h>
@@ -225,6 +225,32 @@
 };
 #endif
 
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+static struct resource bfin_sir_resources[] = {
+#ifdef CONFIG_BFIN_SIR0
+	{
+		.start = 0xFFC00400,
+		.end = 0xFFC004FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+#ifdef CONFIG_BFIN_SIR1
+	{
+		.start = 0xFFC02000,
+		.end = 0xFFC020FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+};
+
+static struct platform_device bfin_sir_device = {
+	.name = "bfin_sir",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bfin_sir_resources),
+	.resource = bfin_sir_resources,
+};
+#endif
+
 #if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
 static struct resource bfin_twi0_resource[] = {
 	[0] = {
@@ -284,6 +310,10 @@
 	&bfin_uart_device,
 #endif
 
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+	&bfin_sir_device,
+#endif
+
 #if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
 	&i2c_bfin_twi_device,
 #endif
@@ -297,7 +327,7 @@
 
 static int __init minotaur_init(void)
 {
-	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	printk(KERN_INFO "%s(): registering device resources\n", __func__);
 	platform_add_devices(minotaur_devices, ARRAY_SIZE(minotaur_devices));
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
 	spi_register_board_info(bfin_spi_board_info,
diff --git a/arch/blackfin/mach-bf537/boards/pnav10.c b/arch/blackfin/mach-bf537/boards/pnav10.c
index 509a8a2..51c3bab 100644
--- a/arch/blackfin/mach-bf537/boards/pnav10.c
+++ b/arch/blackfin/mach-bf537/boards/pnav10.c
@@ -452,6 +452,31 @@
 };
 #endif
 
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+static struct resource bfin_sir_resources[] = {
+#ifdef CONFIG_BFIN_SIR0
+	{
+		.start = 0xFFC00400,
+		.end = 0xFFC004FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+#ifdef CONFIG_BFIN_SIR1
+	{
+		.start = 0xFFC02000,
+		.end = 0xFFC020FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+};
+
+static struct platform_device bfin_sir_device = {
+	.name = "bfin_sir",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bfin_sir_resources),
+	.resource = bfin_sir_resources,
+};
+#endif
 
 static struct platform_device *stamp_devices[] __initdata = {
 #if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
@@ -493,11 +518,15 @@
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
 	&bfin_uart_device,
 #endif
+
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+	&bfin_sir_device,
+#endif
 };
 
 static int __init stamp_init(void)
 {
-	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	printk(KERN_INFO "%s(): registering device resources\n", __func__);
 	platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
 	spi_register_board_info(bfin_spi_board_info,
diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c
index ea83148..0cec14b 100644
--- a/arch/blackfin/mach-bf537/boards/stamp.c
+++ b/arch/blackfin/mach-bf537/boards/stamp.c
@@ -41,6 +41,7 @@
 #include <linux/ata_platform.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
+#include <linux/i2c.h>
 #include <linux/usb/sl811.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
@@ -90,7 +91,7 @@
 {
 	unsigned int num_devices = ARRAY_SIZE(bfin_isp1761_devices);
 
-	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	printk(KERN_INFO "%s(): registering device resources\n", __func__);
 	set_irq_type(ISP1761_IRQ, IRQF_TRIGGER_FALLING);
 
 	return platform_add_devices(bfin_isp1761_devices, num_devices);
@@ -353,6 +354,7 @@
 };
 #endif
 
+#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
 static struct mtd_partition stamp_partitions[] = {
 	{
 		.name       = "Bootloader",
@@ -395,6 +397,7 @@
 	.num_resources = 1,
 	.resource      = &stamp_flash_resource,
 };
+#endif
 
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
 /* all SPI peripherals info goes here */
@@ -500,6 +503,15 @@
 };
 #endif
 
+#if defined(CONFIG_MTD_DATAFLASH) \
+	|| defined(CONFIG_MTD_DATAFLASH_MODULE)
+/* DataFlash chip */
+static struct bfin5xx_spi_chip data_flash_chip_info = {
+	.enable_dma = 0,         /* use dma transfer with this chip*/
+	.bits_per_word = 8,
+};
+#endif
+
 static struct spi_board_info bfin_spi_board_info[] __initdata = {
 #if defined(CONFIG_MTD_M25P80) \
 	|| defined(CONFIG_MTD_M25P80_MODULE)
@@ -514,7 +526,17 @@
 		.mode = SPI_MODE_3,
 	},
 #endif
-
+#if defined(CONFIG_MTD_DATAFLASH) \
+	|| defined(CONFIG_MTD_DATAFLASH_MODULE)
+	{	/* DataFlash chip */
+		.modalias = "mtd_dataflash",
+		.max_speed_hz = 25000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0, /* Framework bus number */
+		.chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/
+		.controller_data = &data_flash_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
 #if defined(CONFIG_SPI_ADC_BF533) \
 	|| defined(CONFIG_SPI_ADC_BF533_MODULE)
 	{
@@ -676,6 +698,32 @@
 };
 #endif
 
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+static struct resource bfin_sir_resources[] = {
+#ifdef CONFIG_BFIN_SIR0
+	{
+		.start = 0xFFC00400,
+		.end = 0xFFC004FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+#ifdef CONFIG_BFIN_SIR1
+	{
+		.start = 0xFFC02000,
+		.end = 0xFFC020FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+};
+
+static struct platform_device bfin_sir_device = {
+	.name = "bfin_sir",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bfin_sir_resources),
+	.resource = bfin_sir_resources,
+};
+#endif
+
 #if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
 static struct resource bfin_twi0_resource[] = {
 	[0] = {
@@ -698,6 +746,31 @@
 };
 #endif
 
+#ifdef CONFIG_I2C_BOARDINFO
+static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
+#if defined(CONFIG_JOYSTICK_AD7142) || defined(CONFIG_JOYSTICK_AD7142_MODULE)
+	{
+		I2C_BOARD_INFO("ad7142_joystick", 0x2C),
+		.type = "ad7142_joystick",
+		.irq = 55,
+	},
+#endif
+#if defined(CONFIG_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
+	{
+		I2C_BOARD_INFO("pcf8574_lcd", 0x22),
+		.type = "pcf8574_lcd",
+	},
+#endif
+#if defined(CONFIG_TWI_KEYPAD) || defined(CONFIG_TWI_KEYPAD_MODULE)
+	{
+		I2C_BOARD_INFO("pcf8574_keypad", 0x27),
+		.type = "pcf8574_keypad",
+		.irq = 72,
+	},
+#endif
+};
+#endif
+
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
 static struct platform_device bfin_sport0_uart_device = {
 	.name = "bfin-sport-uart",
@@ -800,6 +873,10 @@
 	&bfin_uart_device,
 #endif
 
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+	&bfin_sir_device,
+#endif
+
 #if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
 	&i2c_bfin_twi_device,
 #endif
@@ -818,12 +895,21 @@
 #endif
 
 	&bfin_gpios_device,
+
+#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
 	&stamp_flash_device,
+#endif
 };
 
 static int __init stamp_init(void)
 {
-	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	printk(KERN_INFO "%s(): registering device resources\n", __func__);
+
+#ifdef CONFIG_I2C_BOARDINFO
+	i2c_register_board_info(0, bfin_i2c_board_info,
+				ARRAY_SIZE(bfin_i2c_board_info));
+#endif
+
 	platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
 	spi_register_board_info(bfin_spi_board_info,
@@ -833,6 +919,7 @@
 #if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
 	irq_desc[PATA_INT].status |= IRQ_NOAUTOEN;
 #endif
+
 	return 0;
 }
 
diff --git a/arch/blackfin/mach-bf537/cpu.c b/arch/blackfin/mach-bf537/cpu.c
deleted file mode 100644
index 0442c4c..0000000
--- a/arch/blackfin/mach-bf537/cpu.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * File:         arch/blackfin/mach-bf537/cpu.c
- * Based on:
- * Author:       michael.kang@analog.com
- *
- * Created:
- * Description:  clock scaling for the bf537
- *
- * Modified:
- *               Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/cpufreq.h>
-#include <asm/dpmc.h>
-#include <linux/fs.h>
-#include <asm/bfin-global.h>
-
-/* CONFIG_CLKIN_HZ=11059200 */
-#define VCO5 (CONFIG_CLKIN_HZ*45)	/*497664000 */
-#define VCO4 (CONFIG_CLKIN_HZ*36)	/*398131200 */
-#define VCO3 (CONFIG_CLKIN_HZ*27)	/*298598400 */
-#define VCO2 (CONFIG_CLKIN_HZ*18)	/*199065600 */
-#define VCO1 (CONFIG_CLKIN_HZ*9)	/*99532800 */
-#define VCO(x) VCO##x
-
-#define MFREQ(x) {VCO(x),VCO(x)/4},{VCO(x),VCO(x)/2},{VCO(x),VCO(x)}
-/* frequency */
-static struct cpufreq_frequency_table bf537_freq_table[] = {
-	MFREQ(1),
-	MFREQ(3),
-	{VCO4, VCO4 / 2}, {VCO4, VCO4},
-	MFREQ(5),
-	{0, CPUFREQ_TABLE_END},
-};
-
-/*
- * dpmc_fops->ioctl()
- * static int dpmc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
- */
-static int bf537_getfreq(unsigned int cpu)
-{
-	unsigned long cclk_mhz;
-
-	/* The driver only support single cpu */
-	if (cpu == 0)
-		dpmc_fops.ioctl(NULL, NULL, IOCTL_GET_CORECLOCK, &cclk_mhz);
-	else
-		cclk_mhz = -1;
-
-	return cclk_mhz;
-}
-
-static int bf537_target(struct cpufreq_policy *policy,
-			    unsigned int target_freq, unsigned int relation)
-{
-	unsigned long cclk_mhz;
-	unsigned long vco_mhz;
-	unsigned long flags;
-	unsigned int index;
-	struct cpufreq_freqs freqs;
-
-	if (cpufreq_frequency_table_target(policy, bf537_freq_table, target_freq, relation, &index))
-		return -EINVAL;
-
-	cclk_mhz = bf537_freq_table[index].frequency;
-	vco_mhz = bf537_freq_table[index].index;
-
-	dpmc_fops.ioctl(NULL, NULL, IOCTL_CHANGE_FREQUENCY, &vco_mhz);
-	freqs.old = bf537_getfreq(0);
-	freqs.new = cclk_mhz;
-	freqs.cpu = 0;
-
-	pr_debug("cclk begin change to cclk %d,vco=%d,index=%d,target=%d,oldfreq=%d\n",
-	         cclk_mhz, vco_mhz, index, target_freq, freqs.old);
-
-	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-	local_irq_save(flags);
-	dpmc_fops.ioctl(NULL, NULL, IOCTL_SET_CCLK, &cclk_mhz);
-	local_irq_restore(flags);
-	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-
-	vco_mhz = get_vco();
-	cclk_mhz = get_cclk();
-	return 0;
-}
-
-/* make sure that only the "userspace" governor is run -- anything else wouldn't make sense on
- * this platform, anyway.
- */
-static int bf537_verify_speed(struct cpufreq_policy *policy)
-{
-	return cpufreq_frequency_table_verify(policy, &bf537_freq_table);
-}
-
-static int __init __bf537_cpu_init(struct cpufreq_policy *policy)
-{
-	if (policy->cpu != 0)
-		return -EINVAL;
-
-	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-
-	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
-	/*Now ,only support one cpu */
-	policy->cur = bf537_getfreq(0);
-	cpufreq_frequency_table_get_attr(bf537_freq_table, policy->cpu);
-	return cpufreq_frequency_table_cpuinfo(policy, bf537_freq_table);
-}
-
-static struct freq_attr *bf537_freq_attr[] = {
-	&cpufreq_freq_attr_scaling_available_freqs,
-	NULL,
-};
-
-static struct cpufreq_driver bf537_driver = {
-	.verify = bf537_verify_speed,
-	.target = bf537_target,
-	.get = bf537_getfreq,
-	.init = __bf537_cpu_init,
-	.name = "bf537",
-	.owner = THIS_MODULE,
-	.attr = bf537_freq_attr,
-};
-
-static int __init bf537_cpu_init(void)
-{
-	return cpufreq_register_driver(&bf537_driver);
-}
-
-static void __exit bf537_cpu_exit(void)
-{
-	cpufreq_unregister_driver(&bf537_driver);
-}
-
-MODULE_AUTHOR("Mickael Kang");
-MODULE_DESCRIPTION("cpufreq driver for BF537 CPU");
-MODULE_LICENSE("GPL");
-
-module_init(bf537_cpu_init);
-module_exit(bf537_cpu_exit);
diff --git a/arch/blackfin/mach-bf537/dma.c b/arch/blackfin/mach-bf537/dma.c
index 706cb97..4edb363 100644
--- a/arch/blackfin/mach-bf537/dma.c
+++ b/arch/blackfin/mach-bf537/dma.c
@@ -26,10 +26,12 @@
  * to the Free Software Foundation, Inc.,
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
+#include <linux/module.h>
+
 #include <asm/blackfin.h>
 #include <asm/dma.h>
 
-struct dma_register *base_addr[MAX_BLACKFIN_DMA_CHANNEL] = {
+struct dma_register *dma_io_base_addr[MAX_BLACKFIN_DMA_CHANNEL] = {
 	(struct dma_register *) DMA0_NEXT_DESC_PTR,
 	(struct dma_register *) DMA1_NEXT_DESC_PTR,
 	(struct dma_register *) DMA2_NEXT_DESC_PTR,
@@ -47,6 +49,7 @@
 	(struct dma_register *) MDMA_D1_NEXT_DESC_PTR,
 	(struct dma_register *) MDMA_S1_NEXT_DESC_PTR,
 };
+EXPORT_SYMBOL(dma_io_base_addr);
 
 int channel2irq(unsigned int channel)
 {
diff --git a/arch/blackfin/mach-bf537/head.S b/arch/blackfin/mach-bf537/head.S
index 3014fe8..48cd58a 100644
--- a/arch/blackfin/mach-bf537/head.S
+++ b/arch/blackfin/mach-bf537/head.S
@@ -37,9 +37,6 @@
 #include <asm/mach/mem_init.h>
 #endif
 
-.global __rambase
-.global __ramstart
-.global __ramend
 .extern ___bss_stop
 .extern ___bss_start
 .extern _bf53x_relocate_l1_mem
@@ -180,40 +177,28 @@
 	SSYNC;
 #endif
 
-#ifdef CONFIG_BF537_PORT_H
-	p0.h = hi(PORTH_FER);
-	p0.l = lo(PORTH_FER);
-	R0.L = W[P0]; /* Read */
-	SSYNC;
-	R0 = 0x0000;
-	W[P0] = R0.L; /* Write */
-	SSYNC;
-	W[P0] = R0.L; /* Disable peripheral function of PORTH */
-	SSYNC;
-#endif
-
 	/* Initialise UART - when booting from u-boot, the UART is not disabled
 	 * so if we dont initalize here, our serial console gets hosed */
-	p0.h = hi(UART_LCR);
-	p0.l = lo(UART_LCR);
+	p0.h = hi(BFIN_UART_LCR);
+	p0.l = lo(BFIN_UART_LCR);
 	r0 = 0x0(Z);
 	w[p0] = r0.L;	/* To enable DLL writes */
 	ssync;
 
-	p0.h = hi(UART_DLL);
-	p0.l = lo(UART_DLL);
+	p0.h = hi(BFIN_UART_DLL);
+	p0.l = lo(BFIN_UART_DLL);
 	r0 = 0x0(Z);
 	w[p0] = r0.L;
 	ssync;
 
-	p0.h = hi(UART_DLH);
-	p0.l = lo(UART_DLH);
+	p0.h = hi(BFIN_UART_DLH);
+	p0.l = lo(BFIN_UART_DLH);
 	r0 = 0x00(Z);
 	w[p0] = r0.L;
 	ssync;
 
-	p0.h = hi(UART_GCTL);
-	p0.l = lo(UART_GCTL);
+	p0.h = hi(BFIN_UART_GCTL);
+	p0.l = lo(BFIN_UART_GCTL);
 	r0 = 0x0(Z);
 	w[p0] = r0.L;	/* To enable UART clock */
 	ssync;
@@ -483,18 +468,3 @@
 	RTS;
 ENDPROC(_start_dma_code)
 #endif /* CONFIG_BFIN_KERNEL_CLOCK */
-
-.data
-
-/*
- * Set up the usable of RAM stuff. Size of RAM is determined then
- * an initial stack set up at the end.
- */
-
-.align 4
-__rambase:
-.long   0
-__ramstart:
-.long   0
-__ramend:
-.long   0
diff --git a/arch/blackfin/mach-bf548/Makefile b/arch/blackfin/mach-bf548/Makefile
index 7e7c9c8..68e5478 100644
--- a/arch/blackfin/mach-bf548/Makefile
+++ b/arch/blackfin/mach-bf548/Makefile
@@ -5,5 +5,3 @@
 extra-y := head.o
 
 obj-y := ints-priority.o dma.o
-
-obj-$(CONFIG_CPU_FREQ)   += cpu.o
diff --git a/arch/blackfin/mach-bf548/boards/Kconfig b/arch/blackfin/mach-bf548/boards/Kconfig
index 0571290..d38e526 100644
--- a/arch/blackfin/mach-bf548/boards/Kconfig
+++ b/arch/blackfin/mach-bf548/boards/Kconfig
@@ -8,5 +8,11 @@
 	bool "BF548-EZKIT"
 	help
 	  BFIN548-EZKIT board support.
+	  
+config BFIN548_BLUETECHNIX_CM
+	bool "Bluetechnix CM-BF548"
+	depends on (BF548)
+	help
+	  CM-BF548 support for DEV-Board.	  
 
 endchoice
diff --git a/arch/blackfin/mach-bf548/boards/Makefile b/arch/blackfin/mach-bf548/boards/Makefile
index a444cc7..eed161d 100644
--- a/arch/blackfin/mach-bf548/boards/Makefile
+++ b/arch/blackfin/mach-bf548/boards/Makefile
@@ -3,3 +3,4 @@
 #
 
 obj-$(CONFIG_BFIN548_EZKIT)            += ezkit.o led.o
+obj-$(CONFIG_BFIN548_BLUETECHNIX_CM)   += cm_bf548.o
diff --git a/arch/blackfin/mach-bf548/boards/cm_bf548.c b/arch/blackfin/mach-bf548/boards/cm_bf548.c
new file mode 100644
index 0000000..e3e8479
--- /dev/null
+++ b/arch/blackfin/mach-bf548/boards/cm_bf548.c
@@ -0,0 +1,664 @@
+/*
+ * File:         arch/blackfin/mach-bf548/boards/cm_bf548.c
+ * Based on:     arch/blackfin/mach-bf537/boards/ezkit.c
+ * Author:       Aidan Williams <aidan@nicta.com.au>
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2005 National ICT Australia (NICTA)
+ *               Copyright 2004-2008 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/usb/musb.h>
+#include <asm/bfin5xx_spi.h>
+#include <asm/cplb.h>
+#include <asm/dma.h>
+#include <asm/gpio.h>
+#include <asm/nand.h>
+#include <asm/portmux.h>
+#include <asm/mach/bf54x_keys.h>
+#include <linux/input.h>
+#include <linux/spi/ad7877.h>
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+const char bfin_board_name[] = "Bluetechnix CM-BF548";
+
+/*
+ *  Driver needs to know address, irq and flag pin.
+ */
+
+#if defined(CONFIG_FB_BF54X_LQ043) || defined(CONFIG_FB_BF54X_LQ043_MODULE)
+
+#include <asm/mach/bf54x-lq043.h>
+
+static struct bfin_bf54xfb_mach_info bf54x_lq043_data = {
+	.width =	480,
+	.height =	272,
+	.xres =		{480, 480, 480},
+	.yres =		{272, 272, 272},
+	.bpp =		{24, 24, 24},
+	.disp =		GPIO_PE3,
+};
+
+static struct resource bf54x_lq043_resources[] = {
+	{
+		.start = IRQ_EPPI0_ERR,
+		.end = IRQ_EPPI0_ERR,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device bf54x_lq043_device = {
+	.name		= "bf54x-lq043",
+	.id		= -1,
+	.num_resources 	= ARRAY_SIZE(bf54x_lq043_resources),
+	.resource 	= bf54x_lq043_resources,
+	.dev		= {
+		.platform_data = &bf54x_lq043_data,
+	},
+};
+#endif
+
+#if defined(CONFIG_KEYBOARD_BFIN) || defined(CONFIG_KEYBOARD_BFIN_MODULE)
+static unsigned int bf548_keymap[] = {
+	KEYVAL(0, 0, KEY_ENTER),
+	KEYVAL(0, 1, KEY_HELP),
+	KEYVAL(0, 2, KEY_0),
+	KEYVAL(0, 3, KEY_BACKSPACE),
+	KEYVAL(1, 0, KEY_TAB),
+	KEYVAL(1, 1, KEY_9),
+	KEYVAL(1, 2, KEY_8),
+	KEYVAL(1, 3, KEY_7),
+	KEYVAL(2, 0, KEY_DOWN),
+	KEYVAL(2, 1, KEY_6),
+	KEYVAL(2, 2, KEY_5),
+	KEYVAL(2, 3, KEY_4),
+	KEYVAL(3, 0, KEY_UP),
+	KEYVAL(3, 1, KEY_3),
+	KEYVAL(3, 2, KEY_2),
+	KEYVAL(3, 3, KEY_1),
+};
+
+static struct bfin_kpad_platform_data bf54x_kpad_data = {
+	.rows			= 4,
+	.cols			= 4,
+	.keymap 		= bf548_keymap,
+	.keymapsize 		= ARRAY_SIZE(bf548_keymap),
+	.repeat			= 0,
+	.debounce_time		= 5000,	/* ns (5ms) */
+	.coldrive_time		= 1000, /* ns (1ms) */
+	.keyup_test_interval	= 50, /* ms (50ms) */
+};
+
+static struct resource bf54x_kpad_resources[] = {
+	{
+		.start = IRQ_KEY,
+		.end = IRQ_KEY,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device bf54x_kpad_device = {
+	.name		= "bf54x-keys",
+	.id		= -1,
+	.num_resources 	= ARRAY_SIZE(bf54x_kpad_resources),
+	.resource 	= bf54x_kpad_resources,
+	.dev		= {
+		.platform_data = &bf54x_kpad_data,
+	},
+};
+#endif
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+static struct platform_device rtc_device = {
+	.name = "rtc-bfin",
+	.id   = -1,
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+static struct resource bfin_uart_resources[] = {
+#ifdef CONFIG_SERIAL_BFIN_UART0
+	{
+		.start = 0xFFC00400,
+		.end = 0xFFC004FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+	{
+		.start = 0xFFC02000,
+		.end = 0xFFC020FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART2
+	{
+		.start = 0xFFC02100,
+		.end = 0xFFC021FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART3
+	{
+		.start = 0xFFC03100,
+		.end = 0xFFC031FF,
+	},
+#endif
+};
+
+static struct platform_device bfin_uart_device = {
+	.name = "bfin-uart",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(bfin_uart_resources),
+	.resource = bfin_uart_resources,
+};
+#endif
+
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+static struct resource bfin_sir_resources[] = {
+#ifdef CONFIG_BFIN_SIR0
+	{
+		.start = 0xFFC00400,
+		.end = 0xFFC004FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+#ifdef CONFIG_BFIN_SIR1
+	{
+		.start = 0xFFC02000,
+		.end = 0xFFC020FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+#ifdef CONFIG_BFIN_SIR2
+	{
+		.start = 0xFFC02100,
+		.end = 0xFFC021FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+#ifdef CONFIG_BFIN_SIR3
+	{
+		.start = 0xFFC03100,
+		.end = 0xFFC031FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+};
+
+static struct platform_device bfin_sir_device = {
+	.name = "bfin_sir",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bfin_sir_resources),
+	.resource = bfin_sir_resources,
+};
+#endif
+
+#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
+static struct resource smsc911x_resources[] = {
+	{
+		.name = "smsc911x-memory",
+		.start = 0x24000000,
+		.end = 0x24000000 + 0xFF,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = IRQ_PE6,
+		.end = IRQ_PE6,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
+	},
+};
+static struct platform_device smsc911x_device = {
+	.name = "smsc911x",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(smsc911x_resources),
+	.resource = smsc911x_resources,
+};
+#endif
+
+#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
+static struct resource musb_resources[] = {
+	[0] = {
+		.start	= 0xFFC03C00,
+		.end	= 0xFFC040FF,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {	/* general IRQ */
+		.start	= IRQ_USB_INT0,
+		.end	= IRQ_USB_INT0,
+		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+	[2] = {	/* DMA IRQ */
+		.start	= IRQ_USB_DMA,
+		.end	= IRQ_USB_DMA,
+		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+};
+
+static struct musb_hdrc_platform_data musb_plat = {
+#if defined(CONFIG_USB_MUSB_OTG)
+	.mode		= MUSB_OTG,
+#elif defined(CONFIG_USB_MUSB_HDRC_HCD)
+	.mode		= MUSB_HOST,
+#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
+	.mode		= MUSB_PERIPHERAL,
+#endif
+	.multipoint	= 0,
+};
+
+static u64 musb_dmamask = ~(u32)0;
+
+static struct platform_device musb_device = {
+	.name		= "musb_hdrc",
+	.id		= 0,
+	.dev = {
+		.dma_mask		= &musb_dmamask,
+		.coherent_dma_mask	= 0xffffffff,
+		.platform_data		= &musb_plat,
+	},
+	.num_resources	= ARRAY_SIZE(musb_resources),
+	.resource	= musb_resources,
+};
+#endif
+
+#if defined(CONFIG_PATA_BF54X) || defined(CONFIG_PATA_BF54X_MODULE)
+static struct resource bfin_atapi_resources[] = {
+	{
+		.start = 0xFFC03800,
+		.end = 0xFFC0386F,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = IRQ_ATAPI_ERR,
+		.end = IRQ_ATAPI_ERR,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device bfin_atapi_device = {
+	.name = "pata-bf54x",
+	.id = -1,
+	.num_resources = ARRAY_SIZE(bfin_atapi_resources),
+	.resource = bfin_atapi_resources,
+};
+#endif
+
+#if defined(CONFIG_MTD_NAND_BF5XX) || defined(CONFIG_MTD_NAND_BF5XX_MODULE)
+static struct mtd_partition partition_info[] = {
+	{
+		.name = "Linux Kernel",
+		.offset = 0,
+		.size = 4 * SIZE_1M,
+	},
+	{
+		.name = "File System",
+		.offset = 4 * SIZE_1M,
+		.size = (256 - 4) * SIZE_1M,
+	},
+};
+
+static struct bf5xx_nand_platform bf5xx_nand_platform = {
+	.page_size = NFC_PG_SIZE_256,
+	.data_width = NFC_NWIDTH_8,
+	.partitions = partition_info,
+	.nr_partitions = ARRAY_SIZE(partition_info),
+	.rd_dly = 3,
+	.wr_dly = 3,
+};
+
+static struct resource bf5xx_nand_resources[] = {
+	{
+		.start = 0xFFC03B00,
+		.end = 0xFFC03B4F,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = CH_NFC,
+		.end = CH_NFC,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device bf5xx_nand_device = {
+	.name = "bf5xx-nand",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bf5xx_nand_resources),
+	.resource = bf5xx_nand_resources,
+	.dev = {
+		.platform_data = &bf5xx_nand_platform,
+	},
+};
+#endif
+
+#if defined(CONFIG_SDH_BFIN) || defined(CONFIG_SDH_BFIN_MODULE)
+static struct platform_device bf54x_sdh_device = {
+	.name = "bfin-sdh",
+	.id = 0,
+};
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+/* all SPI peripherals info goes here */
+#if defined(CONFIG_MTD_M25P80) \
+	|| defined(CONFIG_MTD_M25P80_MODULE)
+/* SPI flash chip (m25p16) */
+static struct mtd_partition bfin_spi_flash_partitions[] = {
+	{
+		.name = "bootloader",
+		.size = 0x00040000,
+		.offset = 0,
+		.mask_flags = MTD_CAP_ROM
+	}, {
+		.name = "linux kernel",
+		.size = 0x1c0000,
+		.offset = 0x40000
+	}
+};
+
+static struct flash_platform_data bfin_spi_flash_data = {
+	.name = "m25p80",
+	.parts = bfin_spi_flash_partitions,
+	.nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
+	.type = "m25p16",
+};
+
+static struct bfin5xx_spi_chip spi_flash_chip_info = {
+	.enable_dma = 0,         /* use dma transfer with this chip*/
+	.bits_per_word = 8,
+	.cs_change_per_word = 0,
+};
+#endif
+
+#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
+static struct bfin5xx_spi_chip spi_ad7877_chip_info = {
+	.cs_change_per_word = 0,
+	.enable_dma = 0,
+	.bits_per_word = 16,
+};
+
+static const struct ad7877_platform_data bfin_ad7877_ts_info = {
+	.model			= 7877,
+	.vref_delay_usecs	= 50,	/* internal, no capacitor */
+	.x_plate_ohms		= 419,
+	.y_plate_ohms		= 486,
+	.pressure_max		= 1000,
+	.pressure_min		= 0,
+	.stopacq_polarity 	= 1,
+	.first_conversion_delay = 3,
+	.acquisition_time 	= 1,
+	.averaging 		= 1,
+	.pen_down_acc_interval 	= 1,
+};
+#endif
+
+#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
+static struct bfin5xx_spi_chip spidev_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 8,
+};
+#endif
+
+static struct spi_board_info bf54x_spi_board_info[] __initdata = {
+#if defined(CONFIG_MTD_M25P80) \
+	|| defined(CONFIG_MTD_M25P80_MODULE)
+	{
+		/* the modalias must be the same as spi device driver name */
+		.modalias = "m25p80", /* Name of spi_driver for this device */
+		.max_speed_hz = 25000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0, /* Framework bus number */
+		.chip_select = 1, /* SPI_SSEL1*/
+		.platform_data = &bfin_spi_flash_data,
+		.controller_data = &spi_flash_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
+#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
+{
+	.modalias		= "ad7877",
+	.platform_data		= &bfin_ad7877_ts_info,
+	.irq			= IRQ_PJ11,
+	.max_speed_hz		= 12500000,     /* max spi clock (SCK) speed in HZ */
+	.bus_num		= 0,
+	.chip_select  		= 2,
+	.controller_data = &spi_ad7877_chip_info,
+},
+#endif
+#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
+	{
+		.modalias = "spidev",
+		.max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 1,
+		.controller_data = &spidev_chip_info,
+	},
+#endif
+};
+
+/* SPI (0) */
+static struct resource bfin_spi0_resource[] = {
+	[0] = {
+		.start = SPI0_REGBASE,
+		.end   = SPI0_REGBASE + 0xFF,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = CH_SPI0,
+		.end   = CH_SPI0,
+		.flags = IORESOURCE_IRQ,
+	}
+};
+
+/* SPI (1) */
+static struct resource bfin_spi1_resource[] = {
+	[0] = {
+		.start = SPI1_REGBASE,
+		.end   = SPI1_REGBASE + 0xFF,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = CH_SPI1,
+		.end   = CH_SPI1,
+		.flags = IORESOURCE_IRQ,
+	}
+};
+
+/* SPI controller data */
+static struct bfin5xx_spi_master bf54x_spi_master_info0 = {
+	.num_chipselect = 8,
+	.enable_dma = 1,  /* master has the ability to do dma transfer */
+	.pin_req = {P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0},
+};
+
+static struct platform_device bf54x_spi_master0 = {
+	.name = "bfin-spi",
+	.id = 0, /* Bus number */
+	.num_resources = ARRAY_SIZE(bfin_spi0_resource),
+	.resource = bfin_spi0_resource,
+	.dev = {
+		.platform_data = &bf54x_spi_master_info0, /* Passed to driver */
+		},
+};
+
+static struct bfin5xx_spi_master bf54x_spi_master_info1 = {
+	.num_chipselect = 8,
+	.enable_dma = 1,  /* master has the ability to do dma transfer */
+	.pin_req = {P_SPI1_SCK, P_SPI1_MISO, P_SPI1_MOSI, 0},
+};
+
+static struct platform_device bf54x_spi_master1 = {
+	.name = "bfin-spi",
+	.id = 1, /* Bus number */
+	.num_resources = ARRAY_SIZE(bfin_spi1_resource),
+	.resource = bfin_spi1_resource,
+	.dev = {
+		.platform_data = &bf54x_spi_master_info1, /* Passed to driver */
+		},
+};
+#endif  /* spi master and devices */
+
+#if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
+static struct resource bfin_twi0_resource[] = {
+	[0] = {
+		.start = TWI0_REGBASE,
+		.end   = TWI0_REGBASE + 0xFF,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = IRQ_TWI0,
+		.end   = IRQ_TWI0,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device i2c_bfin_twi0_device = {
+	.name = "i2c-bfin-twi",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bfin_twi0_resource),
+	.resource = bfin_twi0_resource,
+};
+
+#if !defined(CONFIG_BF542)	/* The BF542 only has 1 TWI */
+static struct resource bfin_twi1_resource[] = {
+	[0] = {
+		.start = TWI1_REGBASE,
+		.end   = TWI1_REGBASE + 0xFF,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = IRQ_TWI1,
+		.end   = IRQ_TWI1,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device i2c_bfin_twi1_device = {
+	.name = "i2c-bfin-twi",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(bfin_twi1_resource),
+	.resource = bfin_twi1_resource,
+};
+#endif
+#endif
+
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+#include <linux/gpio_keys.h>
+
+static struct gpio_keys_button bfin_gpio_keys_table[] = {
+	{BTN_0, GPIO_PH7, 1, "gpio-keys: BTN0"},
+};
+
+static struct gpio_keys_platform_data bfin_gpio_keys_data = {
+	.buttons        = bfin_gpio_keys_table,
+	.nbuttons       = ARRAY_SIZE(bfin_gpio_keys_table),
+};
+
+static struct platform_device bfin_device_gpiokeys = {
+	.name      = "gpio-keys",
+	.dev = {
+		.platform_data = &bfin_gpio_keys_data,
+	},
+};
+#endif
+
+static struct platform_device *cm_bf548_devices[] __initdata = {
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+	&rtc_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+	&bfin_uart_device,
+#endif
+
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+	&bfin_sir_device,
+#endif
+
+#if defined(CONFIG_FB_BF54X_LQ043) || defined(CONFIG_FB_BF54X_LQ043_MODULE)
+	&bf54x_lq043_device,
+#endif
+
+#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
+	&smsc911x_device,
+#endif
+
+#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
+	&musb_device,
+#endif
+
+#if defined(CONFIG_PATA_BF54X) || defined(CONFIG_PATA_BF54X_MODULE)
+	&bfin_atapi_device,
+#endif
+
+#if defined(CONFIG_MTD_NAND_BF5XX) || defined(CONFIG_MTD_NAND_BF5XX_MODULE)
+	&bf5xx_nand_device,
+#endif
+
+#if defined(CONFIG_SDH_BFIN) || defined(CONFIG_SDH_BFIN_MODULE)
+	&bf54x_sdh_device,
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+	&bf54x_spi_master0,
+	&bf54x_spi_master1,
+#endif
+
+#if defined(CONFIG_KEYBOARD_BFIN) || defined(CONFIG_KEYBOARD_BFIN_MODULE)
+	&bf54x_kpad_device,
+#endif
+
+#if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
+/*	&i2c_bfin_twi0_device, */
+#if !defined(CONFIG_BF542)
+	&i2c_bfin_twi1_device,
+#endif
+#endif
+
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+	&bfin_device_gpiokeys,
+#endif
+};
+
+static int __init cm_bf548_init(void)
+{
+	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	platform_add_devices(cm_bf548_devices, ARRAY_SIZE(cm_bf548_devices));
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+	spi_register_board_info(bf54x_spi_board_info,
+			ARRAY_SIZE(bf54x_spi_board_info));
+#endif
+
+	return 0;
+}
+
+arch_initcall(cm_bf548_init);
diff --git a/arch/blackfin/mach-bf548/boards/ezkit.c b/arch/blackfin/mach-bf548/boards/ezkit.c
index 40846aa..231dfbd3 100644
--- a/arch/blackfin/mach-bf548/boards/ezkit.c
+++ b/arch/blackfin/mach-bf548/boards/ezkit.c
@@ -36,6 +36,7 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/flash.h>
 #include <linux/irq.h>
+#include <linux/i2c.h>
 #include <linux/interrupt.h>
 #if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
 #include <linux/usb/musb.h>
@@ -187,6 +188,46 @@
 };
 #endif
 
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+static struct resource bfin_sir_resources[] = {
+#ifdef CONFIG_BFIN_SIR0
+	{
+		.start = 0xFFC00400,
+		.end = 0xFFC004FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+#ifdef CONFIG_BFIN_SIR1
+	{
+		.start = 0xFFC02000,
+		.end = 0xFFC020FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+#ifdef CONFIG_BFIN_SIR2
+	{
+		.start = 0xFFC02100,
+		.end = 0xFFC021FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+#ifdef CONFIG_BFIN_SIR3
+	{
+		.start = 0xFFC03100,
+		.end = 0xFFC031FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+};
+
+static struct platform_device bfin_sir_device = {
+	.name = "bfin_sir",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bfin_sir_resources),
+	.resource = bfin_sir_resources,
+};
+#endif
+
 #if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
 static struct resource smsc911x_resources[] = {
 	{
@@ -330,6 +371,7 @@
 };
 #endif
 
+#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
 static struct mtd_partition ezkit_partitions[] = {
 	{
 		.name       = "Bootloader",
@@ -337,7 +379,7 @@
 		.offset     = 0,
 	}, {
 		.name       = "Kernel",
-		.size       = 0xE0000,
+		.size       = 0x1C0000,
 		.offset     = MTDPART_OFS_APPEND,
 	}, {
 		.name       = "RootFS",
@@ -367,6 +409,7 @@
 	.num_resources = 1,
 	.resource      = &ezkit_flash_resource,
 };
+#endif
 
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
 /* all SPI peripherals info goes here */
@@ -400,6 +443,14 @@
 };
 #endif
 
+#if defined(CONFIG_SND_BLACKFIN_AD1836) \
+	|| defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 16,
+};
+#endif
+
 #if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
 static struct bfin5xx_spi_chip spi_ad7877_chip_info = {
 	.cs_change_per_word = 0,
@@ -443,6 +494,16 @@
 		.mode = SPI_MODE_3,
 	},
 #endif
+#if defined(CONFIG_SND_BLACKFIN_AD1836) \
+	|| defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+	{
+		.modalias = "ad1836-spi",
+		.max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1,
+		.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+		.controller_data = &ad1836_spi_chip_info,
+	},
+#endif
 #if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
 {
 	.modalias		= "ad7877",
@@ -571,6 +632,29 @@
 #endif
 #endif
 
+#ifdef CONFIG_I2C_BOARDINFO
+static struct i2c_board_info __initdata bfin_i2c_board_info0[] = {
+};
+
+#if !defined(CONFIG_BF542)	/* The BF542 only has 1 TWI */
+static struct i2c_board_info __initdata bfin_i2c_board_info1[] = {
+#if defined(CONFIG_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
+	{
+		I2C_BOARD_INFO("pcf8574_lcd", 0x22),
+		.type = "pcf8574_lcd",
+	},
+#endif
+#if defined(CONFIG_TWI_KEYPAD) || defined(CONFIG_TWI_KEYPAD_MODULE)
+	{
+		I2C_BOARD_INFO("pcf8574_keypad", 0x27),
+		.type = "pcf8574_keypad",
+		.irq = 212,
+	},
+#endif
+};
+#endif
+#endif
+
 #if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
 #include <linux/gpio_keys.h>
 
@@ -616,6 +700,10 @@
 	&bfin_uart_device,
 #endif
 
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+	&bfin_sir_device,
+#endif
+
 #if defined(CONFIG_FB_BF54X_LQ043) || defined(CONFIG_FB_BF54X_LQ043_MODULE)
 	&bf54x_lq043_device,
 #endif
@@ -661,12 +749,25 @@
 #endif
 
 	&bfin_gpios_device,
+
+#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
 	&ezkit_flash_device,
+#endif
 };
 
 static int __init ezkit_init(void)
 {
-	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	printk(KERN_INFO "%s(): registering device resources\n", __func__);
+
+#ifdef CONFIG_I2C_BOARDINFO
+	i2c_register_board_info(0, bfin_i2c_board_info0,
+				ARRAY_SIZE(bfin_i2c_board_info0));
+#if !defined(CONFIG_BF542)	/* The BF542 only has 1 TWI */
+	i2c_register_board_info(1, bfin_i2c_board_info1,
+				ARRAY_SIZE(bfin_i2c_board_info1));
+#endif
+#endif
+
 	platform_add_devices(ezkit_devices, ARRAY_SIZE(ezkit_devices));
 
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
diff --git a/arch/blackfin/mach-bf548/cpu.c b/arch/blackfin/mach-bf548/cpu.c
deleted file mode 100644
index 4298a3c..0000000
--- a/arch/blackfin/mach-bf548/cpu.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * File:         arch/blackfin/mach-bf548/cpu.c
- * Based on:
- * Author:
- *
- * Created:
- * Description:  clock scaling for the bf54x
- *
- * Modified:
- *               Copyright 2004-2007 Analog Devices Inc.
- *
- * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/cpufreq.h>
-#include <asm/dpmc.h>
-#include <linux/fs.h>
-#include <asm/bfin-global.h>
-
-/* CONFIG_CLKIN_HZ=25000000 */
-#define VCO5 (CONFIG_CLKIN_HZ*45)
-#define VCO4 (CONFIG_CLKIN_HZ*36)
-#define VCO3 (CONFIG_CLKIN_HZ*27)
-#define VCO2 (CONFIG_CLKIN_HZ*18)
-#define VCO1 (CONFIG_CLKIN_HZ*9)
-#define VCO(x) VCO##x
-
-#define MFREQ(x) {VCO(x),VCO(x)/4},{VCO(x),VCO(x)/2},{VCO(x),VCO(x)}
-/* frequency */
-static struct cpufreq_frequency_table bf548_freq_table[] = {
-	MFREQ(1),
-	MFREQ(3),
-	{VCO4, VCO4 / 2}, {VCO4, VCO4},
-	MFREQ(5),
-	{0, CPUFREQ_TABLE_END},
-};
-
-/*
- * dpmc_fops->ioctl()
- * static int dpmc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
- */
-static int bf548_getfreq(unsigned int cpu)
-{
-	unsigned long cclk_mhz;
-
-	/* The driver only support single cpu */
-	if (cpu == 0)
-		dpmc_fops.ioctl(NULL, NULL, IOCTL_GET_CORECLOCK, &cclk_mhz);
-	else
-		cclk_mhz = -1;
-
-	return cclk_mhz;
-}
-
-static int bf548_target(struct cpufreq_policy *policy,
-			    unsigned int target_freq, unsigned int relation)
-{
-	unsigned long cclk_mhz;
-	unsigned long vco_mhz;
-	unsigned long flags;
-	unsigned int index;
-	struct cpufreq_freqs freqs;
-
-	if (cpufreq_frequency_table_target(policy, bf548_freq_table, target_freq, relation, &index))
-		return -EINVAL;
-
-	cclk_mhz = bf548_freq_table[index].frequency;
-	vco_mhz = bf548_freq_table[index].index;
-
-	dpmc_fops.ioctl(NULL, NULL, IOCTL_CHANGE_FREQUENCY, &vco_mhz);
-	freqs.old = bf548_getfreq(0);
-	freqs.new = cclk_mhz;
-	freqs.cpu = 0;
-
-	pr_debug("cclk begin change to cclk %d,vco=%d,index=%d,target=%d,oldfreq=%d\n",
-	         cclk_mhz, vco_mhz, index, target_freq, freqs.old);
-
-	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-	local_irq_save(flags);
-	dpmc_fops.ioctl(NULL, NULL, IOCTL_SET_CCLK, &cclk_mhz);
-	local_irq_restore(flags);
-	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-
-	vco_mhz = get_vco();
-	cclk_mhz = get_cclk();
-	return 0;
-}
-
-/* make sure that only the "userspace" governor is run -- anything else wouldn't make sense on
- * this platform, anyway.
- */
-static int bf548_verify_speed(struct cpufreq_policy *policy)
-{
-	return cpufreq_frequency_table_verify(policy, &bf548_freq_table);
-}
-
-static int __init __bf548_cpu_init(struct cpufreq_policy *policy)
-{
-	if (policy->cpu != 0)
-		return -EINVAL;
-
-	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-
-	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
-	/*Now ,only support one cpu */
-	policy->cur = bf548_getfreq(0);
-	cpufreq_frequency_table_get_attr(bf548_freq_table, policy->cpu);
-	return cpufreq_frequency_table_cpuinfo(policy, bf548_freq_table);
-}
-
-static struct freq_attr *bf548_freq_attr[] = {
-	&cpufreq_freq_attr_scaling_available_freqs,
-	NULL,
-};
-
-static struct cpufreq_driver bf548_driver = {
-	.verify = bf548_verify_speed,
-	.target = bf548_target,
-	.get = bf548_getfreq,
-	.init = __bf548_cpu_init,
-	.name = "bf548",
-	.owner = THIS_MODULE,
-	.attr = bf548_freq_attr,
-};
-
-static int __init bf548_cpu_init(void)
-{
-	return cpufreq_register_driver(&bf548_driver);
-}
-
-static void __exit bf548_cpu_exit(void)
-{
-	cpufreq_unregister_driver(&bf548_driver);
-}
-
-MODULE_AUTHOR("Mickael Kang");
-MODULE_DESCRIPTION("cpufreq driver for BF548 CPU");
-MODULE_LICENSE("GPL");
-
-module_init(bf548_cpu_init);
-module_exit(bf548_cpu_exit);
diff --git a/arch/blackfin/mach-bf548/dma.c b/arch/blackfin/mach-bf548/dma.c
index f547929..74730eb 100644
--- a/arch/blackfin/mach-bf548/dma.c
+++ b/arch/blackfin/mach-bf548/dma.c
@@ -32,7 +32,7 @@
 #include <asm/blackfin.h>
 #include <asm/dma.h>
 
- struct dma_register *base_addr[MAX_BLACKFIN_DMA_CHANNEL] = {
+struct dma_register *dma_io_base_addr[MAX_BLACKFIN_DMA_CHANNEL] = {
 	(struct dma_register *) DMA0_NEXT_DESC_PTR,
 	(struct dma_register *) DMA1_NEXT_DESC_PTR,
 	(struct dma_register *) DMA2_NEXT_DESC_PTR,
@@ -66,7 +66,7 @@
 	(struct dma_register *) MDMA_D3_NEXT_DESC_PTR,
 	(struct dma_register *) MDMA_S3_NEXT_DESC_PTR,
 };
-EXPORT_SYMBOL(base_addr);
+EXPORT_SYMBOL(dma_io_base_addr);
 
 int channel2irq(unsigned int channel)
 {
diff --git a/arch/blackfin/mach-bf548/head.S b/arch/blackfin/mach-bf548/head.S
index 46222a7..f719114 100644
--- a/arch/blackfin/mach-bf548/head.S
+++ b/arch/blackfin/mach-bf548/head.S
@@ -36,9 +36,6 @@
 #include <asm/mach/mem_init.h>
 #endif
 
-.global __rambase
-.global __ramstart
-.global __ramend
 .extern ___bss_stop
 .extern ___bss_start
 .extern _bf53x_relocate_l1_mem
@@ -456,18 +453,3 @@
 	RTS;
 ENDPROC(_start_dma_code)
 #endif /* CONFIG_BFIN_KERNEL_CLOCK */
-
-.data
-
-/*
- * Set up the usable of RAM stuff. Size of RAM is determined then
- * an initial stack set up at the end.
- */
-
-.align 4
-__rambase:
-.long   0
-__ramstart:
-.long   0
-__ramend:
-.long   0
diff --git a/arch/blackfin/mach-bf561/boards/cm_bf561.c b/arch/blackfin/mach-bf561/boards/cm_bf561.c
index bf9e738..9fd5809 100644
--- a/arch/blackfin/mach-bf561/boards/cm_bf561.c
+++ b/arch/blackfin/mach-bf561/boards/cm_bf561.c
@@ -283,6 +283,25 @@
 };
 #endif
 
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+static struct resource bfin_sir_resources[] = {
+#ifdef CONFIG_BFIN_SIR0
+	{
+		.start = 0xFFC00400,
+		.end = 0xFFC004FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+};
+
+static struct platform_device bfin_sir_device = {
+	.name = "bfin_sir",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bfin_sir_resources),
+	.resource = bfin_sir_resources,
+};
+#endif
+
 #if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
 #define PATA_INT	119
 
@@ -330,6 +349,10 @@
 	&bfin_uart_device,
 #endif
 
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+	&bfin_sir_device,
+#endif
+
 #if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
 	&isp1362_hcd_device,
 #endif
@@ -349,7 +372,7 @@
 
 static int __init cm_bf561_init(void)
 {
-	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	printk(KERN_INFO "%s(): registering device resources\n", __func__);
 	platform_add_devices(cm_bf561_devices, ARRAY_SIZE(cm_bf561_devices));
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
 	spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
diff --git a/arch/blackfin/mach-bf561/boards/ezkit.c b/arch/blackfin/mach-bf561/boards/ezkit.c
index d357f64..0d74b7d 100644
--- a/arch/blackfin/mach-bf561/boards/ezkit.c
+++ b/arch/blackfin/mach-bf561/boards/ezkit.c
@@ -78,7 +78,7 @@
 {
 	unsigned int num_devices = ARRAY_SIZE(bfin_isp1761_devices);
 
-	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	printk(KERN_INFO "%s(): registering device resources\n", __func__);
 	set_irq_type(ISP1761_IRQ, IRQF_TRIGGER_FALLING);
 
 	return platform_add_devices(bfin_isp1761_devices, num_devices);
@@ -220,6 +220,26 @@
 };
 #endif
 
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+static struct resource bfin_sir_resources[] = {
+#ifdef CONFIG_BFIN_SIR0
+	{
+		.start = 0xFFC00400,
+		.end = 0xFFC004FF,
+		.flags = IORESOURCE_MEM,
+	},
+#endif
+};
+
+static struct platform_device bfin_sir_device = {
+	.name = "bfin_sir",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bfin_sir_resources),
+	.resource = bfin_sir_resources,
+};
+#endif
+
+#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
 static struct mtd_partition ezkit_partitions[] = {
 	{
 		.name       = "Bootloader",
@@ -227,7 +247,7 @@
 		.offset     = 0,
 	}, {
 		.name       = "Kernel",
-		.size       = 0xE0000,
+		.size       = 0x1C0000,
 		.offset     = MTDPART_OFS_APPEND,
 	}, {
 		.name       = "RootFS",
@@ -257,6 +277,7 @@
 	.num_resources = 1,
 	.resource      = &ezkit_flash_resource,
 };
+#endif
 
 #ifdef CONFIG_SPI_BFIN
 #if defined(CONFIG_SND_BLACKFIN_AD1836) \
@@ -443,6 +464,10 @@
 	&bfin_uart_device,
 #endif
 
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+	&bfin_sir_device,
+#endif
+
 #if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
 	&bfin_pata_device,
 #endif
@@ -460,7 +485,10 @@
 #endif
 
 	&bfin_gpios_device,
+
+#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
 	&ezkit_flash_device,
+#endif
 };
 
 static int __init ezkit_init(void)
diff --git a/arch/blackfin/mach-bf561/boards/generic_board.c b/arch/blackfin/mach-bf561/boards/generic_board.c
index fc80c5d..2faa007 100644
--- a/arch/blackfin/mach-bf561/boards/generic_board.c
+++ b/arch/blackfin/mach-bf561/boards/generic_board.c
@@ -70,7 +70,7 @@
 
 static int __init generic_board_init(void)
 {
-	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	printk(KERN_INFO "%s(): registering device resources\n", __func__);
 	return platform_add_devices(generic_board_devices,
 				    ARRAY_SIZE(generic_board_devices));
 }
diff --git a/arch/blackfin/mach-bf561/boards/tepla.c b/arch/blackfin/mach-bf561/boards/tepla.c
index ec6a220..c9174b3 100644
--- a/arch/blackfin/mach-bf561/boards/tepla.c
+++ b/arch/blackfin/mach-bf561/boards/tepla.c
@@ -50,7 +50,7 @@
 
 static int __init tepla_init(void)
 {
-	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	printk(KERN_INFO "%s(): registering device resources\n", __func__);
 	return platform_add_devices(tepla_devices, ARRAY_SIZE(tepla_devices));
 }
 
diff --git a/arch/blackfin/mach-bf561/dma.c b/arch/blackfin/mach-bf561/dma.c
index 89c65bb..24415eb 100644
--- a/arch/blackfin/mach-bf561/dma.c
+++ b/arch/blackfin/mach-bf561/dma.c
@@ -26,10 +26,12 @@
  * to the Free Software Foundation, Inc.,
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
+#include <linux/module.h>
+
 #include <asm/blackfin.h>
 #include <asm/dma.h>
 
-struct dma_register *base_addr[MAX_BLACKFIN_DMA_CHANNEL] = {
+struct dma_register *dma_io_base_addr[MAX_BLACKFIN_DMA_CHANNEL] = {
 	(struct dma_register *) DMA1_0_NEXT_DESC_PTR,
 	(struct dma_register *) DMA1_1_NEXT_DESC_PTR,
 	(struct dma_register *) DMA1_2_NEXT_DESC_PTR,
@@ -67,6 +69,7 @@
 	(struct dma_register *) IMDMA_D1_NEXT_DESC_PTR,
 	(struct dma_register *) IMDMA_S1_NEXT_DESC_PTR,
 };
+EXPORT_SYMBOL(dma_io_base_addr);
 
 int channel2irq(unsigned int channel)
 {
diff --git a/arch/blackfin/mach-bf561/head.S b/arch/blackfin/mach-bf561/head.S
index 96a3d45..5b8bd40 100644
--- a/arch/blackfin/mach-bf561/head.S
+++ b/arch/blackfin/mach-bf561/head.S
@@ -37,9 +37,6 @@
 #include <asm/mach/mem_init.h>
 #endif
 
-.global __rambase
-.global __ramstart
-.global __ramend
 .extern ___bss_stop
 .extern ___bss_start
 .extern _bf53x_relocate_l1_mem
@@ -139,26 +136,26 @@
 
 	/* Initialise UART - when booting from u-boot, the UART is not disabled
 	 * so if we dont initalize here, our serial console gets hosed */
-	p0.h = hi(UART_LCR);
-	p0.l = lo(UART_LCR);
+	p0.h = hi(BFIN_UART_LCR);
+	p0.l = lo(BFIN_UART_LCR);
 	r0 = 0x0(Z);
 	w[p0] = r0.L;	/* To enable DLL writes */
 	ssync;
 
-	p0.h = hi(UART_DLL);
-	p0.l = lo(UART_DLL);
+	p0.h = hi(BFIN_UART_DLL);
+	p0.l = lo(BFIN_UART_DLL);
 	r0 = 0x0(Z);
 	w[p0] = r0.L;
 	ssync;
 
-	p0.h = hi(UART_DLH);
-	p0.l = lo(UART_DLH);
+	p0.h = hi(BFIN_UART_DLH);
+	p0.l = lo(BFIN_UART_DLH);
 	r0 = 0x00(Z);
 	w[p0] = r0.L;
 	ssync;
 
-	p0.h = hi(UART_GCTL);
-	p0.l = lo(UART_GCTL);
+	p0.h = hi(BFIN_UART_GCTL);
+	p0.l = lo(BFIN_UART_GCTL);
 	r0 = 0x0(Z);
 	w[p0] = r0.L;	/* To enable UART clock */
 	ssync;
@@ -411,18 +408,3 @@
 	RTS;
 ENDPROC(_start_dma_code)
 #endif /* CONFIG_BFIN_KERNEL_CLOCK */
-
-.data
-
-/*
- * Set up the usable of RAM stuff. Size of RAM is determined then
- * an initial stack set up at the end.
- */
-
-.align 4
-__rambase:
-.long   0
-__ramstart:
-.long   0
-__ramend:
-.long   0
diff --git a/arch/blackfin/mach-common/Makefile b/arch/blackfin/mach-common/Makefile
index 15e33ca..393081e 100644
--- a/arch/blackfin/mach-common/Makefile
+++ b/arch/blackfin/mach-common/Makefile
@@ -6,4 +6,5 @@
 	cache.o cacheinit.o entry.o \
 	interrupt.o lock.o irqpanic.o arch_checks.o ints-priority.o
 
-obj-$(CONFIG_PM)                 += pm.o dpmc.o
+obj-$(CONFIG_PM)         += pm.o dpmc.o
+obj-$(CONFIG_CPU_FREQ)   += cpufreq.o
diff --git a/arch/blackfin/mach-common/arch_checks.c b/arch/blackfin/mach-common/arch_checks.c
index 2f6ce39..caaab49 100644
--- a/arch/blackfin/mach-common/arch_checks.c
+++ b/arch/blackfin/mach-common/arch_checks.c
@@ -54,7 +54,8 @@
 
 #endif /* CONFIG_BFIN_KERNEL_CLOCK */
 
+#ifdef CONFIG_MEM_SIZE
 #if (CONFIG_MEM_SIZE % 4)
 #error "SDRAM mem size must be multible of 4MB"
 #endif
-
+#endif
diff --git a/arch/blackfin/mach-common/cpufreq.c b/arch/blackfin/mach-common/cpufreq.c
new file mode 100644
index 0000000..ed81e00
--- /dev/null
+++ b/arch/blackfin/mach-common/cpufreq.c
@@ -0,0 +1,194 @@
+/*
+ * File:	 arch/blackfin/mach-common/cpufreq.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:	 Blackfin core clock scaling
+ *
+ * Modified:
+ *		 Copyright 2004-2008 Analog Devices Inc.
+ *
+ * Bugs:	 Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA	02110-1301	USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/fs.h>
+#include <asm/blackfin.h>
+#include <asm/time.h>
+
+
+/* this is the table of CCLK frequencies, in Hz */
+/* .index is the entry in the auxillary dpm_state_table[] */
+static struct cpufreq_frequency_table bfin_freq_table[] = {
+	{
+		.frequency = CPUFREQ_TABLE_END,
+		.index = 0,
+	},
+	{
+		.frequency = CPUFREQ_TABLE_END,
+		.index = 1,
+	},
+	{
+		.frequency = CPUFREQ_TABLE_END,
+		.index = 2,
+	},
+	{
+		.frequency = CPUFREQ_TABLE_END,
+		.index = 0,
+	},
+};
+
+static struct bfin_dpm_state {
+	unsigned int csel; /* system clock divider */
+	unsigned int tscale; /* change the divider on the core timer interrupt */
+} dpm_state_table[3];
+
+/**************************************************************************/
+
+static unsigned int bfin_getfreq(unsigned int cpu)
+{
+	/* The driver only support single cpu */
+	if (cpu != 0)
+		return -1;
+
+	return get_cclk();
+}
+
+
+static int bfin_target(struct cpufreq_policy *policy,
+			unsigned int target_freq, unsigned int relation)
+{
+	unsigned int index, plldiv, tscale;
+	unsigned long flags, cclk_hz;
+	struct cpufreq_freqs freqs;
+
+	if (cpufreq_frequency_table_target(policy, bfin_freq_table,
+		 target_freq, relation, &index))
+		return -EINVAL;
+
+	cclk_hz = bfin_freq_table[index].frequency;
+
+	freqs.old = bfin_getfreq(0);
+	freqs.new = cclk_hz;
+	freqs.cpu = 0;
+
+	pr_debug("cpufreq: changing cclk to %lu; target = %u, oldfreq = %u\n",
+		 cclk_hz, target_freq, freqs.old);
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+	local_irq_save(flags);
+		plldiv = (bfin_read_PLL_DIV() & SSEL) | dpm_state_table[index].csel;
+		tscale = dpm_state_table[index].tscale;
+		bfin_write_PLL_DIV(plldiv);
+		/* we have to adjust the core timer, because it is using cclk */
+		bfin_write_TSCALE(tscale);
+		SSYNC();
+	local_irq_restore(flags);
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+	return 0;
+}
+
+static int bfin_verify_speed(struct cpufreq_policy *policy)
+{
+	return cpufreq_frequency_table_verify(policy, bfin_freq_table);
+}
+
+static int __init __bfin_cpu_init(struct cpufreq_policy *policy)
+{
+
+	unsigned long cclk, sclk, csel, min_cclk;
+	int index;
+
+#ifdef CONFIG_CYCLES_CLOCKSOURCE
+/*
+ * Clocksource CYCLES is still CONTINUOUS but not longer MONOTONIC in case we enable
+ * CPU frequency scaling, since CYCLES runs off Core Clock.
+ */
+	printk(KERN_WARNING "CPU frequency scaling not supported: Clocksource not suitable\n"
+		return -ENODEV;
+#endif
+
+	if (policy->cpu != 0)
+		return -EINVAL;
+
+	cclk = get_cclk();
+	sclk = get_sclk();
+
+#if ANOMALY_05000273
+	min_cclk = sclk * 2;
+#else
+	min_cclk = sclk;
+#endif
+	csel = ((bfin_read_PLL_DIV() & CSEL) >> 4);
+
+	for (index = 0;  (cclk >> index) >= min_cclk && csel <= 3; index++, csel++) {
+		bfin_freq_table[index].frequency = cclk >> index;
+		dpm_state_table[index].csel = csel << 4; /* Shift now into PLL_DIV bitpos */
+		dpm_state_table[index].tscale =  (TIME_SCALE / (1 << csel)) - 1;
+
+		pr_debug("cpufreq: freq:%d csel:%d tscale:%d\n",
+						 bfin_freq_table[index].frequency,
+						 dpm_state_table[index].csel,
+						 dpm_state_table[index].tscale);
+	}
+
+	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
+	policy->cpuinfo.transition_latency = (bfin_read_PLL_LOCKCNT() / (sclk / 1000000)) * 1000;
+	/*Now ,only support one cpu */
+	policy->cur = cclk;
+	cpufreq_frequency_table_get_attr(bfin_freq_table, policy->cpu);
+	return cpufreq_frequency_table_cpuinfo(policy, bfin_freq_table);
+}
+
+static struct freq_attr *bfin_freq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
+static struct cpufreq_driver bfin_driver = {
+	.verify = bfin_verify_speed,
+	.target = bfin_target,
+	.get = bfin_getfreq,
+	.init = __bfin_cpu_init,
+	.name = "bfin cpufreq",
+	.owner = THIS_MODULE,
+	.attr = bfin_freq_attr,
+};
+
+static int __init bfin_cpu_init(void)
+{
+	return cpufreq_register_driver(&bfin_driver);
+}
+
+static void __exit bfin_cpu_exit(void)
+{
+	cpufreq_unregister_driver(&bfin_driver);
+}
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("cpufreq driver for Blackfin");
+MODULE_LICENSE("GPL");
+
+module_init(bfin_cpu_init);
+module_exit(bfin_cpu_exit);
diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S
index cee54ce..f2fb87e 100644
--- a/arch/blackfin/mach-common/entry.S
+++ b/arch/blackfin/mach-common/entry.S
@@ -38,6 +38,7 @@
 #include <linux/unistd.h>
 #include <asm/blackfin.h>
 #include <asm/errno.h>
+#include <asm/fixed_code.h>
 #include <asm/thread_info.h>  /* TIF_NEED_RESCHED */
 #include <asm/asm-offsets.h>
 #include <asm/trace.h>
@@ -52,15 +53,6 @@
 # define EX_SCRATCH_REG CYCLES
 #endif
 
-#if ANOMALY_05000281
-ENTRY(_safe_speculative_execution)
-	NOP;
-	NOP;
-	NOP;
-	jump _safe_speculative_execution;
-ENDPROC(_safe_speculative_execution)
-#endif
-
 #ifdef CONFIG_EXCPT_IRQ_SYSC_L1
 .section .l1.text
 #else
@@ -121,10 +113,14 @@
 	(R7:6,P5:4) = [sp++];
 	ASTAT = [sp++];
 	SAVE_ALL_SYS
-	DEBUG_HWTRACE_SAVE(p5, r7)
 #ifdef CONFIG_MPU
+	/* We must load R1 here, _before_ DEBUG_HWTRACE_SAVE, since that
+	 * will change the stack pointer.  */
 	R0 = SEQSTAT;
 	R1 = SP;
+#endif
+	DEBUG_HWTRACE_SAVE(p5, r7)
+#ifdef CONFIG_MPU
 	sp += -12;
 	call _cplb_hdr;
 	sp += 12;
@@ -191,6 +187,7 @@
 ENDPROC(_bfin_return_from_exception)
 
 ENTRY(_handle_bad_cplb)
+	DEBUG_HWTRACE_RESTORE(p5, r7)
 	/* To get here, we just tried and failed to change a CPLB
 	 * so, handle things in trap_c (C code), by lowering to
 	 * IRQ5, just like we normally do. Since this is not a
@@ -225,6 +222,26 @@
 	[p4] = p5;
 	csync;
 
+	p4.l = lo(DCPLB_FAULT_ADDR);
+	p4.h = hi(DCPLB_FAULT_ADDR);
+	r7 = [p4];
+	p5.h = _saved_dcplb_fault_addr;
+	p5.l = _saved_dcplb_fault_addr;
+	[p5] = r7;
+
+	r7 = [p4 + (ICPLB_FAULT_ADDR - DCPLB_FAULT_ADDR)];
+	p5.h = _saved_icplb_fault_addr;
+	p5.l = _saved_icplb_fault_addr;
+	[p5] = r7;
+
+	p4.l = __retx;
+	p4.h = __retx;
+	r6 = retx;
+	[p4] = r6;
+	p4.l = lo(SAFE_USER_INSTRUCTION);
+	p4.h = hi(SAFE_USER_INSTRUCTION);
+	retx = p4;
+
 	/* Disable all interrupts, but make sure level 5 is enabled so
 	 * we can switch to that level.  Save the old mask.  */
 	cli r6;
@@ -234,23 +251,6 @@
 	r6 = 0x3f;
 	sti r6;
 
-	/* Save the excause into a circular buffer, in case the instruction
-	 * which caused this excecptions causes others.
-	 */
-	P5.l = _in_ptr_excause;
-	P5.h = _in_ptr_excause;
-	R7 = [P5];
-	R7 += 4;
-	R6 = 0xF;
-	R7 = R7 & R6;
-	[P5] = R7;
-	R6.l = _excause_circ_buf;
-	R6.h = _excause_circ_buf;
-	R7 = R7 + R6;
-	p5 = R7;
-	R6 = SEQSTAT;
-	[P5] = R6;
-
 	(R7:6,P5:4) = [sp++];
 	ASTAT = [sp++];
 	SP = EX_SCRATCH_REG;
@@ -307,6 +307,11 @@
 ENTRY(_exception_to_level5)
 	SAVE_ALL_SYS
 
+	p4.l = __retx;
+	p4.h = __retx;
+	r6 = [p4];
+	[sp + PT_PC] = r6;
+
 	/* Restore interrupt mask.  We haven't pushed RETI, so this
 	 * doesn't enable interrupts until we return from this handler.  */
 	p4.l = _excpt_saved_imask;
@@ -328,42 +333,11 @@
 	r0 = [p2];              /* Read current IPEND */
 	[sp + PT_IPEND] = r0;   /* Store IPEND */
 
-	/* Pop the excause from the circular buffer and push it on the stack
-	 * (in the right place - if you change the location of SEQSTAT, you
-	 * must change this offset.
-	 */
-.L_excep_to_5_again:
-	P5.l = _out_ptr_excause;
-	P5.h = _out_ptr_excause;
-	R7 = [P5];
-	R7 += 4;
-	R6 = 0xF;
-	R7 = R7 & R6;
-	[P5] = R7;
-	R6.l = _excause_circ_buf;
-	R6.h = _excause_circ_buf;
-	R7 = R7 + R6;
-	P5 = R7;
-	R1 = [P5];
-	[SP + PT_SEQSTAT] = r1;
-
 	r0 = sp; 	/* stack frame pt_regs pointer argument ==> r0 */
 	SP += -12;
 	call _trap_c;
 	SP += 12;
 
-	/* See if anything else is in the exception buffer
-	 * if there is, process it
-	 */
-	P5.l = _out_ptr_excause;
-	P5.h = _out_ptr_excause;
-	P4.l = _in_ptr_excause;
-	P4.h = _in_ptr_excause;
-	R6 = [P5];
-	R7 = [P4];
-	CC = R6 == R7;
-	if ! CC JUMP .L_excep_to_5_again
-
 	call _ret_from_exception;
 	RESTORE_ALL_SYS
 	rti;
@@ -727,8 +701,8 @@
 	[p0] = p1;
 	csync;
 #if ANOMALY_05000281
-	r0.l = _safe_speculative_execution;
-	r0.h = _safe_speculative_execution;
+	r0.l = lo(SAFE_USER_INSTRUCTION);
+	r0.h = hi(SAFE_USER_INSTRUCTION);
 	reti = r0;
 #endif
 	r0 = 0x801f (z);
@@ -741,8 +715,8 @@
 
 ENTRY(_lower_to_irq14)
 #if ANOMALY_05000281
-	r0.l = _safe_speculative_execution;
-	r0.h = _safe_speculative_execution;
+	r0.l = lo(SAFE_USER_INSTRUCTION);
+	r0.h = hi(SAFE_USER_INSTRUCTION);
 	reti = r0;
 #endif
 	r0 = 0x401f;
@@ -809,20 +783,6 @@
 	rti;
 ENDPROC(_lower_to_irq14)
 
-/* Make sure when we start, that the circular buffer is initialized properly
- * R0 and P0 are call clobbered, so we can use them here.
- */
-ENTRY(_init_exception_buff)
-	r0 = 0;
-	p0.h = _in_ptr_excause;
-	p0.l = _in_ptr_excause;
-	[p0] = r0;
-	p0.h = _out_ptr_excause;
-	p0.l = _out_ptr_excause;
-	[p0] = r0;
-	rts;
-ENDPROC(_init_exception_buff)
-
 /* We handle this 100% in exception space - to reduce overhead
  * Only potiential problem is if the software buffer gets swapped out of the
  * CPLB table - then double fault. - so we don't let this happen in other places
@@ -1398,17 +1358,7 @@
 _last_cplb_fault_retx:
 	.long 0;
 #endif
-/*
- * Single instructions can have multiple faults, which need to be
- * handled by traps.c, in irq5. We store the exception cause to ensure
- * we don't miss a double fault condition
- */
-ENTRY(_in_ptr_excause)
+	/* Used to save the real RETX when temporarily storing a safe
+	 * return address.  */
+__retx:
 	.long 0;
-ENTRY(_out_ptr_excause)
-	.long 0;
-ALIGN
-ENTRY(_excause_circ_buf)
-	.rept 4
-	.long 0
-	.endr
diff --git a/arch/blackfin/mach-common/ints-priority.c b/arch/blackfin/mach-common/ints-priority.c
index 225ef14..f5fd768 100644
--- a/arch/blackfin/mach-common/ints-priority.c
+++ b/arch/blackfin/mach-common/ints-priority.c
@@ -316,7 +316,7 @@
 		printk(KERN_ERR
 		       "%s : %s : LINE %d :\nIRQ ?: PERIPHERAL ERROR"
 		       " INTERRUPT ASSERTED BUT NO SOURCE FOUND\n",
-		       __FUNCTION__, __FILE__, __LINE__);
+		       __func__, __FILE__, __LINE__);
 
 }
 #endif				/* BF537_GENERIC_ERROR_INT_DEMUX */
@@ -326,6 +326,7 @@
 static unsigned short gpio_enabled[gpio_bank(MAX_BLACKFIN_GPIOS)];
 static unsigned short gpio_edge_triggered[gpio_bank(MAX_BLACKFIN_GPIOS)];
 
+extern void bfin_gpio_irq_prepare(unsigned gpio);
 
 static void bfin_gpio_ack_irq(unsigned int irq)
 {
@@ -364,35 +365,25 @@
 
 static unsigned int bfin_gpio_irq_startup(unsigned int irq)
 {
-	unsigned int ret;
 	u16 gpionr = irq - IRQ_PF0;
-	char buf[8];
 
-	if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
-		snprintf(buf, sizeof buf, "IRQ %d", irq);
-		ret = gpio_request(gpionr, buf);
-		if (ret)
-			return ret;
-	}
+	if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr)))
+		bfin_gpio_irq_prepare(gpionr);
 
 	gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr);
 	bfin_gpio_unmask_irq(irq);
 
-	return ret;
+	return 0;
 }
 
 static void bfin_gpio_irq_shutdown(unsigned int irq)
 {
 	bfin_gpio_mask_irq(irq);
-	gpio_free(irq - IRQ_PF0);
 	gpio_enabled[gpio_bank(irq - IRQ_PF0)] &= ~gpio_bit(irq - IRQ_PF0);
 }
 
 static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
 {
-
-	unsigned int ret;
-	char buf[8];
 	u16 gpionr = irq - IRQ_PF0;
 
 	if (type == IRQ_TYPE_PROBE) {
@@ -404,12 +395,8 @@
 
 	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
 		    IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
-		if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
-			snprintf(buf, sizeof buf, "IRQ %d", irq);
-			ret = gpio_request(gpionr, buf);
-			if (ret)
-				return ret;
-		}
+		if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr)))
+			bfin_gpio_irq_prepare(gpionr);
 
 		gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr);
 	} else {
@@ -595,6 +582,8 @@
 	(struct pin_int_t *)PINT3_MASK_SET,
 };
 
+extern void bfin_gpio_irq_prepare(unsigned gpio);
+
 inline unsigned short get_irq_base(u8 bank, u8 bmap)
 {
 
@@ -697,8 +686,6 @@
 
 static unsigned int bfin_gpio_irq_startup(unsigned int irq)
 {
-	unsigned int ret;
-	char buf[8];
 	u16 gpionr = irq_to_gpio(irq);
 	u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
 
@@ -709,17 +696,13 @@
 		return -ENODEV;
 	}
 
-	if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
-		snprintf(buf, sizeof buf, "IRQ %d", irq);
-		ret = gpio_request(gpionr, buf);
-		if (ret)
-			return ret;
-	}
+	if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr)))
+		bfin_gpio_irq_prepare(gpionr);
 
 	gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr);
 	bfin_gpio_unmask_irq(irq);
 
-	return ret;
+	return 0;
 }
 
 static void bfin_gpio_irq_shutdown(unsigned int irq)
@@ -727,15 +710,12 @@
 	u16 gpionr = irq_to_gpio(irq);
 
 	bfin_gpio_mask_irq(irq);
-	gpio_free(gpionr);
 	gpio_enabled[gpio_bank(gpionr)] &= ~gpio_bit(gpionr);
 }
 
 static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
 {
 
-	unsigned int ret;
-	char buf[8];
 	u16 gpionr = irq_to_gpio(irq);
 	u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
 	u32 pintbit = PINT_BIT(pint_val);
@@ -753,12 +733,8 @@
 
 	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
 		    IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
-		if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
-			snprintf(buf, sizeof buf, "IRQ %d", irq);
-			ret = gpio_request(gpionr, buf);
-			if (ret)
-				return ret;
-		}
+		if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr)))
+			bfin_gpio_irq_prepare(gpionr);
 
 		gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr);
 	} else {
@@ -766,8 +742,6 @@
 		return 0;
 	}
 
-	gpio_direction_input(gpionr);
-
 	if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)))
 		pint[bank]->invert_set = pintbit;	/* low or falling edge denoted by one */
 	else
@@ -965,8 +939,6 @@
 
 	local_irq_disable();
 
-	init_exception_buff();
-
 #ifdef CONFIG_BF54x
 # ifdef CONFIG_PINTx_REASSIGN
 	pint[0]->assign = CONFIG_PINT0_ASSIGN;
diff --git a/arch/blackfin/mach-common/lock.S b/arch/blackfin/mach-common/lock.S
index 28b87fe..30b887e 100644
--- a/arch/blackfin/mach-common/lock.S
+++ b/arch/blackfin/mach-common/lock.S
@@ -174,7 +174,7 @@
 	CLI R3;
 
 	R7 = [P1];
-	R2 = 0xFFFFFF87 (X);
+	R2 = ~(0x78) (X);	/* mask out ILOC */
 	R7 = R7 & R2;
 	R0 = R0 << 3;
 	R7 = R0 | R7;
diff --git a/arch/blackfin/mm/blackfin_sram.c b/arch/blackfin/mm/blackfin_sram.c
index e41f0e8..3246f91 100644
--- a/arch/blackfin/mm/blackfin_sram.c
+++ b/arch/blackfin/mm/blackfin_sram.c
@@ -401,7 +401,7 @@
 
 void *l1_inst_sram_alloc(size_t size)
 {
-#if L1_DATA_A_LENGTH != 0
+#if L1_CODE_LENGTH != 0
 	unsigned flags;
 	void *addr;
 
diff --git a/arch/blackfin/oprofile/common.c b/arch/blackfin/oprofile/common.c
index cb8b8d5..0f6d303 100644
--- a/arch/blackfin/oprofile/common.c
+++ b/arch/blackfin/oprofile/common.c
@@ -75,7 +75,7 @@
 {
 	int ret = -EBUSY;
 
-	printk(KERN_INFO "KSDBG:in %s\n", __FUNCTION__);
+	printk(KERN_INFO "KSDBG:in %s\n", __func__);
 	mutex_lock(&pfmon_lock);
 	if (!pfmon_enabled) {
 		ret = model->start(ctr);
diff --git a/arch/blackfin/oprofile/op_model_bf533.c b/arch/blackfin/oprofile/op_model_bf533.c
index 872dffe..d1c698b 100644
--- a/arch/blackfin/oprofile/op_model_bf533.c
+++ b/arch/blackfin/oprofile/op_model_bf533.c
@@ -125,7 +125,7 @@
 	unsigned int pc, pfctl;
 	unsigned int count[2];
 
-	pr_debug("get interrupt in %s\n", __FUNCTION__);
+	pr_debug("get interrupt in %s\n", __func__);
 	if (oprofile_running == 0) {
 		pr_debug("error: entering interrupt when oprofile is stopped.\n\r");
 		return -1;
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
index 135644f..484c83d 100644
--- a/arch/sparc/kernel/entry.S
+++ b/arch/sparc/kernel/entry.S
@@ -1409,7 +1409,6 @@
 
 	st	%o0, [%sp + STACKFRAME_SZ + PT_I0]
 
-	.globl	ret_sys_call
 ret_sys_call:
 	ld	[%curptr + TI_FLAGS], %l6
 	cmp	%o0, -ERESTART_RESTARTBLOCK
diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c
index 1f730619..3e849e8 100644
--- a/arch/sparc/kernel/signal.c
+++ b/arch/sparc/kernel/signal.c
@@ -105,11 +105,6 @@
 	return -ERESTARTNOHAND;
 }
 
-asmlinkage int sys_sigpause(unsigned int set)
-{
-	return _sigpause_common(set);
-}
-
 asmlinkage int sys_sigsuspend(old_sigset_t set)
 {
 	return _sigpause_common(set);
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
index df3eacb..8acc5cc 100644
--- a/arch/sparc64/Kconfig
+++ b/arch/sparc64/Kconfig
@@ -250,6 +250,26 @@
 
 endmenu
 
+config NUMA
+	bool "NUMA support"
+
+config NODES_SHIFT
+	int
+	default "4"
+	depends on NEED_MULTIPLE_NODES
+
+# Some NUMA nodes have memory ranges that span
+# other nodes.  Even though a pfn is valid and
+# between a node's start and end pfns, it may not
+# reside on that node.  See memmap_init_zone()
+# for details.
+config NODES_SPAN_OTHER_NODES
+	def_bool y
+	depends on NEED_MULTIPLE_NODES
+
+config ARCH_POPULATES_NODE_MAP
+	def_bool y
+
 config ARCH_SELECT_MEMORY_MODEL
 	def_bool y
 
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index e183586..92f7968 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.25
-# Sun Apr 20 01:33:21 2008
+# Linux kernel version: 2.6.25-numa
+# Wed Apr 23 04:49:08 2008
 #
 CONFIG_SPARC=y
 CONFIG_SPARC64=y
@@ -152,6 +152,8 @@
 CONFIG_HUGETLB_PAGE_SIZE_4MB=y
 # CONFIG_HUGETLB_PAGE_SIZE_512K is not set
 # CONFIG_HUGETLB_PAGE_SIZE_64K is not set
+# CONFIG_NUMA is not set
+CONFIG_ARCH_POPULATES_NODE_MAP=y
 CONFIG_ARCH_SELECT_MEMORY_MODEL=y
 CONFIG_ARCH_SPARSEMEM_ENABLE=y
 CONFIG_ARCH_SPARSEMEM_DEFAULT=y
@@ -787,7 +789,6 @@
 # CONFIG_SENSORS_PCF8574 is not set
 # CONFIG_PCF8575 is not set
 # CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_TPS65010 is not set
 # CONFIG_SENSORS_MAX6875 is not set
 # CONFIG_SENSORS_TSL2550 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
@@ -869,6 +870,7 @@
 # Multifunction device drivers
 #
 # CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
 
 #
 # Multimedia devices
@@ -1219,10 +1221,6 @@
 # CONFIG_NEW_LEDS is not set
 # CONFIG_INFINIBAND is not set
 # CONFIG_RTC_CLASS is not set
-
-#
-# Userspace I/O
-#
 # CONFIG_UIO is not set
 
 #
@@ -1399,6 +1397,7 @@
 CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_INFO is not set
 # CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
 # CONFIG_DEBUG_LIST is not set
 # CONFIG_DEBUG_SG is not set
 # CONFIG_BOOT_PRINTK_DELAY is not set
@@ -1425,53 +1424,82 @@
 CONFIG_ASYNC_MEMCPY=m
 CONFIG_ASYNC_XOR=m
 CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
 CONFIG_CRYPTO_ALGAPI=y
 CONFIG_CRYPTO_AEAD=y
 CONFIG_CRYPTO_BLKCIPHER=y
-# CONFIG_CRYPTO_SEQIV is not set
 CONFIG_CRYPTO_HASH=y
 CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_GF128MUL=m
+CONFIG_CRYPTO_NULL=m
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_AUTHENC=y
+CONFIG_CRYPTO_TEST=m
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+
+#
+# Hash modes
+#
 CONFIG_CRYPTO_HMAC=y
 CONFIG_CRYPTO_XCBC=y
-CONFIG_CRYPTO_NULL=m
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=m
 CONFIG_CRYPTO_MD4=y
 CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_SHA1=y
 CONFIG_CRYPTO_SHA256=m
 CONFIG_CRYPTO_SHA512=m
-CONFIG_CRYPTO_WP512=m
 CONFIG_CRYPTO_TGR192=m
-CONFIG_CRYPTO_GF128MUL=m
-CONFIG_CRYPTO_ECB=m
-CONFIG_CRYPTO_CBC=y
-CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_XTS=m
-# CONFIG_CRYPTO_CTR is not set
-# CONFIG_CRYPTO_GCM is not set
-# CONFIG_CRYPTO_CCM is not set
-# CONFIG_CRYPTO_CRYPTD is not set
-CONFIG_CRYPTO_DES=y
-CONFIG_CRYPTO_FCRYPT=m
-CONFIG_CRYPTO_BLOWFISH=m
-CONFIG_CRYPTO_TWOFISH=m
-CONFIG_CRYPTO_TWOFISH_COMMON=m
-CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_WP512=m
+
+#
+# Ciphers
+#
 CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CAMELLIA=m
 CONFIG_CRYPTO_CAST5=m
 CONFIG_CRYPTO_CAST6=m
-CONFIG_CRYPTO_TEA=m
-CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_FCRYPT=m
 CONFIG_CRYPTO_KHAZAD=m
-CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_SEED=m
 # CONFIG_CRYPTO_SALSA20 is not set
+CONFIG_CRYPTO_SEED=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+
+#
+# Compression
+#
 CONFIG_CRYPTO_DEFLATE=y
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_CRC32C=m
-CONFIG_CRYPTO_CAMELLIA=m
-CONFIG_CRYPTO_TEST=m
-CONFIG_CRYPTO_AUTHENC=y
 # CONFIG_CRYPTO_LZO is not set
 CONFIG_CRYPTO_HW=y
 # CONFIG_CRYPTO_DEV_HIFN_795X is not set
@@ -1492,3 +1520,4 @@
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=y
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
index 04ab81c..bc26322 100644
--- a/arch/sparc64/kernel/ebus.c
+++ b/arch/sparc64/kernel/ebus.c
@@ -396,6 +396,7 @@
 	sd->op = &dev->ofdev;
 	sd->iommu = dev->bus->ofdev.dev.parent->archdata.iommu;
 	sd->stc = dev->bus->ofdev.dev.parent->archdata.stc;
+	sd->numa_node = dev->bus->ofdev.dev.parent->archdata.numa_node;
 
 	dev->ofdev.node = dp;
 	dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index fb43c76..fd06e93 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -47,7 +47,7 @@
 	ba,pt		%xcc, etrap
 109:	 or		%g7, %lo(109b), %g7
 	add		%g0, %g0, %g0
-	ba,a,pt		%xcc, rtrap_clr_l6
+	ba,a,pt		%xcc, rtrap
 
 1:	TRAP_LOAD_THREAD_REG(%g6, %g1)
 	ldub		[%g6 + TI_FPSAVED], %g5
@@ -226,7 +226,7 @@
 	call		do_fpother
 	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
-	 clr		%l6
+	 nop
 
 	.globl		do_fpother_check_fitos
 	.align		32
@@ -489,7 +489,7 @@
         call		bad_trap
 	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
-	 clr		%l6
+	 nop
 
 invoke_utrap:
 	sllx		%g3, 3, %g3
@@ -607,7 +607,7 @@
 	call		spitfire_access_error
 	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
-	 clr		%l6
+	 nop
 
 	/* This is the trap handler entry point for ECC correctable
 	 * errors.  They are corrected, but we listen for the trap
@@ -686,7 +686,7 @@
 	call		spitfire_data_access_exception_tl1
 	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
-	 clr		%l6
+	 nop
 
 __spitfire_data_access_exception:
 	rdpr		%pstate, %g4
@@ -705,7 +705,7 @@
 	call		spitfire_data_access_exception
 	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
-	 clr		%l6
+	 nop
 
 	.globl		__spitfire_insn_access_exception
 	.globl		__spitfire_insn_access_exception_tl1
@@ -725,7 +725,7 @@
 	call		spitfire_insn_access_exception_tl1
 	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
-	 clr		%l6
+	 nop
 
 __spitfire_insn_access_exception:
 	rdpr		%pstate, %g4
@@ -743,7 +743,7 @@
 	call		spitfire_insn_access_exception
 	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
-	 clr		%l6
+	 nop
 
 	/* These get patched into the trap table at boot time
 	 * once we know we have a cheetah processor.
@@ -937,7 +937,7 @@
 	call		cheetah_plus_parity_error
 	 add		%sp, PTREGS_OFF, %o1
 	ba,pt		%xcc, rtrap
-	 clr		%l6
+	 nop
 
 do_icpe_tl1:
 	rdpr		%tl, %g1		! Save original trap level
@@ -979,7 +979,7 @@
 	call		cheetah_plus_parity_error
 	 add		%sp, PTREGS_OFF, %o1
 	ba,pt		%xcc, rtrap
-	 clr		%l6
+	 nop
 	
 dcpe_icpe_tl1_common:
 	/* Flush D-cache, re-enable D/I caches in DCU and finally
@@ -1281,7 +1281,7 @@
 	call		do_privact
 	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
-	 clr		%l6
+	 nop
 
 	.globl		do_mna
 do_mna:
@@ -1308,7 +1308,7 @@
 	call		mem_address_unaligned
 	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
-	 clr		%l6
+	 nop
 
 	.globl		do_lddfmna
 do_lddfmna:
@@ -1326,7 +1326,7 @@
 	call		handle_lddfmna
 	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
-	 clr		%l6
+	 nop
 
 	.globl		do_stdfmna
 do_stdfmna:
@@ -1344,7 +1344,7 @@
 	call		handle_stdfmna
 	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
-	 clr		%l6
+	 nop
 
 	.globl	breakpoint_trap
 breakpoint_trap:
@@ -1424,13 +1424,13 @@
 1:		ldx		[%curptr + TI_FLAGS], %l5
 		andcc		%l5, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0
 		be,pt		%icc, rtrap
-		 clr		%l6
+		 nop
 		add		%sp, PTREGS_OFF, %o0
 		call		syscall_trace
 		 mov		1, %o1
 
 		ba,pt		%xcc, rtrap
-		 clr		%l6
+		 nop
 
 	/* This is how fork() was meant to be done, 8 instruction entry.
 	 *
@@ -1559,7 +1559,7 @@
 
 	/* Linux native system calls enter here... */
 	.align	32
-	.globl	linux_sparc_syscall, ret_sys_call
+	.globl	linux_sparc_syscall
 linux_sparc_syscall:
 	/* Direct access to user regs, much faster. */
 	cmp		%g1, NR_SYSCALLS			! IEU1	Group
@@ -1605,7 +1605,7 @@
 	bne,pn		%icc, linux_syscall_trace2
 	 add		%l1, 0x4, %l2			! npc = npc+4
 	stx		%l1, [%sp + PTREGS_OFF + PT_V9_TPC]
-	ba,pt		%xcc, rtrap_clr_l6
+	ba,pt		%xcc, rtrap
 	 stx		%l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
 
 1:
@@ -1616,7 +1616,6 @@
 	sub		%g0, %o0, %o0
 	or		%g3, %g2, %g3
 	stx		%o0, [%sp + PTREGS_OFF + PT_V9_I0]
-	mov		1, %l6
 	stx		%g3, [%sp + PTREGS_OFF + PT_V9_TSTATE]
 	bne,pn		%icc, linux_syscall_trace2
 	 add		%l1, 0x4, %l2			! npc = npc+4
diff --git a/arch/sparc64/kernel/entry.h b/arch/sparc64/kernel/entry.h
index 4a91e9c..32fbab6 100644
--- a/arch/sparc64/kernel/entry.h
+++ b/arch/sparc64/kernel/entry.h
@@ -20,7 +20,6 @@
 
 extern void do_notify_resume(struct pt_regs *regs,
 			     unsigned long orig_i0,
-			     int restart_syscall,
 			     unsigned long thread_info_flags);
 
 extern asmlinkage void syscall_trace(struct pt_regs *regs,
diff --git a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S
index 4b2bf9e..b49d3b6 100644
--- a/arch/sparc64/kernel/etrap.S
+++ b/arch/sparc64/kernel/etrap.S
@@ -53,7 +53,11 @@
 		stx	%g3, [%g2 + STACKFRAME_SZ + PT_V9_TPC]
 		rd	%y, %g3
 		stx	%g1, [%g2 + STACKFRAME_SZ + PT_V9_TNPC]
+		rdpr	%tt, %g1
 		st	%g3, [%g2 + STACKFRAME_SZ + PT_V9_Y]
+		sethi	%hi(PT_REGS_MAGIC), %g3
+		or	%g3, %g1, %g1
+		st	%g1, [%g2 + STACKFRAME_SZ + PT_V9_MAGIC]
 
 		rdpr	%cansave, %g1
 		brnz,pt %g1, etrap_save
diff --git a/arch/sparc64/kernel/iommu.c b/arch/sparc64/kernel/iommu.c
index 756fa24..2a37a6c 100644
--- a/arch/sparc64/kernel/iommu.c
+++ b/arch/sparc64/kernel/iommu.c
@@ -173,9 +173,11 @@
 }
 
 int iommu_table_init(struct iommu *iommu, int tsbsize,
-		     u32 dma_offset, u32 dma_addr_mask)
+		     u32 dma_offset, u32 dma_addr_mask,
+		     int numa_node)
 {
-	unsigned long i, tsbbase, order, sz, num_tsb_entries;
+	unsigned long i, order, sz, num_tsb_entries;
+	struct page *page;
 
 	num_tsb_entries = tsbsize / sizeof(iopte_t);
 
@@ -188,11 +190,12 @@
 	/* Allocate and initialize the free area map.  */
 	sz = num_tsb_entries / 8;
 	sz = (sz + 7UL) & ~7UL;
-	iommu->arena.map = kzalloc(sz, GFP_KERNEL);
+	iommu->arena.map = kmalloc_node(sz, GFP_KERNEL, numa_node);
 	if (!iommu->arena.map) {
 		printk(KERN_ERR "IOMMU: Error, kmalloc(arena.map) failed.\n");
 		return -ENOMEM;
 	}
+	memset(iommu->arena.map, 0, sz);
 	iommu->arena.limit = num_tsb_entries;
 
 	if (tlb_type != hypervisor)
@@ -201,21 +204,23 @@
 	/* Allocate and initialize the dummy page which we
 	 * set inactive IO PTEs to point to.
 	 */
-	iommu->dummy_page = get_zeroed_page(GFP_KERNEL);
-	if (!iommu->dummy_page) {
+	page = alloc_pages_node(numa_node, GFP_KERNEL, 0);
+	if (!page) {
 		printk(KERN_ERR "IOMMU: Error, gfp(dummy_page) failed.\n");
 		goto out_free_map;
 	}
+	iommu->dummy_page = (unsigned long) page_address(page);
+	memset((void *)iommu->dummy_page, 0, PAGE_SIZE);
 	iommu->dummy_page_pa = (unsigned long) __pa(iommu->dummy_page);
 
 	/* Now allocate and setup the IOMMU page table itself.  */
 	order = get_order(tsbsize);
-	tsbbase = __get_free_pages(GFP_KERNEL, order);
-	if (!tsbbase) {
+	page = alloc_pages_node(numa_node, GFP_KERNEL, order);
+	if (!page) {
 		printk(KERN_ERR "IOMMU: Error, gfp(tsb) failed.\n");
 		goto out_free_dummy_page;
 	}
-	iommu->page_table = (iopte_t *)tsbbase;
+	iommu->page_table = (iopte_t *)page_address(page);
 
 	for (i = 0; i < num_tsb_entries; i++)
 		iopte_make_dummy(iommu, &iommu->page_table[i]);
@@ -276,20 +281,24 @@
 static void *dma_4u_alloc_coherent(struct device *dev, size_t size,
 				   dma_addr_t *dma_addrp, gfp_t gfp)
 {
-	struct iommu *iommu;
-	iopte_t *iopte;
 	unsigned long flags, order, first_page;
+	struct iommu *iommu;
+	struct page *page;
+	int npages, nid;
+	iopte_t *iopte;
 	void *ret;
-	int npages;
 
 	size = IO_PAGE_ALIGN(size);
 	order = get_order(size);
 	if (order >= 10)
 		return NULL;
 
-	first_page = __get_free_pages(gfp, order);
-	if (first_page == 0UL)
+	nid = dev->archdata.numa_node;
+	page = alloc_pages_node(nid, gfp, order);
+	if (unlikely(!page))
 		return NULL;
+
+	first_page = (unsigned long) page_address(page);
 	memset((char *)first_page, 0, PAGE_SIZE << order);
 
 	iommu = dev->archdata.iommu;
diff --git a/arch/sparc64/kernel/isa.c b/arch/sparc64/kernel/isa.c
index b5f7b35..a2af5ed 100644
--- a/arch/sparc64/kernel/isa.c
+++ b/arch/sparc64/kernel/isa.c
@@ -92,6 +92,7 @@
 		sd->op = &isa_dev->ofdev;
 		sd->iommu = isa_br->ofdev.dev.parent->archdata.iommu;
 		sd->stc = isa_br->ofdev.dev.parent->archdata.stc;
+		sd->numa_node = isa_br->ofdev.dev.parent->archdata.numa_node;
 
 		isa_dev->ofdev.node = dp;
 		isa_dev->ofdev.dev.parent = &isa_br->ofdev.dev;
diff --git a/arch/sparc64/kernel/mdesc.c b/arch/sparc64/kernel/mdesc.c
index 9100835..dde52bc 100644
--- a/arch/sparc64/kernel/mdesc.c
+++ b/arch/sparc64/kernel/mdesc.c
@@ -1,10 +1,10 @@
 /* mdesc.c: Sun4V machine description handling.
  *
- * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
  */
 #include <linux/kernel.h>
 #include <linux/types.h>
-#include <linux/bootmem.h>
+#include <linux/lmb.h>
 #include <linux/log2.h>
 #include <linux/list.h>
 #include <linux/slab.h>
@@ -84,24 +84,28 @@
 	hp->handle_size = handle_size;
 }
 
-static struct mdesc_handle * __init mdesc_bootmem_alloc(unsigned int mdesc_size)
+static struct mdesc_handle * __init mdesc_lmb_alloc(unsigned int mdesc_size)
 {
-	struct mdesc_handle *hp;
 	unsigned int handle_size, alloc_size;
+	struct mdesc_handle *hp;
+	unsigned long paddr;
 
 	handle_size = (sizeof(struct mdesc_handle) -
 		       sizeof(struct mdesc_hdr) +
 		       mdesc_size);
 	alloc_size = PAGE_ALIGN(handle_size);
 
-	hp = __alloc_bootmem(alloc_size, PAGE_SIZE, 0UL);
-	if (hp)
-		mdesc_handle_init(hp, handle_size, hp);
+	paddr = lmb_alloc(alloc_size, PAGE_SIZE);
 
+	hp = NULL;
+	if (paddr) {
+		hp = __va(paddr);
+		mdesc_handle_init(hp, handle_size, hp);
+	}
 	return hp;
 }
 
-static void mdesc_bootmem_free(struct mdesc_handle *hp)
+static void mdesc_lmb_free(struct mdesc_handle *hp)
 {
 	unsigned int alloc_size, handle_size = hp->handle_size;
 	unsigned long start, end;
@@ -124,9 +128,9 @@
 	}
 }
 
-static struct mdesc_mem_ops bootmem_mdesc_ops = {
-	.alloc = mdesc_bootmem_alloc,
-	.free  = mdesc_bootmem_free,
+static struct mdesc_mem_ops lmb_mdesc_ops = {
+	.alloc = mdesc_lmb_alloc,
+	.free  = mdesc_lmb_free,
 };
 
 static struct mdesc_handle *mdesc_kmalloc(unsigned int mdesc_size)
@@ -888,7 +892,7 @@
 
 	printk("MDESC: Size is %lu bytes.\n", len);
 
-	hp = mdesc_alloc(len, &bootmem_mdesc_ops);
+	hp = mdesc_alloc(len, &lmb_mdesc_ops);
 	if (hp == NULL) {
 		prom_printf("MDESC: alloc of %lu bytes failed.\n", len);
 		prom_halt();
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c
index 0fd9db9..9e58e8c 100644
--- a/arch/sparc64/kernel/of_device.c
+++ b/arch/sparc64/kernel/of_device.c
@@ -6,6 +6,7 @@
 #include <linux/mod_devicetable.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
+#include <linux/irq.h>
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
 
@@ -660,6 +661,7 @@
 	struct device_node *dp = op->node;
 	struct device_node *pp, *ip;
 	unsigned int orig_irq = irq;
+	int nid;
 
 	if (irq == 0xffffffff)
 		return irq;
@@ -672,7 +674,7 @@
 			printk("%s: direct translate %x --> %x\n",
 			       dp->full_name, orig_irq, irq);
 
-		return irq;
+		goto out;
 	}
 
 	/* Something more complicated.  Walk up to the root, applying
@@ -744,6 +746,14 @@
 		printk("%s: Apply IRQ trans [%s] %x --> %x\n",
 		       op->node->full_name, ip->full_name, orig_irq, irq);
 
+out:
+	nid = of_node_to_nid(dp);
+	if (nid != -1) {
+		cpumask_t numa_mask = node_to_cpumask(nid);
+
+		irq_set_affinity(irq, numa_mask);
+	}
+
 	return irq;
 }
 
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
index 545356b..49f9127 100644
--- a/arch/sparc64/kernel/pci.c
+++ b/arch/sparc64/kernel/pci.c
@@ -369,10 +369,12 @@
 	sd->host_controller = pbm;
 	sd->prom_node = node;
 	sd->op = of_find_device_by_node(node);
+	sd->numa_node = pbm->numa_node;
 
 	sd = &sd->op->dev.archdata;
 	sd->iommu = pbm->iommu;
 	sd->stc = &pbm->stc;
+	sd->numa_node = pbm->numa_node;
 
 	type = of_get_property(node, "device_type", NULL);
 	if (type == NULL)
@@ -1159,6 +1161,16 @@
 	return 0;
 }
 
+#ifdef CONFIG_NUMA
+int pcibus_to_node(struct pci_bus *pbus)
+{
+	struct pci_pbm_info *pbm = pbus->sysdata;
+
+	return pbm->numa_node;
+}
+EXPORT_SYMBOL(pcibus_to_node);
+#endif
+
 /* Return the domain nuber for this pci bus */
 
 int pci_domain_nr(struct pci_bus *pbus)
diff --git a/arch/sparc64/kernel/pci_fire.c b/arch/sparc64/kernel/pci_fire.c
index 7571ed5..d23bb6f 100644
--- a/arch/sparc64/kernel/pci_fire.c
+++ b/arch/sparc64/kernel/pci_fire.c
@@ -71,7 +71,8 @@
 	 */
 	fire_write(iommu->iommu_flushinv, ~(u64)0);
 
-	err = iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask);
+	err = iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask,
+			       pbm->numa_node);
 	if (err)
 		return err;
 
@@ -449,6 +450,8 @@
 	pbm->next = pci_pbm_root;
 	pci_pbm_root = pbm;
 
+	pbm->numa_node = -1;
+
 	pbm->scan_bus = pci_fire_scan_bus;
 	pbm->pci_ops = &sun4u_pci_ops;
 	pbm->config_space_reg_bits = 12;
diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h
index 4a50da1..218bac4 100644
--- a/arch/sparc64/kernel/pci_impl.h
+++ b/arch/sparc64/kernel/pci_impl.h
@@ -148,6 +148,8 @@
 	struct pci_bus			*pci_bus;
 	void (*scan_bus)(struct pci_pbm_info *);
 	struct pci_ops			*pci_ops;
+
+	int				numa_node;
 };
 
 struct pci_controller_info {
@@ -161,8 +163,6 @@
 extern int pci_num_pbms;
 
 /* PCI bus scanning and fixup support. */
-extern void pci_iommu_table_init(struct iommu *iommu, int tsbsize,
-				 u32 dma_offset, u32 dma_addr_mask);
 extern void pci_get_pbm_props(struct pci_pbm_info *pbm);
 extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm);
 extern void pci_determine_mem_io_space(struct pci_pbm_info *pbm);
diff --git a/arch/sparc64/kernel/pci_msi.c b/arch/sparc64/kernel/pci_msi.c
index d6d64b4..db5e8fd 100644
--- a/arch/sparc64/kernel/pci_msi.c
+++ b/arch/sparc64/kernel/pci_msi.c
@@ -279,11 +279,17 @@
 				 unsigned long devino)
 {
 	int irq = ops->msiq_build_irq(pbm, msiqid, devino);
-	int err;
+	int err, nid;
 
 	if (irq < 0)
 		return irq;
 
+	nid = pbm->numa_node;
+	if (nid != -1) {
+		cpumask_t numa_mask = node_to_cpumask(nid);
+
+		irq_set_affinity(irq, numa_mask);
+	}
 	err = request_irq(irq, sparc64_msiq_interrupt, 0,
 			  "MSIQ",
 			  &pbm->msiq_irq_cookies[msiqid - pbm->msiq_first]);
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c
index 0bad96e..994dbe0 100644
--- a/arch/sparc64/kernel/pci_psycho.c
+++ b/arch/sparc64/kernel/pci_psycho.c
@@ -848,7 +848,8 @@
 	/* Leave diag mode enabled for full-flushing done
 	 * in pci_iommu.c
 	 */
-	err = iommu_table_init(iommu, IO_TSB_SIZE, 0xc0000000, 0xffffffff);
+	err = iommu_table_init(iommu, IO_TSB_SIZE, 0xc0000000, 0xffffffff,
+			       pbm->numa_node);
 	if (err)
 		return err;
 
@@ -979,6 +980,8 @@
 	pbm->next = pci_pbm_root;
 	pci_pbm_root = pbm;
 
+	pbm->numa_node = -1;
+
 	pbm->scan_bus = psycho_scan_bus;
 	pbm->pci_ops = &sun4u_pci_ops;
 	pbm->config_space_reg_bits = 8;
diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c
index 1c5f5fa..4c34195 100644
--- a/arch/sparc64/kernel/pci_sabre.c
+++ b/arch/sparc64/kernel/pci_sabre.c
@@ -704,7 +704,7 @@
 	 * in pci_iommu.c
 	 */
 	err = iommu_table_init(iommu, tsbsize * 1024 * 8,
-			       dvma_offset, dma_mask);
+			       dvma_offset, dma_mask, pbm->numa_node);
 	if (err)
 		return err;
 
@@ -737,6 +737,8 @@
 	pbm->name = dp->full_name;
 	printk("%s: SABRE PCI Bus Module\n", pbm->name);
 
+	pbm->numa_node = -1;
+
 	pbm->scan_bus = sabre_scan_bus;
 	pbm->pci_ops = &sun4u_pci_ops;
 	pbm->config_space_reg_bits = 8;
diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c
index e306093..615edd9 100644
--- a/arch/sparc64/kernel/pci_schizo.c
+++ b/arch/sparc64/kernel/pci_schizo.c
@@ -1220,7 +1220,8 @@
 	/* Leave diag mode enabled for full-flushing done
 	 * in pci_iommu.c
 	 */
-	err = iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask);
+	err = iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask,
+			       pbm->numa_node);
 	if (err)
 		return err;
 
@@ -1379,6 +1380,8 @@
 	pbm->next = pci_pbm_root;
 	pci_pbm_root = pbm;
 
+	pbm->numa_node = -1;
+
 	pbm->scan_bus = schizo_scan_bus;
 	pbm->pci_ops = &sun4u_pci_ops;
 	pbm->config_space_reg_bits = 8;
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c
index 0183970..e2bb979 100644
--- a/arch/sparc64/kernel/pci_sun4v.c
+++ b/arch/sparc64/kernel/pci_sun4v.c
@@ -127,10 +127,12 @@
 static void *dma_4v_alloc_coherent(struct device *dev, size_t size,
 				   dma_addr_t *dma_addrp, gfp_t gfp)
 {
-	struct iommu *iommu;
 	unsigned long flags, order, first_page, npages, n;
+	struct iommu *iommu;
+	struct page *page;
 	void *ret;
 	long entry;
+	int nid;
 
 	size = IO_PAGE_ALIGN(size);
 	order = get_order(size);
@@ -139,10 +141,12 @@
 
 	npages = size >> IO_PAGE_SHIFT;
 
-	first_page = __get_free_pages(gfp, order);
-	if (unlikely(first_page == 0UL))
+	nid = dev->archdata.numa_node;
+	page = alloc_pages_node(nid, gfp, order);
+	if (unlikely(!page))
 		return NULL;
 
+	first_page = (unsigned long) page_address(page);
 	memset((char *)first_page, 0, PAGE_SIZE << order);
 
 	iommu = dev->archdata.iommu;
@@ -899,6 +903,8 @@
 	pbm->next = pci_pbm_root;
 	pci_pbm_root = pbm;
 
+	pbm->numa_node = of_node_to_nid(dp);
+
 	pbm->scan_bus = pci_sun4v_scan_bus;
 	pbm->pci_ops = &sun4v_pci_ops;
 	pbm->config_space_reg_bits = 12;
@@ -913,6 +919,7 @@
 	pbm->name = dp->full_name;
 
 	printk("%s: SUN4V PCI Bus Module\n", pbm->name);
+	printk("%s: On NUMA node %d\n", pbm->name, pbm->numa_node);
 
 	pci_determine_mem_io_space(pbm);
 
diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c
index 68964dd..ed03a18 100644
--- a/arch/sparc64/kernel/prom.c
+++ b/arch/sparc64/kernel/prom.c
@@ -19,8 +19,8 @@
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/mm.h>
-#include <linux/bootmem.h>
 #include <linux/module.h>
+#include <linux/lmb.h>
 
 #include <asm/prom.h>
 #include <asm/of_device.h>
@@ -122,16 +122,20 @@
 }
 EXPORT_SYMBOL(of_find_in_proplist);
 
-static unsigned int prom_early_allocated;
+static unsigned int prom_early_allocated __initdata;
 
 static void * __init prom_early_alloc(unsigned long size)
 {
+	unsigned long paddr = lmb_alloc(size, SMP_CACHE_BYTES);
 	void *ret;
 
-	ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL);
-	if (ret != NULL)
-		memset(ret, 0, size);
+	if (!paddr) {
+		prom_printf("prom_early_alloc(%lu) failed\n");
+		prom_halt();
+	}
 
+	ret = __va(paddr);
+	memset(ret, 0, size);
 	prom_early_allocated += size;
 
 	return ret;
diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S
index 079d18a..ecf6753 100644
--- a/arch/sparc64/kernel/rtrap.S
+++ b/arch/sparc64/kernel/rtrap.S
@@ -18,12 +18,6 @@
 #define		RTRAP_PSTATE_IRQOFF	(PSTATE_RMO|PSTATE_PEF|PSTATE_PRIV)
 #define		RTRAP_PSTATE_AG_IRQOFF	(PSTATE_RMO|PSTATE_PEF|PSTATE_PRIV|PSTATE_AG)
 
-		/* Register %l6 keeps track of whether we are returning
-		 * from a system call or not.  It is cleared if we call
-		 * do_notify_resume, and it must not be otherwise modified
-		 * until we fully commit to returning to userspace.
-		 */
-
 		.text
 		.align			32
 __handle_softirq:
@@ -56,14 +50,12 @@
 		be,pt			%xcc, __handle_user_windows_continue
 		 nop
 		mov			%l5, %o1
-		mov			%l6, %o2
 		add			%sp, PTREGS_OFF, %o0
-		mov			%l0, %o3
+		mov			%l0, %o2
 
 		call			do_notify_resume
 		 wrpr			%g0, RTRAP_PSTATE, %pstate
 		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
-		clr			%l6
 		/* Signal delivery can modify pt_regs tstate, so we must
 		 * reload it.
 		 */
@@ -99,14 +91,12 @@
 		be,pt			%xcc, __handle_perfctrs_continue
 		 sethi			%hi(TSTATE_PEF), %o0
 		mov			%l5, %o1
-		mov			%l6, %o2
 		add			%sp, PTREGS_OFF, %o0
-		mov			%l0, %o3
+		mov			%l0, %o2
 		call			do_notify_resume
 
 		 wrpr			%g0, RTRAP_PSTATE, %pstate
 		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
-		clr			%l6
 		/* Signal delivery can modify pt_regs tstate, so we must
 		 * reload it.
 		 */
@@ -127,13 +117,11 @@
 
 __handle_signal:
 		mov			%l5, %o1
-		mov			%l6, %o2
 		add			%sp, PTREGS_OFF, %o0
-		mov			%l0, %o3
+		mov			%l0, %o2
 		call			do_notify_resume
 		 wrpr			%g0, RTRAP_PSTATE, %pstate
 		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
-		clr			%l6
 
 		/* Signal delivery can modify pt_regs tstate, so we must
 		 * reload it.
@@ -145,9 +133,8 @@
 		 andn			%l1, %l4, %l1
 
 		.align			64
-		.globl			rtrap_irq, rtrap_clr_l6, rtrap, irqsz_patchme, rtrap_xcall
+		.globl			rtrap_irq, rtrap, irqsz_patchme, rtrap_xcall
 rtrap_irq:
-rtrap_clr_l6:	clr			%l6
 rtrap:
 #ifndef CONFIG_SMP
 		sethi			%hi(per_cpu____cpu_data), %l0
diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c
index d1fb13b..fa2827c 100644
--- a/arch/sparc64/kernel/sbus.c
+++ b/arch/sparc64/kernel/sbus.c
@@ -544,6 +544,7 @@
 
 	sbus->ofdev.dev.archdata.iommu = iommu;
 	sbus->ofdev.dev.archdata.stc = strbuf;
+	sbus->ofdev.dev.archdata.numa_node = -1;
 
 	reg_base = regs + SYSIO_IOMMUREG_BASE;
 	iommu->iommu_control = reg_base + IOMMU_CONTROL;
@@ -575,7 +576,7 @@
 	       sbus->portid, regs);
 
 	/* Setup for TSB_SIZE=7, TBW_SIZE=0, MMU_DE=1, MMU_EN=1 */
-	if (iommu_table_init(iommu, IO_TSB_SIZE, MAP_BASE, 0xffffffff))
+	if (iommu_table_init(iommu, IO_TSB_SIZE, MAP_BASE, 0xffffffff, -1))
 		goto fatal_memory_error;
 
 	control = upa_readq(iommu->iommu_control);
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index 6acb4c5..da5e6ee 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -82,7 +82,7 @@
 static struct console prom_early_console = {
 	.name =		"earlyprom",
 	.write =	prom_console_write,
-	.flags =	CON_PRINTBUFFER | CON_BOOT,
+	.flags =	CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME,
 	.index =	-1,
 };
 
@@ -281,6 +281,7 @@
 	/* Initialize PROM console and command line. */
 	*cmdline_p = prom_getbootargs();
 	strcpy(boot_command_line, *cmdline_p);
+	parse_early_param();
 
 	boot_flags_init(*cmdline_p);
 	register_console(&prom_early_console);
diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
index 1c47009..77a3e85 100644
--- a/arch/sparc64/kernel/signal.c
+++ b/arch/sparc64/kernel/signal.c
@@ -510,15 +510,20 @@
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  * mistake.
  */
-static void do_signal(struct pt_regs *regs, unsigned long orig_i0, int restart_syscall)
+static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
 {
-	siginfo_t info;
 	struct signal_deliver_cookie cookie;
 	struct k_sigaction ka;
-	int signr;
 	sigset_t *oldset;
+	siginfo_t info;
+	int signr, tt;
 	
-	cookie.restart_syscall = restart_syscall;
+	tt = regs->magic & 0x1ff;
+	if (tt == 0x110 || tt == 0x111 || tt == 0x16d) {
+		regs->magic &= ~0x1ff;
+		cookie.restart_syscall = 1;
+	} else
+		cookie.restart_syscall = 0;
 	cookie.orig_i0 = orig_i0;
 
 	if (test_thread_flag(TIF_RESTORE_SIGMASK))
@@ -529,9 +534,8 @@
 #ifdef CONFIG_SPARC32_COMPAT
 	if (test_thread_flag(TIF_32BIT)) {
 		extern void do_signal32(sigset_t *, struct pt_regs *,
-					unsigned long, int);
-		do_signal32(oldset, regs, orig_i0,
-			    cookie.restart_syscall);
+					struct signal_deliver_cookie *);
+		do_signal32(oldset, regs, &cookie);
 		return;
 	}
 #endif	
@@ -539,7 +543,7 @@
 	signr = get_signal_to_deliver(&info, &ka, regs, &cookie);
 	if (signr > 0) {
 		if (cookie.restart_syscall)
-			syscall_restart(orig_i0, regs, &ka.sa);
+			syscall_restart(cookie.orig_i0, regs, &ka.sa);
 		handle_signal(signr, &ka, &info, oldset, regs);
 
 		/* a signal was successfully delivered; the saved
@@ -576,11 +580,10 @@
 	}
 }
 
-void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, int restart_syscall,
-		      unsigned long thread_info_flags)
+void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, unsigned long thread_info_flags)
 {
 	if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
-		do_signal(regs, orig_i0, restart_syscall);
+		do_signal(regs, orig_i0);
 }
 
 void ptrace_signal_deliver(struct pt_regs *regs, void *cookie)
diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
index 74e0512..43cdec6 100644
--- a/arch/sparc64/kernel/signal32.c
+++ b/arch/sparc64/kernel/signal32.c
@@ -982,20 +982,16 @@
  * mistake.
  */
 void do_signal32(sigset_t *oldset, struct pt_regs * regs,
-		 unsigned long orig_i0, int restart_syscall)
+		 struct signal_deliver_cookie *cookie)
 {
-	siginfo_t info;
-	struct signal_deliver_cookie cookie;
 	struct k_sigaction ka;
+	siginfo_t info;
 	int signr;
 	
-	cookie.restart_syscall = restart_syscall;
-	cookie.orig_i0 = orig_i0;
-
-	signr = get_signal_to_deliver(&info, &ka, regs, &cookie);
+	signr = get_signal_to_deliver(&info, &ka, regs, cookie);
 	if (signr > 0) {
-		if (cookie.restart_syscall)
-			syscall_restart32(orig_i0, regs, &ka.sa);
+		if (cookie->restart_syscall)
+			syscall_restart32(cookie->orig_i0, regs, &ka.sa);
 		handle_signal32(signr, &ka, &info, oldset, regs);
 
 		/* a signal was successfully delivered; the saved
@@ -1007,16 +1003,16 @@
 			clear_thread_flag(TIF_RESTORE_SIGMASK);
 		return;
 	}
-	if (cookie.restart_syscall &&
+	if (cookie->restart_syscall &&
 	    (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
 	     regs->u_regs[UREG_I0] == ERESTARTSYS ||
 	     regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
 		/* replay the system call when we are done */
-		regs->u_regs[UREG_I0] = cookie.orig_i0;
+		regs->u_regs[UREG_I0] = cookie->orig_i0;
 		regs->tpc -= 4;
 		regs->tnpc -= 4;
 	}
-	if (cookie.restart_syscall &&
+	if (cookie->restart_syscall &&
 	    regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) {
 		regs->u_regs[UREG_G1] = __NR_restart_syscall;
 		regs->tpc -= 4;
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index 59f020d..524b889 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -20,7 +20,7 @@
 #include <linux/cache.h>
 #include <linux/jiffies.h>
 #include <linux/profile.h>
-#include <linux/bootmem.h>
+#include <linux/lmb.h>
 
 #include <asm/head.h>
 #include <asm/ptrace.h>
@@ -1431,7 +1431,7 @@
 
 void __init real_setup_per_cpu_areas(void)
 {
-	unsigned long goal, size, i;
+	unsigned long paddr, goal, size, i;
 	char *ptr;
 
 	/* Copy section for each CPU (we discard the original) */
@@ -1441,8 +1441,13 @@
 	for (size = PAGE_SIZE; size < goal; size <<= 1UL)
 		__per_cpu_shift++;
 
-	ptr = alloc_bootmem_pages(size * NR_CPUS);
+	paddr = lmb_alloc(size * NR_CPUS, PAGE_SIZE);
+	if (!paddr) {
+		prom_printf("Cannot allocate per-cpu memory.\n");
+		prom_halt();
+	}
 
+	ptr = __va(paddr);
 	__per_cpu_base = ptr - __per_cpu_start;
 
 	for (i = 0; i < NR_CPUS; i++, ptr += size)
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index 3873646..6633659 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -68,8 +68,6 @@
 extern void *__memscan_generic(void *, int, size_t);
 extern int __memcmp(const void *, const void *, __kernel_size_t);
 extern __kernel_size_t strlen(const char *);
-extern void linux_sparc_syscall(void);
-extern void rtrap(void);
 extern void show_regs(struct pt_regs *);
 extern void syscall_trace(struct pt_regs *, int);
 extern void sys_sigsuspend(void);
diff --git a/arch/sparc64/kernel/stacktrace.c b/arch/sparc64/kernel/stacktrace.c
index 84d39e8..01b52f5 100644
--- a/arch/sparc64/kernel/stacktrace.c
+++ b/arch/sparc64/kernel/stacktrace.c
@@ -20,6 +20,8 @@
 	thread_base = (unsigned long) tp;
 	do {
 		struct reg_window *rw;
+		struct pt_regs *regs;
+		unsigned long pc;
 
 		/* Bogus frame pointer? */
 		if (fp < (thread_base + sizeof(struct thread_info)) ||
@@ -27,11 +29,19 @@
 			break;
 
 		rw = (struct reg_window *) fp;
+		regs = (struct pt_regs *) (rw + 1);
+
+		if ((regs->magic & ~0x1ff) == PT_REGS_MAGIC) {
+			pc = regs->tpc;
+			fp = regs->u_regs[UREG_I6] + STACK_BIAS;
+		} else {
+			pc = rw->ins[7];
+			fp = rw->ins[6] + STACK_BIAS;
+		}
+
 		if (trace->skip > 0)
 			trace->skip--;
 		else
-			trace->entries[trace->nr_entries++] = rw->ins[7];
-
-		fp = rw->ins[6] + STACK_BIAS;
+			trace->entries[trace->nr_entries++] = pc;
 	} while (trace->nr_entries < trace->max_entries);
 }
diff --git a/arch/sparc64/kernel/sun4v_tlb_miss.S b/arch/sparc64/kernel/sun4v_tlb_miss.S
index fd9430562..e1fbf8c 100644
--- a/arch/sparc64/kernel/sun4v_tlb_miss.S
+++ b/arch/sparc64/kernel/sun4v_tlb_miss.S
@@ -262,7 +262,7 @@
 	mov	%l5, %o2
 	call	sun4v_insn_access_exception
 	 add	%sp, PTREGS_OFF, %o0
-	ba,a,pt	%xcc, rtrap_clr_l6
+	ba,a,pt	%xcc, rtrap
 
 	/* Instruction Access Exception, tl1. */
 sun4v_iacc_tl1:
@@ -278,7 +278,7 @@
 	mov	%l5, %o2
 	call	sun4v_insn_access_exception_tl1
 	 add	%sp, PTREGS_OFF, %o0
-	ba,a,pt	%xcc, rtrap_clr_l6
+	ba,a,pt	%xcc, rtrap
 
 	/* Data Access Exception, tl0. */
 sun4v_dacc:
@@ -294,7 +294,7 @@
 	mov	%l5, %o2
 	call	sun4v_data_access_exception
 	 add	%sp, PTREGS_OFF, %o0
-	ba,a,pt	%xcc, rtrap_clr_l6
+	ba,a,pt	%xcc, rtrap
 
 	/* Data Access Exception, tl1. */
 sun4v_dacc_tl1:
@@ -310,7 +310,7 @@
 	mov	%l5, %o2
 	call	sun4v_data_access_exception_tl1
 	 add	%sp, PTREGS_OFF, %o0
-	ba,a,pt	%xcc, rtrap_clr_l6
+	ba,a,pt	%xcc, rtrap
 
 	/* Memory Address Unaligned.  */
 sun4v_mna:
@@ -344,7 +344,7 @@
 	mov	%l5, %o2
 	call	sun4v_do_mna
 	 add	%sp, PTREGS_OFF, %o0
-	ba,a,pt	%xcc, rtrap_clr_l6
+	ba,a,pt	%xcc, rtrap
 
 	/* Privileged Action.  */
 sun4v_privact:
@@ -352,7 +352,7 @@
 	 rd	%pc, %g7
 	call	do_privact
 	 add	%sp, PTREGS_OFF, %o0
-	ba,a,pt	%xcc, rtrap_clr_l6
+	ba,a,pt	%xcc, rtrap
 
 	/* Unaligned ldd float, tl0. */
 sun4v_lddfmna:
@@ -368,7 +368,7 @@
 	mov	%l5, %o2
 	call	handle_lddfmna
 	 add	%sp, PTREGS_OFF, %o0
-	ba,a,pt	%xcc, rtrap_clr_l6
+	ba,a,pt	%xcc, rtrap
 
 	/* Unaligned std float, tl0. */
 sun4v_stdfmna:
@@ -384,7 +384,7 @@
 	mov	%l5, %o2
 	call	handle_stdfmna
 	 add	%sp, PTREGS_OFF, %o0
-	ba,a,pt	%xcc, rtrap_clr_l6
+	ba,a,pt	%xcc, rtrap
 
 #define BRANCH_ALWAYS	0x10680000
 #define NOP		0x01000000
diff --git a/arch/sparc64/kernel/sysfs.c b/arch/sparc64/kernel/sysfs.c
index 52816c7..e885034 100644
--- a/arch/sparc64/kernel/sysfs.c
+++ b/arch/sparc64/kernel/sysfs.c
@@ -273,10 +273,22 @@
 		mmu_stats_supported = 1;
 }
 
+static void register_nodes(void)
+{
+#ifdef CONFIG_NUMA
+	int i;
+
+	for (i = 0; i < MAX_NUMNODES; i++)
+		register_one_node(i);
+#endif
+}
+
 static int __init topology_init(void)
 {
 	int cpu;
 
+	register_nodes();
+
 	check_mmu_stats();
 
 	register_cpu_notifier(&sysfs_cpu_nb);
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index 96da847..d9b8d46 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -2091,9 +2091,8 @@
 
 void show_stack(struct task_struct *tsk, unsigned long *_ksp)
 {
-	unsigned long pc, fp, thread_base, ksp;
+	unsigned long fp, thread_base, ksp;
 	struct thread_info *tp;
-	struct reg_window *rw;
 	int count = 0;
 
 	ksp = (unsigned long) _ksp;
@@ -2117,15 +2116,27 @@
 	printk("\n");
 #endif
 	do {
+		struct reg_window *rw;
+		struct pt_regs *regs;
+		unsigned long pc;
+
 		/* Bogus frame pointer? */
 		if (fp < (thread_base + sizeof(struct thread_info)) ||
 		    fp >= (thread_base + THREAD_SIZE))
 			break;
 		rw = (struct reg_window *)fp;
-		pc = rw->ins[7];
+		regs = (struct pt_regs *) (rw + 1);
+
+		if ((regs->magic & ~0x1ff) == PT_REGS_MAGIC) {
+			pc = regs->tpc;
+			fp = regs->u_regs[UREG_I6] + STACK_BIAS;
+		} else {
+			pc = rw->ins[7];
+			fp = rw->ins[6] + STACK_BIAS;
+		}
+
 		printk(" [%016lx] ", pc);
 		print_symbol("%s\n", pc);
-		fp = rw->ins[6] + STACK_BIAS;
 	} while (++count < 16);
 #ifndef CONFIG_KALLSYMS
 	printk("\n");
diff --git a/arch/sparc64/kernel/tsb.S b/arch/sparc64/kernel/tsb.S
index 10adb2f..c499214 100644
--- a/arch/sparc64/kernel/tsb.S
+++ b/arch/sparc64/kernel/tsb.S
@@ -275,7 +275,7 @@
 	stx	%l5, [%g6 + TI_FAULT_ADDR]	! Save fault address
 	call	do_sparc64_fault		! Call fault handler
 	 add	%sp, PTREGS_OFF, %o0		! Compute pt_regs arg
-	ba,pt	%xcc, rtrap_clr_l6		! Restore cpu state
+	ba,pt	%xcc, rtrap			! Restore cpu state
 	 nop					! Delay slot (fill me)
 
 winfix_trampoline:
diff --git a/arch/sparc64/kernel/winfixup.S b/arch/sparc64/kernel/winfixup.S
index c4aa110..a6b0863 100644
--- a/arch/sparc64/kernel/winfixup.S
+++ b/arch/sparc64/kernel/winfixup.S
@@ -32,7 +32,7 @@
 	 rd	%pc, %g7
 	call	do_sparc64_fault
 	 add	%sp, PTREGS_OFF, %o0
-	ba,pt	%xcc, rtrap_clr_l6
+	ba,pt	%xcc, rtrap
 	 nop
 
 	/* Be very careful about usage of the trap globals here.
@@ -100,7 +100,7 @@
 	 rd	%pc, %g7
 	call	do_sparc64_fault
 	 add	%sp, PTREGS_OFF, %o0
-	ba,a,pt	%xcc, rtrap_clr_l6
+	ba,a,pt	%xcc, rtrap
 
 winfix_mna:
 	andn	%g3, 0x7f, %g3
@@ -122,12 +122,12 @@
 	mov	%l4, %o2
 	call	sun4v_do_mna
 	 mov	%l5, %o1
-	ba,a,pt	%xcc, rtrap_clr_l6
+	ba,a,pt	%xcc, rtrap
 1:	mov	%l4, %o1
 	mov	%l5, %o2
 	call	mem_address_unaligned
 	 nop
-	ba,a,pt	%xcc, rtrap_clr_l6
+	ba,a,pt	%xcc, rtrap
 
 winfix_dax:
 	andn	%g3, 0x7f, %g3
@@ -150,7 +150,7 @@
 	 add	%sp, PTREGS_OFF, %o0
 	call	sun4v_data_access_exception
 	 nop
-	ba,a,pt	%xcc, rtrap_clr_l6
+	ba,a,pt	%xcc, rtrap
 1:	call	spitfire_data_access_exception
 	 nop
-	ba,a,pt	%xcc, rtrap_clr_l6
+	ba,a,pt	%xcc, rtrap
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index f37078d..177d8aa 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -24,6 +24,8 @@
 #include <linux/cache.h>
 #include <linux/sort.h>
 #include <linux/percpu.h>
+#include <linux/lmb.h>
+#include <linux/mmzone.h>
 
 #include <asm/head.h>
 #include <asm/system.h>
@@ -72,9 +74,7 @@
 #define MAX_BANKS	32
 
 static struct linux_prom64_registers pavail[MAX_BANKS] __initdata;
-static struct linux_prom64_registers pavail_rescan[MAX_BANKS] __initdata;
 static int pavail_ents __initdata;
-static int pavail_rescan_ents __initdata;
 
 static int cmp_p64(const void *a, const void *b)
 {
@@ -715,285 +715,684 @@
 		smp_new_mmu_context_version();
 }
 
-/* Find a free area for the bootmem map, avoiding the kernel image
- * and the initial ramdisk.
- */
-static unsigned long __init choose_bootmap_pfn(unsigned long start_pfn,
-					       unsigned long end_pfn)
+static int numa_enabled = 1;
+static int numa_debug;
+
+static int __init early_numa(char *p)
 {
-	unsigned long avoid_start, avoid_end, bootmap_size;
-	int i;
+	if (!p)
+		return 0;
 
-	bootmap_size = bootmem_bootmap_pages(end_pfn - start_pfn);
-	bootmap_size <<= PAGE_SHIFT;
+	if (strstr(p, "off"))
+		numa_enabled = 0;
 
-	avoid_start = avoid_end = 0;
+	if (strstr(p, "debug"))
+		numa_debug = 1;
+
+	return 0;
+}
+early_param("numa", early_numa);
+
+#define numadbg(f, a...) \
+do {	if (numa_debug) \
+		printk(KERN_INFO f, ## a); \
+} while (0)
+
+static void __init find_ramdisk(unsigned long phys_base)
+{
 #ifdef CONFIG_BLK_DEV_INITRD
-	avoid_start = initrd_start;
-	avoid_end = PAGE_ALIGN(initrd_end);
-#endif
+	if (sparc_ramdisk_image || sparc_ramdisk_image64) {
+		unsigned long ramdisk_image;
 
-	for (i = 0; i < pavail_ents; i++) {
-		unsigned long start, end;
+		/* Older versions of the bootloader only supported a
+		 * 32-bit physical address for the ramdisk image
+		 * location, stored at sparc_ramdisk_image.  Newer
+		 * SILO versions set sparc_ramdisk_image to zero and
+		 * provide a full 64-bit physical address at
+		 * sparc_ramdisk_image64.
+		 */
+		ramdisk_image = sparc_ramdisk_image;
+		if (!ramdisk_image)
+			ramdisk_image = sparc_ramdisk_image64;
 
-		start = pavail[i].phys_addr;
-		end = start + pavail[i].reg_size;
+		/* Another bootloader quirk.  The bootloader normalizes
+		 * the physical address to KERNBASE, so we have to
+		 * factor that back out and add in the lowest valid
+		 * physical page address to get the true physical address.
+		 */
+		ramdisk_image -= KERNBASE;
+		ramdisk_image += phys_base;
 
-		while (start < end) {
-			if (start >= kern_base &&
-			    start < PAGE_ALIGN(kern_base + kern_size)) {
-				start = PAGE_ALIGN(kern_base + kern_size);
-				continue;
-			}
-			if (start >= avoid_start && start < avoid_end) {
-				start = avoid_end;
-				continue;
-			}
+		numadbg("Found ramdisk at physical address 0x%lx, size %u\n",
+			ramdisk_image, sparc_ramdisk_size);
 
-			if ((end - start) < bootmap_size)
-				break;
+		initrd_start = ramdisk_image;
+		initrd_end = ramdisk_image + sparc_ramdisk_size;
 
-			if (start < kern_base &&
-			    (start + bootmap_size) > kern_base) {
-				start = PAGE_ALIGN(kern_base + kern_size);
-				continue;
-			}
-
-			if (start < avoid_start &&
-			    (start + bootmap_size) > avoid_start) {
-				start = avoid_end;
-				continue;
-			}
-
-			/* OK, it doesn't overlap anything, use it.  */
-			return start >> PAGE_SHIFT;
-		}
+		lmb_reserve(initrd_start, initrd_end);
 	}
-
-	prom_printf("Cannot find free area for bootmap, aborting.\n");
-	prom_halt();
+#endif
 }
 
-static void __init trim_pavail(unsigned long *cur_size_p,
-			       unsigned long *end_of_phys_p)
+struct node_mem_mask {
+	unsigned long mask;
+	unsigned long val;
+	unsigned long bootmem_paddr;
+};
+static struct node_mem_mask node_masks[MAX_NUMNODES];
+static int num_node_masks;
+
+int numa_cpu_lookup_table[NR_CPUS];
+cpumask_t numa_cpumask_lookup_table[MAX_NUMNODES];
+
+#ifdef CONFIG_NEED_MULTIPLE_NODES
+static bootmem_data_t plat_node_bdata[MAX_NUMNODES];
+
+struct mdesc_mblock {
+	u64	base;
+	u64	size;
+	u64	offset; /* RA-to-PA */
+};
+static struct mdesc_mblock *mblocks;
+static int num_mblocks;
+
+static unsigned long ra_to_pa(unsigned long addr)
 {
-	unsigned long to_trim = *cur_size_p - cmdline_memory_size;
-	unsigned long avoid_start, avoid_end;
 	int i;
 
-	to_trim = PAGE_ALIGN(to_trim);
+	for (i = 0; i < num_mblocks; i++) {
+		struct mdesc_mblock *m = &mblocks[i];
 
-	avoid_start = avoid_end = 0;
-#ifdef CONFIG_BLK_DEV_INITRD
-	avoid_start = initrd_start;
-	avoid_end = PAGE_ALIGN(initrd_end);
+		if (addr >= m->base &&
+		    addr < (m->base + m->size)) {
+			addr += m->offset;
+			break;
+		}
+	}
+	return addr;
+}
+
+static int find_node(unsigned long addr)
+{
+	int i;
+
+	addr = ra_to_pa(addr);
+	for (i = 0; i < num_node_masks; i++) {
+		struct node_mem_mask *p = &node_masks[i];
+
+		if ((addr & p->mask) == p->val)
+			return i;
+	}
+	return -1;
+}
+
+static unsigned long nid_range(unsigned long start, unsigned long end,
+			       int *nid)
+{
+	*nid = find_node(start);
+	start += PAGE_SIZE;
+	while (start < end) {
+		int n = find_node(start);
+
+		if (n != *nid)
+			break;
+		start += PAGE_SIZE;
+	}
+
+	return start;
+}
+#else
+static unsigned long nid_range(unsigned long start, unsigned long end,
+			       int *nid)
+{
+	*nid = 0;
+	return end;
+}
 #endif
 
-	/* Trim some pavail[] entries in order to satisfy the
-	 * requested "mem=xxx" kernel command line specification.
-	 *
-	 * We must not trim off the kernel image area nor the
-	 * initial ramdisk range (if any).  Also, we must not trim
-	 * any pavail[] entry down to zero in order to preserve
-	 * the invariant that all pavail[] entries have a non-zero
-	 * size which is assumed by all of the code in here.
-	 */
-	for (i = 0; i < pavail_ents; i++) {
-		unsigned long start, end, kern_end;
-		unsigned long trim_low, trim_high, n;
+/* This must be invoked after performing all of the necessary
+ * add_active_range() calls for 'nid'.  We need to be able to get
+ * correct data from get_pfn_range_for_nid().
+ */
+static void __init allocate_node_data(int nid)
+{
+	unsigned long paddr, num_pages, start_pfn, end_pfn;
+	struct pglist_data *p;
 
-		kern_end = PAGE_ALIGN(kern_base + kern_size);
+#ifdef CONFIG_NEED_MULTIPLE_NODES
+	paddr = lmb_alloc_nid(sizeof(struct pglist_data),
+			      SMP_CACHE_BYTES, nid, nid_range);
+	if (!paddr) {
+		prom_printf("Cannot allocate pglist_data for nid[%d]\n", nid);
+		prom_halt();
+	}
+	NODE_DATA(nid) = __va(paddr);
+	memset(NODE_DATA(nid), 0, sizeof(struct pglist_data));
 
-		trim_low = start = pavail[i].phys_addr;
-		trim_high = end = start + pavail[i].reg_size;
+	NODE_DATA(nid)->bdata = &plat_node_bdata[nid];
+#endif
 
-		if (kern_base >= start &&
-		    kern_base < end) {
-			trim_low = kern_base;
-			if (kern_end >= end)
-				continue;
-		}
-		if (kern_end >= start &&
-		    kern_end < end) {
-			trim_high = kern_end;
-		}
-		if (avoid_start &&
-		    avoid_start >= start &&
-		    avoid_start < end) {
-			if (trim_low > avoid_start)
-				trim_low = avoid_start;
-			if (avoid_end >= end)
-				continue;
-		}
-		if (avoid_end &&
-		    avoid_end >= start &&
-		    avoid_end < end) {
-			if (trim_high < avoid_end)
-				trim_high = avoid_end;
-		}
+	p = NODE_DATA(nid);
 
-		if (trim_high <= trim_low)
+	get_pfn_range_for_nid(nid, &start_pfn, &end_pfn);
+	p->node_start_pfn = start_pfn;
+	p->node_spanned_pages = end_pfn - start_pfn;
+
+	if (p->node_spanned_pages) {
+		num_pages = bootmem_bootmap_pages(p->node_spanned_pages);
+
+		paddr = lmb_alloc_nid(num_pages << PAGE_SHIFT, PAGE_SIZE, nid,
+				      nid_range);
+		if (!paddr) {
+			prom_printf("Cannot allocate bootmap for nid[%d]\n",
+				  nid);
+			prom_halt();
+		}
+		node_masks[nid].bootmem_paddr = paddr;
+	}
+}
+
+static void init_node_masks_nonnuma(void)
+{
+	int i;
+
+	numadbg("Initializing tables for non-numa.\n");
+
+	node_masks[0].mask = node_masks[0].val = 0;
+	num_node_masks = 1;
+
+	for (i = 0; i < NR_CPUS; i++)
+		numa_cpu_lookup_table[i] = 0;
+
+	numa_cpumask_lookup_table[0] = CPU_MASK_ALL;
+}
+
+#ifdef CONFIG_NEED_MULTIPLE_NODES
+struct pglist_data *node_data[MAX_NUMNODES];
+
+EXPORT_SYMBOL(numa_cpu_lookup_table);
+EXPORT_SYMBOL(numa_cpumask_lookup_table);
+EXPORT_SYMBOL(node_data);
+
+struct mdesc_mlgroup {
+	u64	node;
+	u64	latency;
+	u64	match;
+	u64	mask;
+};
+static struct mdesc_mlgroup *mlgroups;
+static int num_mlgroups;
+
+static int scan_pio_for_cfg_handle(struct mdesc_handle *md, u64 pio,
+				   u32 cfg_handle)
+{
+	u64 arc;
+
+	mdesc_for_each_arc(arc, md, pio, MDESC_ARC_TYPE_FWD) {
+		u64 target = mdesc_arc_target(md, arc);
+		const u64 *val;
+
+		val = mdesc_get_property(md, target,
+					 "cfg-handle", NULL);
+		if (val && *val == cfg_handle)
+			return 0;
+	}
+	return -ENODEV;
+}
+
+static int scan_arcs_for_cfg_handle(struct mdesc_handle *md, u64 grp,
+				    u32 cfg_handle)
+{
+	u64 arc, candidate, best_latency = ~(u64)0;
+
+	candidate = MDESC_NODE_NULL;
+	mdesc_for_each_arc(arc, md, grp, MDESC_ARC_TYPE_FWD) {
+		u64 target = mdesc_arc_target(md, arc);
+		const char *name = mdesc_node_name(md, target);
+		const u64 *val;
+
+		if (strcmp(name, "pio-latency-group"))
 			continue;
 
-		if (trim_low == start && trim_high == end) {
-			/* Whole chunk is available for trimming.
-			 * Trim all except one page, in order to keep
-			 * entry non-empty.
-			 */
-			n = (end - start) - PAGE_SIZE;
-			if (n > to_trim)
-				n = to_trim;
+		val = mdesc_get_property(md, target, "latency", NULL);
+		if (!val)
+			continue;
 
-			if (n) {
-				pavail[i].phys_addr += n;
-				pavail[i].reg_size -= n;
-				to_trim -= n;
-			}
-		} else {
-			n = (trim_low - start);
-			if (n > to_trim)
-				n = to_trim;
-
-			if (n) {
-				pavail[i].phys_addr += n;
-				pavail[i].reg_size -= n;
-				to_trim -= n;
-			}
-			if (to_trim) {
-				n = end - trim_high;
-				if (n > to_trim)
-					n = to_trim;
-				if (n) {
-					pavail[i].reg_size -= n;
-					to_trim -= n;
-				}
-			}
+		if (*val < best_latency) {
+			candidate = target;
+			best_latency = *val;
 		}
-
-		if (!to_trim)
-			break;
 	}
 
-	/* Recalculate.  */
-	*cur_size_p = 0UL;
-	for (i = 0; i < pavail_ents; i++) {
-		*end_of_phys_p = pavail[i].phys_addr +
-			pavail[i].reg_size;
-		*cur_size_p += pavail[i].reg_size;
+	if (candidate == MDESC_NODE_NULL)
+		return -ENODEV;
+
+	return scan_pio_for_cfg_handle(md, candidate, cfg_handle);
+}
+
+int of_node_to_nid(struct device_node *dp)
+{
+	const struct linux_prom64_registers *regs;
+	struct mdesc_handle *md;
+	u32 cfg_handle;
+	int count, nid;
+	u64 grp;
+
+	if (!mlgroups)
+		return -1;
+
+	regs = of_get_property(dp, "reg", NULL);
+	if (!regs)
+		return -1;
+
+	cfg_handle = (regs->phys_addr >> 32UL) & 0x0fffffff;
+
+	md = mdesc_grab();
+
+	count = 0;
+	nid = -1;
+	mdesc_for_each_node_by_name(md, grp, "group") {
+		if (!scan_arcs_for_cfg_handle(md, grp, cfg_handle)) {
+			nid = count;
+			break;
+		}
+		count++;
+	}
+
+	mdesc_release(md);
+
+	return nid;
+}
+
+static void add_node_ranges(void)
+{
+	int i;
+
+	for (i = 0; i < lmb.memory.cnt; i++) {
+		unsigned long size = lmb_size_bytes(&lmb.memory, i);
+		unsigned long start, end;
+
+		start = lmb.memory.region[i].base;
+		end = start + size;
+		while (start < end) {
+			unsigned long this_end;
+			int nid;
+
+			this_end = nid_range(start, end, &nid);
+
+			numadbg("Adding active range nid[%d] "
+				"start[%lx] end[%lx]\n",
+				nid, start, this_end);
+
+			add_active_range(nid,
+					 start >> PAGE_SHIFT,
+					 this_end >> PAGE_SHIFT);
+
+			start = this_end;
+		}
 	}
 }
 
-/* About pages_avail, this is the value we will use to calculate
- * the zholes_size[] argument given to free_area_init_node().  The
- * page allocator uses this to calculate nr_kernel_pages,
- * nr_all_pages and zone->present_pages.  On NUMA it is used
- * to calculate zone->min_unmapped_pages and zone->min_slab_pages.
- *
- * So this number should really be set to what the page allocator
- * actually ends up with.  This means:
- * 1) It should include bootmem map pages, we'll release those.
- * 2) It should not include the kernel image, except for the
- *    __init sections which we will also release.
- * 3) It should include the initrd image, since we'll release
- *    that too.
- */
-static unsigned long __init bootmem_init(unsigned long *pages_avail,
-					 unsigned long phys_base)
+static int __init grab_mlgroups(struct mdesc_handle *md)
 {
-	unsigned long bootmap_size, end_pfn;
-	unsigned long end_of_phys_memory = 0UL;
-	unsigned long bootmap_pfn, bytes_avail, size;
+	unsigned long paddr;
+	int count = 0;
+	u64 node;
+
+	mdesc_for_each_node_by_name(md, node, "memory-latency-group")
+		count++;
+	if (!count)
+		return -ENOENT;
+
+	paddr = lmb_alloc(count * sizeof(struct mdesc_mlgroup),
+			  SMP_CACHE_BYTES);
+	if (!paddr)
+		return -ENOMEM;
+
+	mlgroups = __va(paddr);
+	num_mlgroups = count;
+
+	count = 0;
+	mdesc_for_each_node_by_name(md, node, "memory-latency-group") {
+		struct mdesc_mlgroup *m = &mlgroups[count++];
+		const u64 *val;
+
+		m->node = node;
+
+		val = mdesc_get_property(md, node, "latency", NULL);
+		m->latency = *val;
+		val = mdesc_get_property(md, node, "address-match", NULL);
+		m->match = *val;
+		val = mdesc_get_property(md, node, "address-mask", NULL);
+		m->mask = *val;
+
+		numadbg("MLGROUP[%d]: node[%lx] latency[%lx] "
+			"match[%lx] mask[%lx]\n",
+			count - 1, m->node, m->latency, m->match, m->mask);
+	}
+
+	return 0;
+}
+
+static int __init grab_mblocks(struct mdesc_handle *md)
+{
+	unsigned long paddr;
+	int count = 0;
+	u64 node;
+
+	mdesc_for_each_node_by_name(md, node, "mblock")
+		count++;
+	if (!count)
+		return -ENOENT;
+
+	paddr = lmb_alloc(count * sizeof(struct mdesc_mblock),
+			  SMP_CACHE_BYTES);
+	if (!paddr)
+		return -ENOMEM;
+
+	mblocks = __va(paddr);
+	num_mblocks = count;
+
+	count = 0;
+	mdesc_for_each_node_by_name(md, node, "mblock") {
+		struct mdesc_mblock *m = &mblocks[count++];
+		const u64 *val;
+
+		val = mdesc_get_property(md, node, "base", NULL);
+		m->base = *val;
+		val = mdesc_get_property(md, node, "size", NULL);
+		m->size = *val;
+		val = mdesc_get_property(md, node,
+					 "address-congruence-offset", NULL);
+		m->offset = *val;
+
+		numadbg("MBLOCK[%d]: base[%lx] size[%lx] offset[%lx]\n",
+			count - 1, m->base, m->size, m->offset);
+	}
+
+	return 0;
+}
+
+static void __init numa_parse_mdesc_group_cpus(struct mdesc_handle *md,
+					       u64 grp, cpumask_t *mask)
+{
+	u64 arc;
+
+	cpus_clear(*mask);
+
+	mdesc_for_each_arc(arc, md, grp, MDESC_ARC_TYPE_BACK) {
+		u64 target = mdesc_arc_target(md, arc);
+		const char *name = mdesc_node_name(md, target);
+		const u64 *id;
+
+		if (strcmp(name, "cpu"))
+			continue;
+		id = mdesc_get_property(md, target, "id", NULL);
+		if (*id < NR_CPUS)
+			cpu_set(*id, *mask);
+	}
+}
+
+static struct mdesc_mlgroup * __init find_mlgroup(u64 node)
+{
 	int i;
 
-	bytes_avail = 0UL;
-	for (i = 0; i < pavail_ents; i++) {
-		end_of_phys_memory = pavail[i].phys_addr +
-			pavail[i].reg_size;
-		bytes_avail += pavail[i].reg_size;
+	for (i = 0; i < num_mlgroups; i++) {
+		struct mdesc_mlgroup *m = &mlgroups[i];
+		if (m->node == node)
+			return m;
 	}
+	return NULL;
+}
 
-	/* Determine the location of the initial ramdisk before trying
-	 * to honor the "mem=xxx" command line argument.  We must know
-	 * where the kernel image and the ramdisk image are so that we
-	 * do not trim those two areas from the physical memory map.
-	 */
+static int __init numa_attach_mlgroup(struct mdesc_handle *md, u64 grp,
+				      int index)
+{
+	struct mdesc_mlgroup *candidate = NULL;
+	u64 arc, best_latency = ~(u64)0;
+	struct node_mem_mask *n;
 
-#ifdef CONFIG_BLK_DEV_INITRD
-	/* Now have to check initial ramdisk, so that bootmap does not overwrite it */
-	if (sparc_ramdisk_image || sparc_ramdisk_image64) {
-		unsigned long ramdisk_image = sparc_ramdisk_image ?
-			sparc_ramdisk_image : sparc_ramdisk_image64;
-		ramdisk_image -= KERNBASE;
-		initrd_start = ramdisk_image + phys_base;
-		initrd_end = initrd_start + sparc_ramdisk_size;
-		if (initrd_end > end_of_phys_memory) {
-			printk(KERN_CRIT "initrd extends beyond end of memory "
-		                 	 "(0x%016lx > 0x%016lx)\ndisabling initrd\n",
-			       initrd_end, end_of_phys_memory);
-			initrd_start = 0;
-			initrd_end = 0;
+	mdesc_for_each_arc(arc, md, grp, MDESC_ARC_TYPE_FWD) {
+		u64 target = mdesc_arc_target(md, arc);
+		struct mdesc_mlgroup *m = find_mlgroup(target);
+		if (!m)
+			continue;
+		if (m->latency < best_latency) {
+			candidate = m;
+			best_latency = m->latency;
 		}
 	}
-#endif	
+	if (!candidate)
+		return -ENOENT;
 
-	if (cmdline_memory_size &&
-	    bytes_avail > cmdline_memory_size)
-		trim_pavail(&bytes_avail,
-			    &end_of_phys_memory);
+	if (num_node_masks != index) {
+		printk(KERN_ERR "Inconsistent NUMA state, "
+		       "index[%d] != num_node_masks[%d]\n",
+		       index, num_node_masks);
+		return -EINVAL;
+	}
 
-	*pages_avail = bytes_avail >> PAGE_SHIFT;
+	n = &node_masks[num_node_masks++];
 
-	end_pfn = end_of_phys_memory >> PAGE_SHIFT;
+	n->mask = candidate->mask;
+	n->val = candidate->match;
 
-	/* Initialize the boot-time allocator. */
+	numadbg("NUMA NODE[%d]: mask[%lx] val[%lx] (latency[%lx])\n",
+		index, n->mask, n->val, candidate->latency);
+
+	return 0;
+}
+
+static int __init numa_parse_mdesc_group(struct mdesc_handle *md, u64 grp,
+					 int index)
+{
+	cpumask_t mask;
+	int cpu;
+
+	numa_parse_mdesc_group_cpus(md, grp, &mask);
+
+	for_each_cpu_mask(cpu, mask)
+		numa_cpu_lookup_table[cpu] = index;
+	numa_cpumask_lookup_table[index] = mask;
+
+	if (numa_debug) {
+		printk(KERN_INFO "NUMA GROUP[%d]: cpus [ ", index);
+		for_each_cpu_mask(cpu, mask)
+			printk("%d ", cpu);
+		printk("]\n");
+	}
+
+	return numa_attach_mlgroup(md, grp, index);
+}
+
+static int __init numa_parse_mdesc(void)
+{
+	struct mdesc_handle *md = mdesc_grab();
+	int i, err, count;
+	u64 node;
+
+	node = mdesc_node_by_name(md, MDESC_NODE_NULL, "latency-groups");
+	if (node == MDESC_NODE_NULL) {
+		mdesc_release(md);
+		return -ENOENT;
+	}
+
+	err = grab_mblocks(md);
+	if (err < 0)
+		goto out;
+
+	err = grab_mlgroups(md);
+	if (err < 0)
+		goto out;
+
+	count = 0;
+	mdesc_for_each_node_by_name(md, node, "group") {
+		err = numa_parse_mdesc_group(md, node, count);
+		if (err < 0)
+			break;
+		count++;
+	}
+
+	add_node_ranges();
+
+	for (i = 0; i < num_node_masks; i++) {
+		allocate_node_data(i);
+		node_set_online(i);
+	}
+
+	err = 0;
+out:
+	mdesc_release(md);
+	return err;
+}
+
+static int __init numa_parse_sun4u(void)
+{
+	return -1;
+}
+
+static int __init bootmem_init_numa(void)
+{
+	int err = -1;
+
+	numadbg("bootmem_init_numa()\n");
+
+	if (numa_enabled) {
+		if (tlb_type == hypervisor)
+			err = numa_parse_mdesc();
+		else
+			err = numa_parse_sun4u();
+	}
+	return err;
+}
+
+#else
+
+static int bootmem_init_numa(void)
+{
+	return -1;
+}
+
+#endif
+
+static void __init bootmem_init_nonnuma(void)
+{
+	unsigned long top_of_ram = lmb_end_of_DRAM();
+	unsigned long total_ram = lmb_phys_mem_size();
+	unsigned int i;
+
+	numadbg("bootmem_init_nonnuma()\n");
+
+	printk(KERN_INFO "Top of RAM: 0x%lx, Total RAM: 0x%lx\n",
+	       top_of_ram, total_ram);
+	printk(KERN_INFO "Memory hole size: %ldMB\n",
+	       (top_of_ram - total_ram) >> 20);
+
+	init_node_masks_nonnuma();
+
+	for (i = 0; i < lmb.memory.cnt; i++) {
+		unsigned long size = lmb_size_bytes(&lmb.memory, i);
+		unsigned long start_pfn, end_pfn;
+
+		if (!size)
+			continue;
+
+		start_pfn = lmb.memory.region[i].base >> PAGE_SHIFT;
+		end_pfn = start_pfn + lmb_size_pages(&lmb.memory, i);
+		add_active_range(0, start_pfn, end_pfn);
+	}
+
+	allocate_node_data(0);
+
+	node_set_online(0);
+}
+
+static void __init reserve_range_in_node(int nid, unsigned long start,
+					 unsigned long end)
+{
+	numadbg("    reserve_range_in_node(nid[%d],start[%lx],end[%lx]\n",
+		nid, start, end);
+	while (start < end) {
+		unsigned long this_end;
+		int n;
+
+		this_end = nid_range(start, end, &n);
+		if (n == nid) {
+			numadbg("      MATCH reserving range [%lx:%lx]\n",
+				start, this_end);
+			reserve_bootmem_node(NODE_DATA(nid), start,
+					     (this_end - start), BOOTMEM_DEFAULT);
+		} else
+			numadbg("      NO MATCH, advancing start to %lx\n",
+				this_end);
+
+		start = this_end;
+	}
+}
+
+static void __init trim_reserved_in_node(int nid)
+{
+	int i;
+
+	numadbg("  trim_reserved_in_node(%d)\n", nid);
+
+	for (i = 0; i < lmb.reserved.cnt; i++) {
+		unsigned long start = lmb.reserved.region[i].base;
+		unsigned long size = lmb_size_bytes(&lmb.reserved, i);
+		unsigned long end = start + size;
+
+		reserve_range_in_node(nid, start, end);
+	}
+}
+
+static void __init bootmem_init_one_node(int nid)
+{
+	struct pglist_data *p;
+
+	numadbg("bootmem_init_one_node(%d)\n", nid);
+
+	p = NODE_DATA(nid);
+
+	if (p->node_spanned_pages) {
+		unsigned long paddr = node_masks[nid].bootmem_paddr;
+		unsigned long end_pfn;
+
+		end_pfn = p->node_start_pfn + p->node_spanned_pages;
+
+		numadbg("  init_bootmem_node(%d, %lx, %lx, %lx)\n",
+			nid, paddr >> PAGE_SHIFT, p->node_start_pfn, end_pfn);
+
+		init_bootmem_node(p, paddr >> PAGE_SHIFT,
+				  p->node_start_pfn, end_pfn);
+
+		numadbg("  free_bootmem_with_active_regions(%d, %lx)\n",
+			nid, end_pfn);
+		free_bootmem_with_active_regions(nid, end_pfn);
+
+		trim_reserved_in_node(nid);
+
+		numadbg("  sparse_memory_present_with_active_regions(%d)\n",
+			nid);
+		sparse_memory_present_with_active_regions(nid);
+	}
+}
+
+static unsigned long __init bootmem_init(unsigned long phys_base)
+{
+	unsigned long end_pfn;
+	int nid;
+
+	end_pfn = lmb_end_of_DRAM() >> PAGE_SHIFT;
 	max_pfn = max_low_pfn = end_pfn;
 	min_low_pfn = (phys_base >> PAGE_SHIFT);
 
-	bootmap_pfn = choose_bootmap_pfn(min_low_pfn, end_pfn);
+	if (bootmem_init_numa() < 0)
+		bootmem_init_nonnuma();
 
-	bootmap_size = init_bootmem_node(NODE_DATA(0), bootmap_pfn,
-					 min_low_pfn, end_pfn);
+	/* XXX cpu notifier XXX */
 
-	/* Now register the available physical memory with the
-	 * allocator.
-	 */
-	for (i = 0; i < pavail_ents; i++)
-		free_bootmem(pavail[i].phys_addr, pavail[i].reg_size);
-
-#ifdef CONFIG_BLK_DEV_INITRD
-	if (initrd_start) {
-		size = initrd_end - initrd_start;
-
-		/* Reserve the initrd image area. */
-		reserve_bootmem(initrd_start, size, BOOTMEM_DEFAULT);
-
-		initrd_start += PAGE_OFFSET;
-		initrd_end += PAGE_OFFSET;
-	}
-#endif
-	/* Reserve the kernel text/data/bss. */
-	reserve_bootmem(kern_base, kern_size, BOOTMEM_DEFAULT);
-	*pages_avail -= PAGE_ALIGN(kern_size) >> PAGE_SHIFT;
-
-	/* Add back in the initmem pages. */
-	size = ((unsigned long)(__init_end) & PAGE_MASK) -
-		PAGE_ALIGN((unsigned long)__init_begin);
-	*pages_avail += size >> PAGE_SHIFT;
-
-	/* Reserve the bootmem map.   We do not account for it
-	 * in pages_avail because we will release that memory
-	 * in free_all_bootmem.
-	 */
-	size = bootmap_size;
-	reserve_bootmem((bootmap_pfn << PAGE_SHIFT), size, BOOTMEM_DEFAULT);
-
-	for (i = 0; i < pavail_ents; i++) {
-		unsigned long start_pfn, end_pfn;
-
-		start_pfn = pavail[i].phys_addr >> PAGE_SHIFT;
-		end_pfn = (start_pfn + (pavail[i].reg_size >> PAGE_SHIFT));
-		memory_present(0, start_pfn, end_pfn);
-	}
+	for_each_online_node(nid)
+		bootmem_init_one_node(nid);
 
 	sparse_init();
 
@@ -1289,7 +1688,7 @@
 
 void __init paging_init(void)
 {
-	unsigned long end_pfn, pages_avail, shift, phys_base;
+	unsigned long end_pfn, shift, phys_base;
 	unsigned long real_end, i;
 
 	/* These build time checkes make sure that the dcache_dirty_cpu()
@@ -1330,12 +1729,26 @@
 		sun4v_ktsb_init();
 	}
 
+	lmb_init();
+
 	/* Find available physical memory... */
 	read_obp_memory("available", &pavail[0], &pavail_ents);
 
 	phys_base = 0xffffffffffffffffUL;
-	for (i = 0; i < pavail_ents; i++)
+	for (i = 0; i < pavail_ents; i++) {
 		phys_base = min(phys_base, pavail[i].phys_addr);
+		lmb_add(pavail[i].phys_addr, pavail[i].reg_size);
+	}
+
+	lmb_reserve(kern_base, kern_size);
+
+	find_ramdisk(phys_base);
+
+	if (cmdline_memory_size)
+		lmb_enforce_memory_limit(phys_base + cmdline_memory_size);
+
+	lmb_analyze();
+	lmb_dump_all();
 
 	set_bit(0, mmu_context_bmap);
 
@@ -1371,14 +1784,10 @@
 	if (tlb_type == hypervisor)
 		sun4v_ktsb_register();
 
-	/* Setup bootmem... */
-	pages_avail = 0;
-	last_valid_pfn = end_pfn = bootmem_init(&pages_avail, phys_base);
-
-	max_mapnr = last_valid_pfn;
-
-	kernel_physical_mapping_init();
-
+	/* We must setup the per-cpu areas before we pull in the
+	 * PROM and the MDESC.  The code there fills in cpu and
+	 * other information into per-cpu data structures.
+	 */
 	real_setup_per_cpu_areas();
 
 	prom_build_devicetree();
@@ -1386,20 +1795,22 @@
 	if (tlb_type == hypervisor)
 		sun4v_mdesc_init();
 
+	/* Setup bootmem... */
+	last_valid_pfn = end_pfn = bootmem_init(phys_base);
+
+#ifndef CONFIG_NEED_MULTIPLE_NODES
+	max_mapnr = last_valid_pfn;
+#endif
+	kernel_physical_mapping_init();
+
 	{
-		unsigned long zones_size[MAX_NR_ZONES];
-		unsigned long zholes_size[MAX_NR_ZONES];
-		int znum;
+		unsigned long max_zone_pfns[MAX_NR_ZONES];
 
-		for (znum = 0; znum < MAX_NR_ZONES; znum++)
-			zones_size[znum] = zholes_size[znum] = 0;
+		memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
 
-		zones_size[ZONE_NORMAL] = end_pfn;
-		zholes_size[ZONE_NORMAL] = end_pfn - pages_avail;
+		max_zone_pfns[ZONE_NORMAL] = end_pfn;
 
-		free_area_init_node(0, &contig_page_data, zones_size,
-				    __pa(PAGE_OFFSET) >> PAGE_SHIFT,
-				    zholes_size);
+		free_area_init_nodes(max_zone_pfns);
 	}
 
 	printk("Booting Linux...\n");
@@ -1408,21 +1819,52 @@
 	cpu_probe();
 }
 
-static void __init taint_real_pages(void)
+int __init page_in_phys_avail(unsigned long paddr)
+{
+	int i;
+
+	paddr &= PAGE_MASK;
+
+	for (i = 0; i < pavail_ents; i++) {
+		unsigned long start, end;
+
+		start = pavail[i].phys_addr;
+		end = start + pavail[i].reg_size;
+
+		if (paddr >= start && paddr < end)
+			return 1;
+	}
+	if (paddr >= kern_base && paddr < (kern_base + kern_size))
+		return 1;
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (paddr >= __pa(initrd_start) &&
+	    paddr < __pa(PAGE_ALIGN(initrd_end)))
+		return 1;
+#endif
+
+	return 0;
+}
+
+static struct linux_prom64_registers pavail_rescan[MAX_BANKS] __initdata;
+static int pavail_rescan_ents __initdata;
+
+/* Certain OBP calls, such as fetching "available" properties, can
+ * claim physical memory.  So, along with initializing the valid
+ * address bitmap, what we do here is refetch the physical available
+ * memory list again, and make sure it provides at least as much
+ * memory as 'pavail' does.
+ */
+static void setup_valid_addr_bitmap_from_pavail(void)
 {
 	int i;
 
 	read_obp_memory("available", &pavail_rescan[0], &pavail_rescan_ents);
 
-	/* Find changes discovered in the physmem available rescan and
-	 * reserve the lost portions in the bootmem maps.
-	 */
 	for (i = 0; i < pavail_ents; i++) {
 		unsigned long old_start, old_end;
 
 		old_start = pavail[i].phys_addr;
-		old_end = old_start +
-			pavail[i].reg_size;
+		old_end = old_start + pavail[i].reg_size;
 		while (old_start < old_end) {
 			int n;
 
@@ -1440,7 +1882,16 @@
 					goto do_next_page;
 				}
 			}
-			reserve_bootmem(old_start, PAGE_SIZE, BOOTMEM_DEFAULT);
+
+			prom_printf("mem_init: Lost memory in pavail\n");
+			prom_printf("mem_init: OLD start[%lx] size[%lx]\n",
+				    pavail[i].phys_addr,
+				    pavail[i].reg_size);
+			prom_printf("mem_init: NEW start[%lx] size[%lx]\n",
+				    pavail_rescan[i].phys_addr,
+				    pavail_rescan[i].reg_size);
+			prom_printf("mem_init: Cannot continue, aborting.\n");
+			prom_halt();
 
 		do_next_page:
 			old_start += PAGE_SIZE;
@@ -1448,32 +1899,6 @@
 	}
 }
 
-int __init page_in_phys_avail(unsigned long paddr)
-{
-	int i;
-
-	paddr &= PAGE_MASK;
-
-	for (i = 0; i < pavail_rescan_ents; i++) {
-		unsigned long start, end;
-
-		start = pavail_rescan[i].phys_addr;
-		end = start + pavail_rescan[i].reg_size;
-
-		if (paddr >= start && paddr < end)
-			return 1;
-	}
-	if (paddr >= kern_base && paddr < (kern_base + kern_size))
-		return 1;
-#ifdef CONFIG_BLK_DEV_INITRD
-	if (paddr >= __pa(initrd_start) &&
-	    paddr < __pa(PAGE_ALIGN(initrd_end)))
-		return 1;
-#endif
-
-	return 0;
-}
-
 void __init mem_init(void)
 {
 	unsigned long codepages, datapages, initpages;
@@ -1496,14 +1921,26 @@
 		addr += PAGE_SIZE;
 	}
 
-	taint_real_pages();
+	setup_valid_addr_bitmap_from_pavail();
 
 	high_memory = __va(last_valid_pfn << PAGE_SHIFT);
 
+#ifdef CONFIG_NEED_MULTIPLE_NODES
+	for_each_online_node(i) {
+		if (NODE_DATA(i)->node_spanned_pages != 0) {
+			totalram_pages +=
+				free_all_bootmem_node(NODE_DATA(i));
+		}
+	}
+#else
+	totalram_pages = free_all_bootmem();
+#endif
+
 	/* We subtract one to account for the mem_map_zero page
 	 * allocated below.
 	 */
-	totalram_pages = num_physpages = free_all_bootmem() - 1;
+	totalram_pages -= 1;
+	num_physpages = totalram_pages;
 
 	/*
 	 * Set up the zero page, mark it reserved, so that page count
diff --git a/arch/sparc64/mm/tsb.c b/arch/sparc64/mm/tsb.c
index a3e6e4b..fe70c8a 100644
--- a/arch/sparc64/mm/tsb.c
+++ b/arch/sparc64/mm/tsb.c
@@ -321,7 +321,8 @@
 	if (new_size > (PAGE_SIZE * 2))
 		gfp_flags = __GFP_NOWARN | __GFP_NORETRY;
 
-	new_tsb = kmem_cache_alloc(tsb_caches[new_cache_index], gfp_flags);
+	new_tsb = kmem_cache_alloc_node(tsb_caches[new_cache_index],
+					gfp_flags, numa_node_id());
 	if (unlikely(!new_tsb)) {
 		/* Not being able to fork due to a high-order TSB
 		 * allocation failure is very bad behavior.  Just back
diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S
index 2865c10..e686a67 100644
--- a/arch/sparc64/mm/ultra.S
+++ b/arch/sparc64/mm/ultra.S
@@ -476,7 +476,6 @@
 #endif
 	call		smp_synchronize_tick_client
 	 nop
-	clr		%l6
 	b		rtrap_xcall
 	 ldx		[%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
 
@@ -511,7 +510,6 @@
 #endif
 	call		__show_regs
 	 add		%sp, PTREGS_OFF, %o0
-	clr		%l6
 	/* Has to be a non-v9 branch due to the large distance. */
 	b		rtrap_xcall
 	 ldx		[%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
@@ -576,7 +574,7 @@
 	mov	%l4, %o0
 	call	hypervisor_tlbop_error_xcall
 	 mov	%l5, %o1
-	ba,a,pt	%xcc, rtrap_clr_l6
+	ba,a,pt	%xcc, rtrap
 
 	.globl		__hypervisor_xcall_flush_tlb_mm
 __hypervisor_xcall_flush_tlb_mm: /* 21 insns */
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index a87b89d..2906ee7 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -481,6 +481,34 @@
 
 	  It's safe to say N here.
 
+config BFIN_OTP
+	tristate "Blackfin On-Chip OTP Memory Support"
+	depends on BLACKFIN && (BF52x || BF54x)
+	default y
+	help
+	  If you say Y here, you will get support for a character device
+	  interface into the One Time Programmable memory pages that are
+	  stored on the Blackfin processor.  This will not get you access
+	  to the secure memory pages however.  You will need to write your
+	  own secure code and reader for that.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called bfin-otp.
+
+	  If unsure, it is safe to say Y.
+
+config BFIN_OTP_WRITE_ENABLE
+	bool "Enable writing support of OTP pages"
+	depends on BFIN_OTP
+	default n
+	help
+	  If you say Y here, you will enable support for writing of the
+	  OTP pages.  This is dangerous by nature as you can only program
+	  the pages once, so only enable this option when you actually
+	  need it so as to not inadvertently clobber data.
+
+	  If unsure, say N.
+
 config PRINTER
 	tristate "Parallel printer support"
 	depends on PARPORT
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 5407b76..4c1c584 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -59,6 +59,7 @@
 obj-$(CONFIG_HVCS)		+= hvcs.o
 obj-$(CONFIG_SGI_MBCS)		+= mbcs.o
 obj-$(CONFIG_BRIQ_PANEL)	+= briq_panel.o
+obj-$(CONFIG_BFIN_OTP)		+= bfin-otp.o
 
 obj-$(CONFIG_PRINTER)		+= lp.o
 obj-$(CONFIG_TIPAR)		+= tipar.o
diff --git a/drivers/char/bfin-otp.c b/drivers/char/bfin-otp.c
new file mode 100644
index 0000000..0a01329
--- /dev/null
+++ b/drivers/char/bfin-otp.c
@@ -0,0 +1,189 @@
+/*
+ * Blackfin On-Chip OTP Memory Interface
+ *  Supports BF52x/BF54x
+ *
+ * Copyright 2007-2008 Analog Devices Inc.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+
+#include <asm/blackfin.h>
+#include <asm/uaccess.h>
+
+#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args)
+#define stampit() stamp("here i am")
+#define pr_init(fmt, args...) ({ static const __initconst char __fmt[] = fmt; printk(__fmt, ## args); })
+
+#define DRIVER_NAME "bfin-otp"
+#define PFX DRIVER_NAME ": "
+
+static DEFINE_MUTEX(bfin_otp_lock);
+
+/* OTP Boot ROM functions */
+#define _BOOTROM_OTP_COMMAND           0xEF000018
+#define _BOOTROM_OTP_READ              0xEF00001A
+#define _BOOTROM_OTP_WRITE             0xEF00001C
+
+static u32 (* const otp_command)(u32 command, u32 value) = (void *)_BOOTROM_OTP_COMMAND;
+static u32 (* const otp_read)(u32 page, u32 flags, u64 *page_content) = (void *)_BOOTROM_OTP_READ;
+static u32 (* const otp_write)(u32 page, u32 flags, u64 *page_content) = (void *)_BOOTROM_OTP_WRITE;
+
+/* otp_command(): defines for "command" */
+#define OTP_INIT             0x00000001
+#define OTP_CLOSE            0x00000002
+
+/* otp_{read,write}(): defines for "flags" */
+#define OTP_LOWER_HALF       0x00000000 /* select upper/lower 64-bit half (bit 0) */
+#define OTP_UPPER_HALF       0x00000001
+#define OTP_NO_ECC           0x00000010 /* do not use ECC */
+#define OTP_LOCK             0x00000020 /* sets page protection bit for page */
+#define OTP_ACCESS_READ      0x00001000
+#define OTP_ACCESS_READWRITE 0x00002000
+
+/* Return values for all functions */
+#define OTP_SUCCESS          0x00000000
+#define OTP_MASTER_ERROR     0x001
+#define OTP_WRITE_ERROR      0x003
+#define OTP_READ_ERROR       0x005
+#define OTP_ACC_VIO_ERROR    0x009
+#define OTP_DATA_MULT_ERROR  0x011
+#define OTP_ECC_MULT_ERROR   0x021
+#define OTP_PREV_WR_ERROR    0x041
+#define OTP_DATA_SB_WARN     0x100
+#define OTP_ECC_SB_WARN      0x200
+
+/**
+ *	bfin_otp_read - Read OTP pages
+ *
+ *	All reads must be in half page chunks (half page == 64 bits).
+ */
+static ssize_t bfin_otp_read(struct file *file, char __user *buff, size_t count, loff_t *pos)
+{
+	ssize_t bytes_done;
+	u32 page, flags, ret;
+	u64 content;
+
+	stampit();
+
+	if (count % sizeof(u64))
+		return -EMSGSIZE;
+
+	if (mutex_lock_interruptible(&bfin_otp_lock))
+		return -ERESTARTSYS;
+
+	bytes_done = 0;
+	page = *pos / (sizeof(u64) * 2);
+	while (bytes_done < count) {
+		flags = (*pos % (sizeof(u64) * 2) ? OTP_UPPER_HALF : OTP_LOWER_HALF);
+		stamp("processing page %i (%s)", page, (flags == OTP_UPPER_HALF ? "upper" : "lower"));
+		ret = otp_read(page, flags, &content);
+		if (ret & OTP_MASTER_ERROR) {
+			bytes_done = -EIO;
+			break;
+		}
+		if (copy_to_user(buff + bytes_done, &content, sizeof(content))) {
+			bytes_done = -EFAULT;
+			break;
+		}
+		if (flags == OTP_UPPER_HALF)
+			++page;
+		bytes_done += sizeof(content);
+		*pos += sizeof(content);
+	}
+
+	mutex_unlock(&bfin_otp_lock);
+
+	return bytes_done;
+}
+
+#ifdef CONFIG_BFIN_OTP_WRITE_ENABLE
+/**
+ *	bfin_otp_write - Write OTP pages
+ *
+ *	All writes must be in half page chunks (half page == 64 bits).
+ */
+static ssize_t bfin_otp_write(struct file *filp, const char __user *buff, size_t count, loff_t *pos)
+{
+	stampit();
+
+	if (count % sizeof(u64))
+		return -EMSGSIZE;
+
+	if (mutex_lock_interruptible(&bfin_otp_lock))
+		return -ERESTARTSYS;
+
+	/* need otp_init() documentation before this can be implemented */
+
+	mutex_unlock(&bfin_otp_lock);
+
+	return -EINVAL;
+}
+#else
+# define bfin_otp_write NULL
+#endif
+
+static struct file_operations bfin_otp_fops = {
+	.owner    = THIS_MODULE,
+	.read     = bfin_otp_read,
+	.write    = bfin_otp_write,
+};
+
+static struct miscdevice bfin_otp_misc_device = {
+	.minor    = MISC_DYNAMIC_MINOR,
+	.name     = DRIVER_NAME,
+	.fops     = &bfin_otp_fops,
+};
+
+/**
+ *	bfin_otp_init - Initialize module
+ *
+ *	Registers the device and notifier handler. Actual device
+ *	initialization is handled by bfin_otp_open().
+ */
+static int __init bfin_otp_init(void)
+{
+	int ret;
+
+	stampit();
+
+	ret = misc_register(&bfin_otp_misc_device);
+	if (ret) {
+		pr_init(KERN_ERR PFX "unable to register a misc device\n");
+		return ret;
+	}
+
+	pr_init(KERN_INFO PFX "initialized\n");
+
+	return 0;
+}
+
+/**
+ *	bfin_otp_exit - Deinitialize module
+ *
+ *	Unregisters the device and notifier handler. Actual device
+ *	deinitialization is handled by bfin_otp_close().
+ */
+static void __exit bfin_otp_exit(void)
+{
+	stampit();
+
+	misc_deregister(&bfin_otp_misc_device);
+}
+
+module_init(bfin_otp_init);
+module_exit(bfin_otp_exit);
+
+MODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>");
+MODULE_DESCRIPTION("Blackfin OTP Memory Interface");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/mwave/tp3780i.c b/drivers/char/mwave/tp3780i.c
index 37fe80d..f282976 100644
--- a/drivers/char/mwave/tp3780i.c
+++ b/drivers/char/mwave/tp3780i.c
@@ -97,24 +97,20 @@
 
 static irqreturn_t UartInterrupt(int irq, void *dev_id)
 {
-	int irqno = (int)(unsigned long) dev_id;
-
 	PRINTK_3(TRACE_TP3780I,
-		"tp3780i::UartInterrupt entry irq %x dev_id %p\n", irqno, dev_id);
+		"tp3780i::UartInterrupt entry irq %x dev_id %p\n", irq, dev_id);
 	return IRQ_HANDLED;
 }
 
 static irqreturn_t DspInterrupt(int irq, void *dev_id)
 {
-	int irqno = (int)(unsigned long) dev_id;
-
 	pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd;
 	DSP_3780I_CONFIG_SETTINGS *pSettings = &pDrvData->rBDData.rDspSettings;
 	unsigned short usDspBaseIO = pSettings->usDspBaseIO;
 	unsigned short usIPCSource = 0, usIsolationMask, usPCNum;
 
 	PRINTK_3(TRACE_TP3780I,
-		"tp3780i::DspInterrupt entry irq %x dev_id %p\n", irqno, dev_id);
+		"tp3780i::DspInterrupt entry irq %x dev_id %p\n", irq, dev_id);
 
 	if (dsp3780I_GetIPCSource(usDspBaseIO, &usIPCSource) == 0) {
 		PRINTK_2(TRACE_TP3780I,
@@ -365,16 +361,14 @@
 	pSettings->bPllBypass = TP_CFG_PllBypass;
 	pSettings->usChipletEnable = TP_CFG_ChipletEnable;
 
-	if (request_irq(pSettings->usUartIrq, &UartInterrupt, 0, "mwave_uart",
-			(void *)(unsigned long) pSettings->usUartIrq)) {
+	if (request_irq(pSettings->usUartIrq, &UartInterrupt, 0, "mwave_uart", NULL)) {
 		PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_EnableDSP: Error: Could not get UART IRQ %x\n", pSettings->usUartIrq);
 		goto exit_cleanup;
 	} else {		/* no conflict just release */
 		free_irq(pSettings->usUartIrq, NULL);
 	}
 
-	if (request_irq(pSettings->usDspIrq, &DspInterrupt, 0, "mwave_3780i",
-			(void *)(unsigned long) pSettings->usDspIrq)) {
+	if (request_irq(pSettings->usDspIrq, &DspInterrupt, 0, "mwave_3780i", NULL)) {
 		PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Error: Could not get 3780i IRQ %x\n", pSettings->usDspIrq);
 		goto exit_cleanup;
 	} else {
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index c5263d6..92b6834 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -15,6 +15,7 @@
 config INPUT_PCSPKR
 	tristate "PC Speaker support"
 	depends on ALPHA || X86 || MIPS || PPC_PREP || PPC_CHRP || PPC_PSERIES
+	depends on SND_PCSP=n
 	help
 	  Say Y here if you want the standard PC Speaker to be used for
 	  bells and whistles.
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 1195069..128bb9c 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -30,7 +30,7 @@
 	depends on (I2C || I2C=n) && VIDEO_DEV
 	default (I2C || I2C=n) && VIDEO_DEV
 
-config VIDEO_V4L1
+config VIDEO_ALLOW_V4L1
 	bool "Enable Video For Linux API 1 (DEPRECATED)"
 	depends on VIDEO_DEV && VIDEO_V4L2_COMMON
 	default VIDEO_DEV && VIDEO_V4L2_COMMON
@@ -59,10 +59,15 @@
 	  If you are unsure as to whether this is required, answer Y.
 
 config VIDEO_V4L2
-	bool
+	tristate
 	depends on VIDEO_DEV && VIDEO_V4L2_COMMON
 	default VIDEO_DEV && VIDEO_V4L2_COMMON
 
+config VIDEO_V4L1
+	tristate
+	depends on VIDEO_DEV && VIDEO_V4L2_COMMON && VIDEO_ALLOW_V4L1
+	default VIDEO_DEV && VIDEO_V4L2_COMMON && VIDEO_ALLOW_V4L1
+
 source "drivers/media/video/Kconfig"
 
 source "drivers/media/radio/Kconfig"
@@ -155,7 +160,7 @@
 	tristate
 
 config VIDEOBUF_DMA_SG
-	depends on PCI
+	depends on HAS_DMA
 	select VIDEOBUF_GEN
 	tristate
 
diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c
index bb2a027..2665052 100644
--- a/drivers/media/common/ir-functions.c
+++ b/drivers/media/common/ir-functions.c
@@ -34,7 +34,7 @@
 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) */
+static int debug;    /* debug level (0,1,2) */
 module_param(debug, int, 0644);
 
 #define dprintk(level, fmt, arg...)	if (debug >= level) \
diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
index 2ab5a12..a348581 100644
--- a/drivers/media/common/ir-keymaps.c
+++ b/drivers/media/common/ir-keymaps.c
@@ -212,6 +212,51 @@
 
 EXPORT_SYMBOL_GPL(ir_codes_pixelview);
 
+/*
+   Mauro Carvalho Chehab <mchehab@infradead.org>
+   present on PV MPEG 8000GT
+ */
+IR_KEYTAB_TYPE ir_codes_pixelview_new[IR_KEYTAB_SIZE] = {
+	[0x3c] = KEY_PAUSE,		/* Timeshift */
+	[0x12] = KEY_POWER,
+
+	[0x3d] = KEY_1,
+	[0x38] = KEY_2,
+	[0x18] = KEY_3,
+	[0x35] = KEY_4,
+	[0x39] = KEY_5,
+	[0x15] = KEY_6,
+	[0x36] = KEY_7,
+	[0x3a] = KEY_8,
+	[0x1e] = KEY_9,
+	[0x3e] = KEY_0,
+
+	[0x1c] = KEY_AGAIN,		/* LOOP	*/
+	[0x3f] = KEY_MEDIA,		/* Source */
+	[0x1f] = KEY_LAST,		/* +100 */
+	[0x1b] = KEY_MUTE,
+
+	[0x17] = KEY_CHANNELDOWN,
+	[0x16] = KEY_CHANNELUP,
+	[0x10] = KEY_VOLUMEUP,
+	[0x14] = KEY_VOLUMEDOWN,
+	[0x13] = KEY_ZOOM,
+
+	[0x19] = KEY_SHUFFLE,		/* SNAPSHOT */
+	[0x1a] = KEY_SEARCH,		/* scan */
+
+	[0x37] = KEY_REWIND,		/* << */
+	[0x32] = KEY_RECORD,		/* o (red) */
+	[0x33] = KEY_FORWARD,		/* >> */
+	[0x11] = KEY_STOP,		/* square */
+	[0x3b] = KEY_PLAY,		/* > */
+	[0x30] = KEY_PLAYPAUSE,		/* || */
+
+	[0x31] = KEY_TV,
+	[0x34] = KEY_RADIO,
+};
+EXPORT_SYMBOL_GPL(ir_codes_pixelview_new);
+
 IR_KEYTAB_TYPE ir_codes_nebula[IR_KEYTAB_SIZE] = {
 	[ 0x00 ] = KEY_0,
 	[ 0x01 ] = KEY_1,
@@ -726,7 +771,11 @@
 	[ 0x12 ] = KEY_CHANNELUP,    // Channel +
 	[ 0x13 ] = KEY_CHANNELDOWN,  // Channel -
 	[ 0x06 ] = KEY_AGAIN,        // Recall
-	[ 0x10 ] = KEY_ENTER,      // Enter
+	[ 0x10 ] = KEY_ENTER,        // Enter
+
+	[ 0x19 ] = KEY_BACK,         // Rewind  ( <<< )
+	[ 0x1f ] = KEY_FORWARD,      // Forward ( >>> )
+	[ 0x0a ] = KEY_ANGLE,        // (no label, may be used as the PAUSE button)
 };
 
 EXPORT_SYMBOL_GPL(ir_codes_flyvideo);
@@ -1157,7 +1206,8 @@
 
 /* Mapping for the 28 key remote control as seen at
    http://www.sednacomputer.com/photo/cardbus-tv.jpg
-   Pavel Mihaylov <bin@bash.info> */
+   Pavel Mihaylov <bin@bash.info>
+   Also for the remote bundled with Kozumi KTV-01C card */
 IR_KEYTAB_TYPE ir_codes_pctv_sedna[IR_KEYTAB_SIZE] = {
 	[ 0x00 ] = KEY_0,
 	[ 0x01 ] = KEY_1,
@@ -1188,6 +1238,11 @@
 	[ 0x1c ] = KEY_RADIO,          /* FM Radio */
 	[ 0x1d ] = KEY_RECORD,
 	[ 0x1e ] = KEY_PAUSE,
+	/* additional codes for Kozumi's remote */
+	[0x14] = KEY_INFO,        /* OSD */
+	[0x16] = KEY_OK,          /* OK */
+	[0x17] = KEY_DIGITS,      /* Plus */
+	[0x1f] = KEY_PLAY,        /* Play */
 };
 
 EXPORT_SYMBOL_GPL(ir_codes_pctv_sedna);
@@ -1988,6 +2043,76 @@
 
 EXPORT_SYMBOL_GPL(ir_codes_behold);
 
+/* Beholder Intl. Ltd. 2008
+ * Dmitry Belimov d.belimov@google.com
+ * Keytable is used by BeholdTV Columbus
+ * 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_behold_columbus[IR_KEYTAB_SIZE] = {
+
+	/*  0x13   0x11   0x1C   0x12  *
+	 *  Mute  Source  TV/FM  Power *
+	 *                             */
+
+	[0x13] = KEY_MUTE,
+	[0x11] = KEY_PROPS,
+	[0x1C] = KEY_TUNER,	/* KEY_TV/KEY_RADIO */
+	[0x12] = KEY_POWER,
+
+	/*  0x01    0x02    0x03  0x0D    *
+	 *   1       2       3   Stereo   *
+	 *                        	  *
+	 *  0x04    0x05    0x06  0x19    *
+	 *   4       5       6   Snapshot *
+	 *                        	  *
+	 *  0x07    0x08    0x09  0x10    *
+	 *   7       8       9    Zoom 	  *
+	 *                                */
+	[0x01] = KEY_1,
+	[0x02] = KEY_2,
+	[0x03] = KEY_3,
+	[0x0D] = KEY_SETUP,	  /* Setup key */
+	[0x04] = KEY_4,
+	[0x05] = KEY_5,
+	[0x06] = KEY_6,
+	[0x19] = KEY_BOOKMARKS, /* Snapshot key */
+	[0x07] = KEY_7,
+	[0x08] = KEY_8,
+	[0x09] = KEY_9,
+	[0x10] = KEY_ZOOM,
+
+	/*  0x0A    0x00    0x0B       0x0C   *
+	 * RECALL    0    ChannelUp  VolumeUp *
+	 *                                    */
+	[0x0A] = KEY_AGAIN,
+	[0x00] = KEY_0,
+	[0x0B] = KEY_CHANNELUP,
+	[0x0C] = KEY_VOLUMEUP,
+
+	/*   0x1B      0x1D      0x15        0x18     *
+	 * Timeshift  Record  ChannelDown  VolumeDown *
+	 *                                            */
+
+	[0x1B] = KEY_REWIND,
+	[0x1D] = KEY_RECORD,
+	[0x15] = KEY_CHANNELDOWN,
+	[0x18] = KEY_VOLUMEDOWN,
+
+	/*   0x0E   0x1E     0x0F     0x1A  *
+	 *   Stop   Pause  Previouse  Next  *
+	 *                                  */
+
+	[0x0E] = KEY_STOP,
+	[0x1E] = KEY_PAUSE,
+	[0x0F] = KEY_PREVIOUS,
+	[0x1A] = KEY_NEXT,
+
+};
+EXPORT_SYMBOL_GPL(ir_codes_behold_columbus);
+
 /*
  * Remote control for the Genius TVGO A11MCE
  * Adrian Pardini <pardo.bsso@gmail.com>
@@ -2033,3 +2158,46 @@
 	[0x50] = KEY_BLUE,
 };
 EXPORT_SYMBOL_GPL(ir_codes_genius_tvgo_a11mce);
+
+/*
+ * Remote control for Powercolor Real Angel 330
+ * Daniel Fraga <fragabr@gmail.com>
+ */
+IR_KEYTAB_TYPE ir_codes_powercolor_real_angel[IR_KEYTAB_SIZE] = {
+	[0x38] = KEY_SWITCHVIDEOMODE,	/* switch inputs */
+	[0x0c] = KEY_MEDIA,		/* Turn ON/OFF App */
+	[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_DIGITS,		/* single, double, tripple digit */
+	[0x29] = KEY_PREVIOUS,		/* previous channel */
+	[0x12] = KEY_BRIGHTNESSUP,
+	[0x13] = KEY_BRIGHTNESSDOWN,
+	[0x2b] = KEY_MODE,		/* stereo/mono */
+	[0x2c] = KEY_TEXT,		/* teletext */
+	[0x20] = KEY_UP,		/* channel up */
+	[0x21] = KEY_DOWN,		/* channel down */
+	[0x10] = KEY_RIGHT,		/* volume up */
+	[0x11] = KEY_LEFT,		/* volume down */
+	[0x0d] = KEY_MUTE,
+	[0x1f] = KEY_RECORD,
+	[0x17] = KEY_PLAY,
+	[0x16] = KEY_PAUSE,
+	[0x0b] = KEY_STOP,
+	[0x27] = KEY_FASTFORWARD,
+	[0x26] = KEY_REWIND,
+	[0x1e] = KEY_SEARCH,		/* autoscan */
+	[0x0e] = KEY_SHUFFLE,		/* snapshot */
+	[0x2d] = KEY_SETUP,
+	[0x0f] = KEY_SCREEN,		/* full screen */
+	[0x14] = KEY_RADIO,		/* FM radio */
+	[0x25] = KEY_POWER,		/* power */
+};
+EXPORT_SYMBOL_GPL(ir_codes_powercolor_real_angel);
diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c
index 7707b8c..89c7660 100644
--- a/drivers/media/common/saa7146_core.c
+++ b/drivers/media/common/saa7146_core.c
@@ -74,7 +74,7 @@
 		if (err) {
 			printk(KERN_ERR "%s: %s timed out while waiting for "
 					"registers getting programmed\n",
-					dev->name, __FUNCTION__);
+					dev->name, __func__);
 			return -ETIMEDOUT;
 		}
 		msleep(1);
@@ -89,7 +89,7 @@
 		saa7146_read(dev, MC2);
 		if (err) {
 			DEB_S(("%s: %s timed out while waiting for transfer "
-				"completion\n",	dev->name, __FUNCTION__));
+				"completion\n",	dev->name, __func__));
 			return -ETIMEDOUT;
 		}
 		msleep(1);
@@ -111,7 +111,7 @@
 		if (!loops--) {
 			printk(KERN_ERR "%s: %s timed out while waiting for "
 					"registers getting programmed\n",
-					dev->name, __FUNCTION__);
+					dev->name, __func__);
 			return -ETIMEDOUT;
 		}
 		udelay(1);
@@ -125,7 +125,7 @@
 		saa7146_read(dev, MC2);
 		if (!loops--) {
 			DEB_S(("%s: %s timed out while waiting for transfer "
-				"completion\n", dev->name, __FUNCTION__));
+				"completion\n", dev->name, __func__));
 			return -ETIMEDOUT;
 		}
 		udelay(5);
diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c
index 7e7689a..35b01ec 100644
--- a/drivers/media/common/saa7146_i2c.c
+++ b/drivers/media/common/saa7146_i2c.c
@@ -203,7 +203,7 @@
 				return -ERESTARTSYS;
 
 			printk(KERN_WARNING "%s %s [irq]: timed out waiting for end of xfer\n",
-				dev->name, __FUNCTION__);
+				dev->name, __func__);
 			return -EIO;
 		}
 		status = saa7146_read(dev, I2C_STATUS);
@@ -221,7 +221,7 @@
 			}
 			if (time_after(jiffies,timeout)) {
 				printk(KERN_WARNING "%s %s: timed out waiting for MC2\n",
-					dev->name, __FUNCTION__);
+					dev->name, __func__);
 				return -EIO;
 			}
 		}
@@ -238,7 +238,7 @@
 				 * (no answer from nonexisistant device...)
 				 */
 				printk(KERN_WARNING "%s %s [poll]: timed out waiting for end of xfer\n",
-					dev->name, __FUNCTION__);
+					dev->name, __func__);
 				return -EIO;
 			}
 			if (++trial < 50 && short_delay)
diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c
index bfbd5a8..74e2b56 100644
--- a/drivers/media/common/saa7146_vbi.c
+++ b/drivers/media/common/saa7146_vbi.c
@@ -407,8 +407,8 @@
 	fh->vbi_fmt.start[1] = 312;
 	fh->vbi_fmt.count[1] = 16;
 
-	videobuf_queue_pci_init(&fh->vbi_q, &vbi_qops,
-			    dev->pci, &dev->slock,
+	videobuf_queue_sg_init(&fh->vbi_q, &vbi_qops,
+			    &dev->pci->dev, &dev->slock,
 			    V4L2_BUF_TYPE_VBI_CAPTURE,
 			    V4L2_FIELD_SEQ_TB, // FIXME: does this really work?
 			    sizeof(struct saa7146_buf),
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index 66fdbd0..3cbc6eb 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -1410,8 +1410,8 @@
 	sfmt = format_by_fourcc(dev,fh->video_fmt.pixelformat);
 	fh->video_fmt.sizeimage = (fh->video_fmt.width * fh->video_fmt.height * sfmt->depth)/8;
 
-	videobuf_queue_pci_init(&fh->video_q, &video_qops,
-			    dev->pci, &dev->slock,
+	videobuf_queue_sg_init(&fh->video_q, &video_qops,
+			    &dev->pci->dev, &dev->slock,
 			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
 			    V4L2_FIELD_INTERLACED,
 			    sizeof(struct saa7146_buf),
diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig
index 3197aeb..6ec5afb 100644
--- a/drivers/media/dvb/b2c2/Kconfig
+++ b/drivers/media/dvb/b2c2/Kconfig
@@ -9,6 +9,11 @@
 	select DVB_STV0297 if !DVB_FE_CUSTOMISE
 	select DVB_BCM3510 if !DVB_FE_CUSTOMISE
 	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+	select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+	select DVB_S5H1420 if !DVB_FE_CUSTOMISE
+	select DVB_TUNER_ITD1000 if !DVB_FE_CUSTOMISE
+	select DVB_ISL6421 if !DVB_FE_CUSTOMISE
+	select DVB_CX24123 if !DVB_FE_CUSTOMISE
 	help
 	  Support for the digital TV receiver chip made by B2C2 Inc. included in
 	  Technisats PCI cards and USB boxes.
diff --git a/drivers/media/dvb/b2c2/Makefile b/drivers/media/dvb/b2c2/Makefile
index e97ff60..870e284 100644
--- a/drivers/media/dvb/b2c2/Makefile
+++ b/drivers/media/dvb/b2c2/Makefile
@@ -2,6 +2,7 @@
 	flexcop-sram.o flexcop-eeprom.o flexcop-misc.o flexcop-hw-filter.o
 obj-$(CONFIG_DVB_B2C2_FLEXCOP) += b2c2-flexcop.o
 
+
 ifneq ($(CONFIG_DVB_B2C2_FLEXCOP_PCI),)
 b2c2-flexcop-objs += flexcop-dma.o
 endif
@@ -13,3 +14,4 @@
 obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o
 
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+EXTRA_CFLAGS += -Idrivers/media/video/
diff --git a/drivers/media/dvb/b2c2/flexcop-common.h b/drivers/media/dvb/b2c2/flexcop-common.h
index 5a6c4fe..8ce0633 100644
--- a/drivers/media/dvb/b2c2/flexcop-common.h
+++ b/drivers/media/dvb/b2c2/flexcop-common.h
@@ -44,6 +44,14 @@
 	u32 size; /* size of each address in bytes */
 };
 
+struct flexcop_i2c_adapter {
+	struct flexcop_device *fc;
+	struct i2c_adapter i2c_adap;
+
+	u8 no_base_addr;
+	flexcop_i2c_port_t port;
+};
+
 /* Control structure for data definitions that are common to
  * the B2C2-based PCI and USB devices.
  */
@@ -72,7 +80,7 @@
 	struct dmx_frontend mem_frontend;
 	int (*fe_sleep) (struct dvb_frontend *);
 
-	struct i2c_adapter i2c_adap;
+	struct flexcop_i2c_adapter fc_i2c_adap[3];
 	struct mutex i2c_mutex;
 	struct module *owner;
 
@@ -87,7 +95,8 @@
 	int               (*write_ibi_reg) (struct flexcop_device *, flexcop_ibi_register, flexcop_ibi_value);
 
 
-	int (*i2c_request) (struct flexcop_device*, flexcop_access_op_t, flexcop_i2c_port_t, u8 chipaddr, u8 addr, u8 *buf, u16 len);
+	int (*i2c_request) (struct flexcop_i2c_adapter*,
+		flexcop_access_op_t, u8 chipaddr, u8 addr, u8 *buf, u16 len);
 	int (*stream_control) (struct flexcop_device*, int);
 
 	int (*get_mac_addr) (struct flexcop_device *fc, int extended);
@@ -128,8 +137,8 @@
  * one. We have it in flexcop-i2c.c, because it is going via the actual
  * I2C-channel of the flexcop.
  */
-int flexcop_i2c_request(struct flexcop_device*, flexcop_access_op_t,
-			flexcop_i2c_port_t, u8 chipaddr, u8 addr, u8 *buf, u16 len);
+int flexcop_i2c_request(struct flexcop_i2c_adapter*, flexcop_access_op_t,
+	u8 chipaddr, u8 addr, u8 *buf, u16 len);
 
 /* from flexcop-sram.c */
 int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest, flexcop_sram_dest_target_t target);
diff --git a/drivers/media/dvb/b2c2/flexcop-dma.c b/drivers/media/dvb/b2c2/flexcop-dma.c
index 6f592bc..a91ed28 100644
--- a/drivers/media/dvb/b2c2/flexcop-dma.c
+++ b/drivers/media/dvb/b2c2/flexcop-dma.c
@@ -112,7 +112,7 @@
 {
 	flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_00c : dma2_01c;
 	flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
-	deb_info("%s\n",__FUNCTION__);
+	deb_info("%s\n",__func__);
 	v.dma_0xc.remap_enable = onoff;
 	fc->write_ibi_reg(fc,r,v);
 	return 0;
@@ -162,7 +162,7 @@
 
 	flexcop_dma_remap(fc,dma_idx,0);
 
-	deb_info("%s\n",__FUNCTION__);
+	deb_info("%s\n",__func__);
 	v.dma_0x4_write.dmatimer = cycles;
 	fc->write_ibi_reg(fc,r,v);
 	return 0;
diff --git a/drivers/media/dvb/b2c2/flexcop-eeprom.c b/drivers/media/dvb/b2c2/flexcop-eeprom.c
index bbcf070..8a8ae8a 100644
--- a/drivers/media/dvb/b2c2/flexcop-eeprom.c
+++ b/drivers/media/dvb/b2c2/flexcop-eeprom.c
@@ -114,15 +114,18 @@
 {
 	int i,ret = 0;
 	u8 chipaddr =  0x50 | ((addr >> 8) & 3);
-	for (i = 0; i < retries; i++)
-		if ((ret = fc->i2c_request(fc,op,FC_I2C_PORT_EEPROM,chipaddr,addr & 0xff,buf,len)) == 0)
+	for (i = 0; i < retries; i++) {
+		ret = fc->i2c_request(&fc->fc_i2c_adap[1], op, chipaddr,
+			addr & 0xff, buf, len);
+		if (ret == 0)
 			break;
+	}
 	return ret;
 }
 
 static int flexcop_eeprom_lrc_read(struct flexcop_device *fc, u16 addr, u8 *buf, u16 len, int retries)
 {
-	int ret = flexcop_eeprom_request(fc,FC_READ,addr,buf,len,retries);
+	int ret = flexcop_eeprom_request(fc, FC_READ, addr, buf, len, retries);
 	if (ret == 0)
 		if (calc_lrc(buf, len - 1) != buf[len - 1])
 			ret = -EINVAL;
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index 0378fd6..7b0ea3b 100644
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -5,6 +5,8 @@
  *
  * see flexcop.c for copyright information.
  */
+#include <media/tuner.h>
+
 #include "flexcop.h"
 
 #include "stv0299.h"
@@ -15,6 +17,15 @@
 #include "mt312.h"
 #include "lgdt330x.h"
 #include "dvb-pll.h"
+#include "tuner-simple.h"
+
+#include "s5h1420.h"
+#include "itd1000.h"
+
+#include "cx24123.h"
+#include "cx24113.h"
+
+#include "isl6421.h"
 
 /* lnb control */
 
@@ -180,13 +191,13 @@
 	buf[2] = 0x84;  /* 0xC4 */
 	buf[3] = 0x08;
 
-	if (params->frequency < 1500000) buf[3] |= 0x10;
+	if (params->frequency < 1500000)
+		buf[3] |= 0x10;
 
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1) {
+	if (i2c_transfer(&fc->fc_i2c_adap[0].i2c_adap, &msg, 1) != 1)
 		return -EIO;
-	}
 	return 0;
 }
 
@@ -241,7 +252,7 @@
 	.mclk = 88000000UL,
 	.invert = 0,
 	.skip_reinit = 0,
-	.lock_output = STV0229_LOCKOUTPUT_LK,
+	.lock_output = STV0299_LOCKOUTPUT_LK,
 	.volt13_op0_op1 = STV0299_VOLT13_OP1,
 	.min_delay_ms = 100,
 	.set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
@@ -337,7 +348,7 @@
 
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1)
+	if (i2c_transfer(&fc->fc_i2c_adap[0].i2c_adap, &msg, 1) != 1)
 		return -EIO;
 	return 0;
 }
@@ -386,10 +397,11 @@
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 0);
 	deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n",fep->frequency, buf[0],buf[1],buf[2],buf[3]);
-	ret = fc->i2c_request(fc, FC_WRITE, FC_I2C_PORT_TUNER, 0x61, buf[0], &buf[1], 3);
+	ret = fc->i2c_request(&fc->fc_i2c_adap[2],
+		FC_WRITE, 0x61, buf[0], &buf[1], 3);
 	deb_tuner("tuner write returned: %d\n",ret);
 
-	return 0;
+	return ret;
 }
 
 static u8 alps_tdee4_stv0297_inittab[] = {
@@ -472,56 +484,159 @@
 //	.pll_set = alps_tdee4_stv0297_pll_set,
 };
 
+
+/* SkyStar2 rev2.7 (a/u) */
+static struct s5h1420_config skystar2_rev2_7_s5h1420_config = {
+	.demod_address = 0x53,
+	.invert = 1,
+	.repeated_start_workaround = 1,
+};
+
+static struct itd1000_config skystar2_rev2_7_itd1000_config = {
+	.i2c_address = 0x61,
+};
+
+/* SkyStar2 rev2.8 */
+static struct cx24123_config skystar2_rev2_8_cx24123_config = {
+	.demod_address = 0x55,
+	.dont_use_pll = 1,
+	.agc_callback = cx24113_agc_callback,
+};
+
+static const struct cx24113_config skystar2_rev2_8_cx24113_config = {
+	.i2c_addr = 0x54,
+	.xtal_khz = 10111,
+};
+
 /* try to figure out the frontend, each card/box can have on of the following list */
 int flexcop_frontend_init(struct flexcop_device *fc)
 {
 	struct dvb_frontend_ops *ops;
+	struct i2c_adapter *i2c = &fc->fc_i2c_adap[0].i2c_adap;
+	struct i2c_adapter *i2c_tuner;
+
+	/* enable no_base_addr - no repeated start when reading */
+	fc->fc_i2c_adap[0].no_base_addr = 1;
+	fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config, i2c);
+	if (fc->fe != NULL) {
+		flexcop_ibi_value r108;
+		i2c_tuner = s5h1420_get_tuner_i2c_adapter(fc->fe);
+		ops = &fc->fe->ops;
+
+		fc->fe_sleep = ops->sleep;
+		ops->sleep   = flexcop_sleep;
+
+		fc->dev_type = FC_SKY_REV27;
+
+		/* enable no_base_addr - no repeated start when reading */
+		fc->fc_i2c_adap[2].no_base_addr = 1;
+		if (dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap, 0x08, 1, 1) == NULL)
+			err("ISL6421 could NOT be attached");
+		else
+			info("ISL6421 successfully attached");
+
+		/* the ITD1000 requires a lower i2c clock - it slows down the stuff for everyone - but is it a problem ? */
+		r108.raw = 0x00000506;
+		fc->write_ibi_reg(fc, tw_sm_c_108, r108);
+		if (i2c_tuner) {
+			if (dvb_attach(itd1000_attach, fc->fe, i2c_tuner, &skystar2_rev2_7_itd1000_config) == NULL)
+				err("ITD1000 could NOT be attached");
+			else
+				info("ITD1000 successfully attached");
+		}
+		goto fe_found;
+	}
+	fc->fc_i2c_adap[0].no_base_addr = 0; /* for the next devices we need it again */
+
+	/* try the sky v2.8 (cx24123, isl6421) */
+	fc->fe = dvb_attach(cx24123_attach,
+		&skystar2_rev2_8_cx24123_config, i2c);
+	if (fc->fe != NULL) {
+		i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe);
+		if (i2c_tuner != NULL) {
+			if (dvb_attach(cx24113_attach, fc->fe,
+					&skystar2_rev2_8_cx24113_config,
+					i2c_tuner) == NULL)
+				err("CX24113 could NOT be attached");
+			else
+				info("CX24113 successfully attached");
+		}
+
+		fc->dev_type = FC_SKY_REV28;
+
+		fc->fc_i2c_adap[2].no_base_addr = 1;
+		if (dvb_attach(isl6421_attach, fc->fe,
+		       &fc->fc_i2c_adap[2].i2c_adap, 0x08, 0, 0) == NULL)
+			err("ISL6421 could NOT be attached");
+		else
+			info("ISL6421 successfully attached");
+
+		/* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an
+		 * IR-receiver (PIC16F818) - but the card has no input for
+		 * that ??? */
+
+		goto fe_found;
+    }
 
 	/* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */
-	if ((fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) {
+	fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c);
+	if (fc->fe != NULL) {
 		ops = &fc->fe->ops;
 
 		ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params;
 
 		ops->set_voltage = flexcop_set_voltage;
 
-		fc->fe_sleep             = ops->sleep;
-		ops->sleep               = flexcop_sleep;
+		fc->fe_sleep = ops->sleep;
+		ops->sleep = flexcop_sleep;
 
-		fc->dev_type          = FC_SKY;
-		info("found the stv0299 at i2c address: 0x%02x",samsung_tbmu24112_config.demod_address);
-	} else
+		fc->dev_type = FC_SKY;
+		goto fe_found;
+	}
+
 	/* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */
-	if ((fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, &fc->i2c_adap)) != NULL ) {
-		fc->dev_type          = FC_AIR_DVB;
+	fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c);
+	if (fc->fe != NULL) {
+		fc->dev_type = FC_AIR_DVB;
 		fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
-		info("found the mt352 at i2c address: 0x%02x",samsung_tdtc9251dh0_config.demod_address);
-	} else
+		goto fe_found;
+	}
+
 	/* try the air atsc 2nd generation (nxt2002) */
-	if ((fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
-		fc->dev_type          = FC_AIR_ATSC2;
+	fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c);
+	if (fc->fe != NULL) {
+		fc->dev_type = FC_AIR_ATSC2;
 		dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, DVB_PLL_SAMSUNG_TBMV);
-		info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address);
-	} else
-	/* try the air atsc 3nd generation (lgdt3303) */
-	if ((fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) {
-		fc->dev_type          = FC_AIR_ATSC3;
-		dvb_attach(dvb_pll_attach, fc->fe, 0x61, &fc->i2c_adap, DVB_PLL_LG_TDVS_H06XF);
-		info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address);
-	} else
+		goto fe_found;
+	}
+
+	fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c);
+	if (fc->fe != NULL) {
+		fc->dev_type = FC_AIR_ATSC3;
+		dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61,
+				TUNER_LG_TDVS_H06XF);
+		goto fe_found;
+	}
+
 	/* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
-	if ((fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, &fc->i2c_adap)) != NULL) {
-		fc->dev_type          = FC_AIR_ATSC1;
-		info("found the bcm3510 at i2c address: 0x%02x",air2pc_atsc_first_gen_config.demod_address);
-	} else
+	fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c);
+	if (fc->fe != NULL) {
+		fc->dev_type = FC_AIR_ATSC1;
+		goto fe_found;
+	}
+
 	/* try the cable dvb (stv0297) */
-	if ((fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, &fc->i2c_adap)) != NULL) {
-		fc->dev_type                        = FC_CABLE;
+	fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c);
+	if (fc->fe != NULL) {
+		fc->dev_type = FC_CABLE;
 		fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
-		info("found the stv0297 at i2c address: 0x%02x",alps_tdee4_stv0297_config.demod_address);
-	} else
+		goto fe_found;
+	}
+
 	/* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
-	if ((fc->fe = dvb_attach(vp310_mt312_attach, &skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) {
+	fc->fe = dvb_attach(vp310_mt312_attach,
+		&skystar23_samsung_tbdu18132_config, i2c);
+	if (fc->fe != NULL) {
 		ops = &fc->fe->ops;
 
 		ops->tuner_ops.set_params = skystar23_samsung_tbdu18132_tuner_set_params;
@@ -535,19 +650,21 @@
 		ops->sleep                  = flexcop_sleep;
 
 		fc->dev_type                = FC_SKY_OLD;
-		info("found the vp310 (aka mt312) at i2c address: 0x%02x",skystar23_samsung_tbdu18132_config.demod_address);
+		goto fe_found;
 	}
 
-	if (fc->fe == NULL) {
-		err("no frontend driver found for this B2C2/FlexCop adapter");
-		return -ENODEV;
-	} else {
-		if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
-			err("frontend registration failed!");
-			dvb_frontend_detach(fc->fe);
-			fc->fe = NULL;
-			return -EINVAL;
-		}
+	err("no frontend driver found for this B2C2/FlexCop adapter");
+	return -ENODEV;
+
+fe_found:
+	info("found '%s' .", fc->fe->ops.info.name);
+	if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
+		err("frontend registration failed!");
+		ops = &fc->fe->ops;
+		if (ops->release != NULL)
+			ops->release(fc->fe);
+		fc->fe = NULL;
+		return -EINVAL;
 	}
 	fc->init_state |= FC_STATE_FE_INIT;
 	return 0;
diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c
index 6bf858a..55973ea 100644
--- a/drivers/media/dvb/b2c2/flexcop-i2c.c
+++ b/drivers/media/dvb/b2c2/flexcop-i2c.c
@@ -9,6 +9,8 @@
 
 #define FC_MAX_I2C_RETRIES 100000
 
+/* #define DUMP_I2C_MESSAGES */
+
 static int flexcop_i2c_operation(struct flexcop_device *fc, flexcop_ibi_value *r100)
 {
 	int i;
@@ -38,30 +40,25 @@
 	return -EREMOTEIO;
 }
 
-static int flexcop_i2c_read4(struct flexcop_device *fc, flexcop_ibi_value r100, u8 *buf)
+static int flexcop_i2c_read4(struct flexcop_i2c_adapter *i2c,
+	flexcop_ibi_value r100, u8 *buf)
 {
 	flexcop_ibi_value r104;
 	int len = r100.tw_sm_c_100.total_bytes, /* remember total_bytes is buflen-1 */
 		ret;
 
-	if ((ret = flexcop_i2c_operation(fc,&r100)) != 0) {
-		/* The Cablestar needs a different kind of i2c-transfer (does not
-		 * support "Repeat Start"):
-		 * wait for the ACK failure,
-		 * and do a subsequent read with the Bit 30 enabled
-		 */
-		r100.tw_sm_c_100.no_base_addr_ack_error = 1;
-		if ((ret = flexcop_i2c_operation(fc,&r100)) != 0) {
-			deb_i2c("no_base_addr read failed. %d\n",ret);
-			return ret;
-		}
+	r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr;
+	ret = flexcop_i2c_operation(i2c->fc, &r100);
+	if (ret != 0) {
+		deb_i2c("read failed. %d\n", ret);
+		return ret;
 	}
 
 	buf[0] = r100.tw_sm_c_100.data1_reg;
 
 	if (len > 0) {
-		r104 = fc->read_ibi_reg(fc,tw_sm_c_104);
-		deb_i2c("read: r100: %08x, r104: %08x\n",r100.raw,r104.raw);
+		r104 = i2c->fc->read_ibi_reg(i2c->fc, tw_sm_c_104);
+		deb_i2c("read: r100: %08x, r104: %08x\n", r100.raw, r104.raw);
 
 		/* there is at least one more byte, otherwise we wouldn't be here */
 		buf[1] = r104.tw_sm_c_104.data2_reg;
@@ -85,17 +82,22 @@
 	r104.tw_sm_c_104.data3_reg = len > 1 ? buf[2] : 0;
 	r104.tw_sm_c_104.data4_reg = len > 2 ? buf[3] : 0;
 
-	deb_i2c("write: r100: %08x, r104: %08x\n",r100.raw,r104.raw);
+	deb_i2c("write: r100: %08x, r104: %08x\n", r100.raw, r104.raw);
 
 	/* write the additional i2c data before doing the actual i2c operation */
-	fc->write_ibi_reg(fc,tw_sm_c_104,r104);
-	return flexcop_i2c_operation(fc,&r100);
+	fc->write_ibi_reg(fc, tw_sm_c_104, r104);
+	return flexcop_i2c_operation(fc, &r100);
 }
 
-int flexcop_i2c_request(struct flexcop_device *fc, flexcop_access_op_t op,
-		flexcop_i2c_port_t port, u8 chipaddr, u8 addr, u8 *buf, u16 len)
+int flexcop_i2c_request(struct flexcop_i2c_adapter *i2c,
+	flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len)
 {
 	int ret;
+
+#ifdef DUMP_I2C_MESSAGES
+	int i;
+#endif
+
 	u16 bytes_to_transfer;
 	flexcop_ibi_value r100;
 
@@ -103,7 +105,25 @@
 	r100.raw = 0;
 	r100.tw_sm_c_100.chipaddr = chipaddr;
 	r100.tw_sm_c_100.twoWS_rw = op;
-	r100.tw_sm_c_100.twoWS_port_reg = port;
+	r100.tw_sm_c_100.twoWS_port_reg = i2c->port;
+
+#ifdef DUMP_I2C_MESSAGES
+	printk(KERN_DEBUG "%d ", i2c->port);
+	if (op == FC_READ)
+		printk("rd(");
+	else
+		printk("wr(");
+
+	printk("%02x): %02x ", chipaddr, addr);
+#endif
+
+	/* in that case addr is the only value ->
+	 * we write it twice as baseaddr and val0
+	 * BBTI is doing it like that for ISL6421 at least */
+	if (i2c->no_base_addr && len == 0 && op == FC_WRITE) {
+		buf = &addr;
+		len = 1;
+	}
 
 	while (len != 0) {
 		bytes_to_transfer = len > 4 ? 4 : len;
@@ -112,9 +132,14 @@
 		r100.tw_sm_c_100.baseaddr = addr;
 
 		if (op == FC_READ)
-			ret = flexcop_i2c_read4(fc, r100, buf);
+			ret = flexcop_i2c_read4(i2c, r100, buf);
 		else
-			ret = flexcop_i2c_write4(fc,r100, buf);
+			ret = flexcop_i2c_write4(i2c->fc, r100, buf);
+
+#ifdef DUMP_I2C_MESSAGES
+		for (i = 0; i < bytes_to_transfer; i++)
+			printk("%02x ", buf[i]);
+#endif
 
 		if (ret < 0)
 			return ret;
@@ -122,7 +147,11 @@
 		buf  += bytes_to_transfer;
 		addr += bytes_to_transfer;
 		len  -= bytes_to_transfer;
-	};
+	}
+
+#ifdef DUMP_I2C_MESSAGES
+	printk("\n");
+#endif
 
 	return 0;
 }
@@ -132,7 +161,7 @@
 /* master xfer callback for demodulator */
 static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
 {
-	struct flexcop_device *fc = i2c_get_adapdata(i2c_adap);
+	struct flexcop_i2c_adapter *i2c = i2c_get_adapdata(i2c_adap);
 	int i, ret = 0;
 
 	/* Some drivers use 1 byte or 0 byte reads as probes, which this
@@ -142,34 +171,29 @@
 	if (num == 1 && msgs[0].flags == I2C_M_RD && msgs[0].len <= 1)
 		return 1;
 
-	if (mutex_lock_interruptible(&fc->i2c_mutex))
+	if (mutex_lock_interruptible(&i2c->fc->i2c_mutex))
 		return -ERESTARTSYS;
 
-	/* reading */
-	if (num == 2 &&
-		msgs[0].flags == 0 &&
-		msgs[1].flags == I2C_M_RD &&
-		msgs[0].buf != NULL &&
-		msgs[1].buf != NULL) {
-
-		ret = fc->i2c_request(fc, FC_READ, FC_I2C_PORT_DEMOD, msgs[0].addr, msgs[0].buf[0], msgs[1].buf, msgs[1].len);
-
-	} else for (i = 0; i < num; i++) { /* writing command */
-		if (msgs[i].flags != 0 || msgs[i].buf == NULL || msgs[i].len < 2) {
-			ret = -EINVAL;
+	for (i = 0; i < num; i++) {
+		/* reading */
+		if (i+1 < num && (msgs[i+1].flags == I2C_M_RD)) {
+			ret = i2c->fc->i2c_request(i2c, FC_READ, msgs[i].addr,
+				msgs[i].buf[0], msgs[i+1].buf, msgs[i+1].len);
+			i++; /* skip the following message */
+		} else /* writing */
+			ret = i2c->fc->i2c_request(i2c, FC_WRITE, msgs[i].addr,
+				msgs[i].buf[0], &msgs[i].buf[1],
+				msgs[i].len - 1);
+		if (ret < 0) {
+			err("i2c master_xfer failed");
 			break;
 		}
-
-		ret = fc->i2c_request(fc, FC_WRITE, FC_I2C_PORT_DEMOD, msgs[i].addr, msgs[i].buf[0], &msgs[i].buf[1], msgs[i].len - 1);
 	}
 
-	if (ret < 0)
-		err("i2c master_xfer failed");
-	else
+	mutex_unlock(&i2c->fc->i2c_mutex);
+
+	if (ret == 0)
 		ret = num;
-
-	mutex_unlock(&fc->i2c_mutex);
-
 	return ret;
 }
 
@@ -189,28 +213,68 @@
 
 	mutex_init(&fc->i2c_mutex);
 
-	memset(&fc->i2c_adap, 0, sizeof(struct i2c_adapter));
-	strncpy(fc->i2c_adap.name, "B2C2 FlexCop device",
-		sizeof(fc->i2c_adap.name));
+	fc->fc_i2c_adap[0].fc = fc;
+	fc->fc_i2c_adap[1].fc = fc;
+	fc->fc_i2c_adap[2].fc = fc;
 
-	i2c_set_adapdata(&fc->i2c_adap,fc);
+	fc->fc_i2c_adap[0].port = FC_I2C_PORT_DEMOD;
+	fc->fc_i2c_adap[1].port = FC_I2C_PORT_EEPROM;
+	fc->fc_i2c_adap[2].port = FC_I2C_PORT_TUNER;
 
-	fc->i2c_adap.class	    = I2C_CLASS_TV_DIGITAL;
-	fc->i2c_adap.algo       = &flexcop_algo;
-	fc->i2c_adap.algo_data  = NULL;
-	fc->i2c_adap.dev.parent	= fc->dev;
+	strncpy(fc->fc_i2c_adap[0].i2c_adap.name,
+		"B2C2 FlexCop I2C to demod", I2C_NAME_SIZE);
+	strncpy(fc->fc_i2c_adap[1].i2c_adap.name,
+		"B2C2 FlexCop I2C to eeprom", I2C_NAME_SIZE);
+	strncpy(fc->fc_i2c_adap[2].i2c_adap.name,
+		"B2C2 FlexCop I2C to tuner", I2C_NAME_SIZE);
 
-	if ((ret = i2c_add_adapter(&fc->i2c_adap)) < 0)
+	i2c_set_adapdata(&fc->fc_i2c_adap[0].i2c_adap, &fc->fc_i2c_adap[0]);
+	i2c_set_adapdata(&fc->fc_i2c_adap[1].i2c_adap, &fc->fc_i2c_adap[1]);
+	i2c_set_adapdata(&fc->fc_i2c_adap[2].i2c_adap, &fc->fc_i2c_adap[2]);
+
+	fc->fc_i2c_adap[0].i2c_adap.class =
+		fc->fc_i2c_adap[1].i2c_adap.class =
+		fc->fc_i2c_adap[2].i2c_adap.class = I2C_CLASS_TV_DIGITAL;
+	fc->fc_i2c_adap[0].i2c_adap.algo =
+		fc->fc_i2c_adap[1].i2c_adap.algo =
+		fc->fc_i2c_adap[2].i2c_adap.algo = &flexcop_algo;
+	fc->fc_i2c_adap[0].i2c_adap.algo_data =
+		fc->fc_i2c_adap[1].i2c_adap.algo_data =
+		fc->fc_i2c_adap[2].i2c_adap.algo_data = NULL;
+	fc->fc_i2c_adap[0].i2c_adap.dev.parent =
+		fc->fc_i2c_adap[1].i2c_adap.dev.parent =
+		fc->fc_i2c_adap[2].i2c_adap.dev.parent = fc->dev;
+
+	ret = i2c_add_adapter(&fc->fc_i2c_adap[0].i2c_adap);
+	if (ret < 0)
 		return ret;
 
+	ret = i2c_add_adapter(&fc->fc_i2c_adap[1].i2c_adap);
+	if (ret < 0)
+		goto adap_1_failed;
+
+	ret = i2c_add_adapter(&fc->fc_i2c_adap[2].i2c_adap);
+	if (ret < 0)
+		goto adap_2_failed;
+
 	fc->init_state |= FC_STATE_I2C_INIT;
 	return 0;
+
+adap_2_failed:
+	i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap);
+adap_1_failed:
+	i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap);
+
+	return ret;
 }
 
 void flexcop_i2c_exit(struct flexcop_device *fc)
 {
-	if (fc->init_state & FC_STATE_I2C_INIT)
-		i2c_del_adapter(&fc->i2c_adap);
+	if (fc->init_state & FC_STATE_I2C_INIT) {
+		i2c_del_adapter(&fc->fc_i2c_adap[2].i2c_adap);
+		i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap);
+		i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap);
+	}
 
 	fc->init_state &= ~FC_STATE_I2C_INIT;
 }
diff --git a/drivers/media/dvb/b2c2/flexcop-misc.c b/drivers/media/dvb/b2c2/flexcop-misc.c
index 167583b..93d20e5 100644
--- a/drivers/media/dvb/b2c2/flexcop-misc.c
+++ b/drivers/media/dvb/b2c2/flexcop-misc.c
@@ -52,6 +52,8 @@
 	"Sky2PC/SkyStar 2 DVB-S (old version)",
 	"Cable2PC/CableStar 2 DVB-C",
 	"Air2PC/AirStar 2 ATSC 3rd generation (HD5000)",
+	"Sky2PC/SkyStar 2 DVB-S rev 2.7a/u",
+	"Sky2PC/SkyStar 2 DVB-S rev 2.8",
 };
 
 static const char *flexcop_bus_names[] = {
diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c
index 01af4d2..5b30dfc 100644
--- a/drivers/media/dvb/b2c2/flexcop-pci.c
+++ b/drivers/media/dvb/b2c2/flexcop-pci.c
@@ -32,7 +32,7 @@
 #define deb_irq(args...)   dprintk(0x08,args)
 #define deb_chk(args...)   dprintk(0x10,args)
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debug level (1=info,2=regs,4=TS,8=irqdma (|-able))." DEBSTATUS);
 
diff --git a/drivers/media/dvb/b2c2/flexcop-reg.h b/drivers/media/dvb/b2c2/flexcop-reg.h
index 491f9bd..7599fcc 100644
--- a/drivers/media/dvb/b2c2/flexcop-reg.h
+++ b/drivers/media/dvb/b2c2/flexcop-reg.h
@@ -25,6 +25,8 @@
 	FC_SKY_OLD,
 	FC_CABLE,
 	FC_AIR_ATSC3,
+	FC_SKY_REV27,
+	FC_SKY_REV28,
 } flexcop_device_type_t;
 
 typedef enum {
diff --git a/drivers/media/dvb/b2c2/flexcop-sram.c b/drivers/media/dvb/b2c2/flexcop-sram.c
index 01570ec..cda6952 100644
--- a/drivers/media/dvb/b2c2/flexcop-sram.c
+++ b/drivers/media/dvb/b2c2/flexcop-sram.c
@@ -90,7 +90,7 @@
 		};
 
 		if (retries == 0)
-			printk("%s: SRAM timeout\n", __FUNCTION__);
+			printk("%s: SRAM timeout\n", __func__);
 
 		write_reg_dw(adapter, 0x700, command);
 
@@ -115,7 +115,7 @@
 		};
 
 		if (retries == 0)
-			printk("%s: SRAM timeout\n", __FUNCTION__);
+			printk("%s: SRAM timeout\n", __func__);
 
 		write_reg_dw(adapter, 0x700, command);
 
@@ -127,7 +127,7 @@
 		};
 
 		if (retries == 0)
-			printk("%s: SRAM timeout\n", __FUNCTION__);
+			printk("%s: SRAM timeout\n", __func__);
 
 		value = read_reg_dw(adapter, 0x700) >> 0x10;
 
@@ -240,13 +240,13 @@
 
 		adapter->dw_sram_type = tmp & 0x30000;
 
-		ddprintk("%s: dw_sram_type = %x\n", __FUNCTION__, adapter->dw_sram_type);
+		ddprintk("%s: dw_sram_type = %x\n", __func__, adapter->dw_sram_type);
 
 	} else {
 
 		adapter->dw_sram_type = 0x10000;
 
-		ddprintk("%s: dw_sram_type = %x\n", __FUNCTION__, adapter->dw_sram_type);
+		ddprintk("%s: dw_sram_type = %x\n", __func__, adapter->dw_sram_type);
 	}
 
 	/* return value is never used? */
@@ -257,7 +257,7 @@
 {
 	u8 tmp1, tmp2;
 
-	dprintk("%s: mask = %x, addr = %x\n", __FUNCTION__, mask, addr);
+	dprintk("%s: mask = %x, addr = %x\n", __func__, mask, addr);
 
 	sram_set_size(adapter, mask);
 	sram_init(adapter);
@@ -275,7 +275,7 @@
 	sram_read(adapter, addr, &tmp2, 1);
 	sram_read(adapter, addr, &tmp2, 1);
 
-	dprintk("%s: wrote 0xa5, read 0x%2x\n", __FUNCTION__, tmp2);
+	dprintk("%s: wrote 0xa5, read 0x%2x\n", __func__, tmp2);
 
 	if (tmp2 != 0xa5)
 		return 0;
@@ -293,7 +293,7 @@
 	sram_read(adapter, addr, &tmp2, 1);
 	sram_read(adapter, addr, &tmp2, 1);
 
-	dprintk("%s: wrote 0x5a, read 0x%2x\n", __FUNCTION__, tmp2);
+	dprintk("%s: wrote 0x5a, read 0x%2x\n", __func__, tmp2);
 
 	if (tmp2 != 0x5a)
 		return 0;
@@ -340,7 +340,7 @@
 
 	tmp3 = read_reg_dw(adapter, 0x71c);
 
-	dprintk("%s: tmp3 = %x\n", __FUNCTION__, tmp3);
+	dprintk("%s: tmp3 = %x\n", __func__, tmp3);
 
 	write_reg_dw(adapter, 0x71c, tmp2);
 
@@ -351,7 +351,7 @@
 		sram_init(adapter);
 		write_reg_dw(adapter, 0x208, tmp);
 
-		dprintk("%s: sram size = 32K\n", __FUNCTION__);
+		dprintk("%s: sram size = 32K\n", __func__);
 
 		return 32;
 	}
@@ -361,7 +361,7 @@
 		sram_init(adapter);
 		write_reg_dw(adapter, 0x208, tmp);
 
-		dprintk("%s: sram size = 128K\n", __FUNCTION__);
+		dprintk("%s: sram size = 128K\n", __func__);
 
 		return 128;
 	}
@@ -371,7 +371,7 @@
 		sram_init(adapter);
 		write_reg_dw(adapter, 0x208, tmp);
 
-		dprintk("%s: sram size = 64K\n", __FUNCTION__);
+		dprintk("%s: sram size = 64K\n", __func__);
 
 		return 64;
 	}
@@ -381,7 +381,7 @@
 		sram_init(adapter);
 		write_reg_dw(adapter, 0x208, tmp);
 
-		dprintk("%s: sram size = 32K\n", __FUNCTION__);
+		dprintk("%s: sram size = 32K\n", __func__);
 
 		return 32;
 	}
@@ -390,7 +390,7 @@
 	sram_init(adapter);
 	write_reg_dw(adapter, 0x208, tmp);
 
-	dprintk("%s: SRAM detection failed. Set to 32K \n", __FUNCTION__);
+	dprintk("%s: SRAM detection failed. Set to 32K \n", __func__);
 
 	return 0;
 }
diff --git a/drivers/media/dvb/b2c2/flexcop-usb.c b/drivers/media/dvb/b2c2/flexcop-usb.c
index 87fb75f..449fb5c 100644
--- a/drivers/media/dvb/b2c2/flexcop-usb.c
+++ b/drivers/media/dvb/b2c2/flexcop-usb.c
@@ -211,10 +211,11 @@
 #endif
 
 /* usb i2c stuff */
-static int flexcop_usb_i2c_req(struct flexcop_usb *fc_usb,
+static int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c,
 		flexcop_usb_request_t req, flexcop_usb_i2c_function_t func,
-		flexcop_i2c_port_t port, u8 chipaddr, u8 addr, u8 *buf, u8 buflen)
+		u8 chipaddr, u8 addr, u8 *buf, u8 buflen)
 {
+	struct flexcop_usb *fc_usb = i2c->fc->bus_specific;
 	u16 wValue, wIndex;
 	int nWaitTime,pipe,len;
 //	u8 dwRequestType;
@@ -242,7 +243,7 @@
 			deb_info("unsupported function for i2c_req %x\n",func);
 			return -EINVAL;
 	}
-	wValue = (func << 8 ) | (port << 4);
+	wValue = (func << 8) | (i2c->port << 4);
 	wIndex = (chipaddr << 8 ) | addr;
 
 	deb_i2c("i2c %2d: %02x %02x %02x %02x %02x %02x\n",func,request_type,req,
@@ -274,13 +275,15 @@
 	return flexcop_usb_readwrite_dw(fc,reg, &val.raw, 0);
 }
 
-static int flexcop_usb_i2c_request(struct flexcop_device *fc, flexcop_access_op_t op,
-		flexcop_i2c_port_t port, u8 chipaddr, u8 addr, u8 *buf, u16 len)
+static int flexcop_usb_i2c_request(struct flexcop_i2c_adapter *i2c,
+	flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len)
 {
 	if (op == FC_READ)
-		return flexcop_usb_i2c_req(fc->bus_specific,B2C2_USB_I2C_REQUEST,USB_FUNC_I2C_READ,port,chipaddr,addr,buf,len);
+		return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST,
+			USB_FUNC_I2C_READ, chipaddr, addr, buf, len);
 	else
-		return flexcop_usb_i2c_req(fc->bus_specific,B2C2_USB_I2C_REQUEST,USB_FUNC_I2C_WRITE,port,chipaddr,addr,buf,len);
+		return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST,
+			USB_FUNC_I2C_WRITE, chipaddr, addr, buf, len);
 }
 
 static void flexcop_usb_process_frame(struct flexcop_usb *fc_usb, u8 *buffer, int buffer_length)
diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c
index 2ddafd0..5f79c8d 100644
--- a/drivers/media/dvb/b2c2/flexcop.c
+++ b/drivers/media/dvb/b2c2/flexcop.c
@@ -49,6 +49,8 @@
 MODULE_PARM_DESC(debug, "set debug level (1=info,2=tuner,4=i2c,8=ts,16=sram,32=reg (|-able))." DEBSTATUS);
 #undef DEBSTATUS
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 /* global zero for ibi values */
 flexcop_ibi_value ibi_zero;
 
@@ -66,8 +68,10 @@
 
 static int flexcop_dvb_init(struct flexcop_device *fc)
 {
-	int ret;
-	if ((ret = dvb_register_adapter(&fc->dvb_adapter,"FlexCop Digital TV device",fc->owner,fc->dev)) < 0) {
+	int ret = dvb_register_adapter(&fc->dvb_adapter,
+				       "FlexCop Digital TV device", fc->owner,
+				       fc->dev, adapter_nr);
+	if (ret < 0) {
 		err("error registering DVB adapter");
 		return ret;
 	}
@@ -257,6 +261,12 @@
 	if ((ret = flexcop_dvb_init(fc)))
 		goto error;
 
+	/* i2c has to be done before doing EEProm stuff -
+	 * because the EEProm is accessed via i2c */
+	ret = flexcop_i2c_init(fc);
+	if (ret)
+		goto error;
+
 	/* do the MAC address reading after initializing the dvb_adapter */
 	if (fc->get_mac_addr(fc, 0) == 0) {
 		u8 *b = fc->dvb_adapter.proposed_mac;
@@ -266,10 +276,6 @@
 	} else
 		warn("reading of MAC address failed.\n");
 
-
-	if ((ret = flexcop_i2c_init(fc)))
-		goto error;
-
 	if ((ret = flexcop_frontend_init(fc)))
 		goto error;
 
diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig
index ea66617..902c762 100644
--- a/drivers/media/dvb/bt8xx/Kconfig
+++ b/drivers/media/dvb/bt8xx/Kconfig
@@ -7,8 +7,8 @@
 	select DVB_CX24110 if !DVB_FE_CUSTOMISE
 	select DVB_OR51211 if !DVB_FE_CUSTOMISE
 	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
-	select DVB_PLL if !DVB_FE_CUSTOMISE
 	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+	select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
 	select FW_LOADER
 	help
 	  Support for PCI cards based on the Bt8xx PCI bridge. Examples are
diff --git a/drivers/media/dvb/bt8xx/Makefile b/drivers/media/dvb/bt8xx/Makefile
index 84cf705..9d3e68b 100644
--- a/drivers/media/dvb/bt8xx/Makefile
+++ b/drivers/media/dvb/bt8xx/Makefile
@@ -1,3 +1,6 @@
 obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o
 
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/video/bt8xx -Idrivers/media/dvb/frontends
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+EXTRA_CFLAGS += -Idrivers/media/video/bt8xx
+EXTRA_CFLAGS += -Idrivers/media/video
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index 307ff35..75711bd 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -1290,7 +1290,7 @@
 {
 	int retval;
 	u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb };
-	//dprintk("%s: Getting Signal strength and other parameters\n", __FUNCTION__);
+	//dprintk("%s: Getting Signal strength and other parameters\n", __func__);
 	if ((state->diseq_flags & ATTEMPT_TUNE) == 0) {
 		state->decode_lock = state->decode_strength = state->decode_snr = 0;
 		return 0;
diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c
index 50bc32a..0258451 100644
--- a/drivers/media/dvb/bt8xx/dst_ca.c
+++ b/drivers/media/dvb/bt8xx/dst_ca.c
@@ -36,13 +36,13 @@
 #define dprintk(x, y, z, format, arg...) do {						\
 	if (z) {									\
 		if	((x > DST_CA_ERROR) && (x > y))					\
-			printk(KERN_ERR "%s: " format "\n", __FUNCTION__ , ##arg);	\
+			printk(KERN_ERR "%s: " format "\n", __func__ , ##arg);	\
 		else if	((x > DST_CA_NOTICE) && (x > y))				\
-			printk(KERN_NOTICE "%s: " format "\n", __FUNCTION__ , ##arg);	\
+			printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg);	\
 		else if ((x > DST_CA_INFO) && (x > y))					\
-			printk(KERN_INFO "%s: " format "\n", __FUNCTION__ , ##arg);	\
+			printk(KERN_INFO "%s: " format "\n", __func__ , ##arg);	\
 		else if ((x > DST_CA_DEBUG) && (x > y))					\
-			printk(KERN_DEBUG "%s: " format "\n", __FUNCTION__ , ##arg);	\
+			printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg);	\
 	} else {									\
 		if (x > y)								\
 			printk(format, ## arg);						\
@@ -162,7 +162,7 @@
 	dprintk(verbose, DST_CA_INFO, 1, " ================================ CI Module Application Info ======================================");
 	dprintk(verbose, DST_CA_INFO, 1, " Application Type=[%d], Application Vendor=[%d], Vendor Code=[%d]\n%s: Application info=[%s]",
 		state->messages[7], (state->messages[8] << 8) | state->messages[9],
-		(state->messages[10] << 8) | state->messages[11], __FUNCTION__, (char *)(&state->messages[12]));
+		(state->messages[10] << 8) | state->messages[11], __func__, (char *)(&state->messages[12]));
 	dprintk(verbose, DST_CA_INFO, 1, " ==================================================================================================");
 
 	// Transform dst message to correct application_info message
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
index dedd30a..6afbfbb 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -40,10 +40,12 @@
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 #define dprintk( args... ) \
-	do \
+	do { \
 		if (debug) printk(KERN_DEBUG args); \
-	while (0)
+	} while (0)
 
 #define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
 
@@ -609,8 +611,9 @@
 		lgdt330x_reset(card);
 		card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, card->i2c_adapter);
 		if (card->fe != NULL) {
-			dvb_attach(dvb_pll_attach, card->fe, 0x61,
-				   card->i2c_adapter, DVB_PLL_LG_TDVS_H06XF);
+			dvb_attach(simple_tuner_attach, card->fe,
+				   card->i2c_adapter, 0x61,
+				   TUNER_LG_TDVS_H06XF);
 			dprintk ("dvb_bt8xx: lgdt330x detected\n");
 		}
 		break;
@@ -670,7 +673,7 @@
 		state->dst_ca = NULL;
 		/*	DST is not a frontend, attaching the ASIC	*/
 		if (dvb_attach(dst_attach, state, &card->dvb_adapter) == NULL) {
-			printk("%s: Could not find a Twinhan DST.\n", __FUNCTION__);
+			printk("%s: Could not find a Twinhan DST.\n", __func__);
 			break;
 		}
 		/*	Attach other DST peripherals if any		*/
@@ -692,8 +695,9 @@
 	case BTTV_BOARD_PC_HDTV:
 		card->fe = dvb_attach(or51211_attach, &or51211_config, card->i2c_adapter);
 		if (card->fe != NULL)
-			dvb_attach(dvb_pll_attach, card->fe, 0x61,
-				   card->i2c_adapter, DVB_PLL_FCV1236D);
+			dvb_attach(simple_tuner_attach, card->fe,
+				   card->i2c_adapter, 0x61,
+				   TUNER_PHILIPS_FCV1236D);
 		break;
 	}
 
@@ -715,7 +719,10 @@
 {
 	int result;
 
-	if ((result = dvb_register_adapter(&card->dvb_adapter, card->card_name, THIS_MODULE, &card->bt->dev->dev)) < 0) {
+	result = dvb_register_adapter(&card->dvb_adapter, card->card_name,
+				      THIS_MODULE, &card->bt->dev->dev,
+				      adapter_nr);
+	if (result < 0) {
 		printk("dvb_bt8xx: dvb_register_adapter failed (errno = %d)\n", result);
 		return result;
 	}
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.h b/drivers/media/dvb/bt8xx/dvb-bt8xx.h
index 436880e..4499ed2 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.h
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.h
@@ -38,7 +38,7 @@
 #include "or51211.h"
 #include "lgdt330x.h"
 #include "zl10353.h"
-#include "dvb-pll.h"
+#include "tuner-simple.h"
 
 struct dvb_bt8xx_card {
 	struct mutex lock;
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
index db08b0a..f5010e8 100644
--- a/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ b/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -58,11 +58,13 @@
 module_param_named(debug, debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 #define dprintk(level, args...)						\
 do {									\
 	if ((debug & level)) {						\
 		printk("%s: %s(): ", KBUILD_MODNAME,			\
-		       __FUNCTION__);					\
+		       __func__);					\
 		printk(args); }						\
 } while (0)
 
@@ -938,7 +940,10 @@
 		return -ENOMEM;
 	}
 
-	if ((err = dvb_register_adapter(&cinergyt2->adapter, DRIVER_NAME, THIS_MODULE, &cinergyt2->udev->dev)) < 0) {
+	err = dvb_register_adapter(&cinergyt2->adapter, DRIVER_NAME,
+				   THIS_MODULE, &cinergyt2->udev->dev,
+				   adapter_nr);
+	if (err < 0) {
 		kfree(cinergyt2);
 		return err;
 	}
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index 0c1d87c..b0d347d 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -80,6 +80,8 @@
 #define	TS_PAYLOAD_ONLY 2   /* in case TS_PACKET is set, only send the TS
 			       payload (<=184 bytes per packet) to callback */
 #define TS_DECODER      4   /* send stream to built-in decoder (if present) */
+#define TS_DEMUX        8   /* in case TS_PACKET is set, send the TS to
+			       the demux device, not to the dvr device */
 
 /* PES type for filters which write to built-in decoder */
 /* these should be kept identical to the types in dmx.h */
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index f94bc31..df5bef6 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -126,7 +126,7 @@
 	struct dmxdev *dmxdev = dvbdev->priv;
 	struct dmx_frontend *front;
 
-	dprintk("function : %s\n", __FUNCTION__);
+	dprintk("function : %s\n", __func__);
 
 	if (mutex_lock_interruptible(&dmxdev->mutex))
 		return -ERESTARTSYS;
@@ -259,6 +259,39 @@
 	return ret;
 }
 
+static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev,
+				      unsigned long size)
+{
+	struct dvb_ringbuffer *buf = &dmxdev->dvr_buffer;
+	void *newmem;
+	void *oldmem;
+
+	dprintk("function : %s\n", __func__);
+
+	if (buf->size == size)
+		return 0;
+	if (!size)
+		return -EINVAL;
+
+	newmem = vmalloc(size);
+	if (!newmem)
+		return -ENOMEM;
+
+	oldmem = buf->data;
+
+	spin_lock_irq(&dmxdev->lock);
+	buf->data = newmem;
+	buf->size = size;
+
+	/* reset and not flush in case the buffer shrinks */
+	dvb_ringbuffer_reset(buf);
+	spin_unlock_irq(&dmxdev->lock);
+
+	vfree(oldmem);
+
+	return 0;
+}
+
 static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter
 					       *dmxdevfilter, int state)
 {
@@ -271,28 +304,32 @@
 				      unsigned long size)
 {
 	struct dvb_ringbuffer *buf = &dmxdevfilter->buffer;
-	void *mem;
+	void *newmem;
+	void *oldmem;
 
 	if (buf->size == size)
 		return 0;
+	if (!size)
+		return -EINVAL;
 	if (dmxdevfilter->state >= DMXDEV_STATE_GO)
 		return -EBUSY;
-	spin_lock_irq(&dmxdevfilter->dev->lock);
-	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);
-		if (!mem)
-			return -ENOMEM;
-		spin_lock_irq(&dmxdevfilter->dev->lock);
-		buf->data = mem;
-		spin_unlock_irq(&dmxdevfilter->dev->lock);
-	}
+	newmem = vmalloc(size);
+	if (!newmem)
+		return -ENOMEM;
+
+	oldmem = buf->data;
+
+	spin_lock_irq(&dmxdevfilter->dev->lock);
+	buf->data = newmem;
+	buf->size = size;
+
+	/* reset and not flush in case the buffer shrinks */
+	dvb_ringbuffer_reset(buf);
+	spin_unlock_irq(&dmxdevfilter->dev->lock);
+
+	vfree(oldmem);
+
 	return 0;
 }
 
@@ -374,7 +411,8 @@
 		return 0;
 	}
 
-	if (dmxdevfilter->params.pes.output == DMX_OUT_TAP)
+	if (dmxdevfilter->params.pes.output == DMX_OUT_TAP
+	    || dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP)
 		buffer = &dmxdevfilter->buffer;
 	else
 		buffer = &dmxdevfilter->dev->dvr_buffer;
@@ -550,7 +588,7 @@
 								   dvb_dmxdev_section_callback);
 			if (ret < 0) {
 				printk("DVB (%s): could not alloc feed\n",
-				       __FUNCTION__);
+				       __func__);
 				return ret;
 			}
 
@@ -558,7 +596,7 @@
 					      (para->flags & DMX_CHECK_CRC) ? 1 : 0);
 			if (ret < 0) {
 				printk("DVB (%s): could not set feed\n",
-				       __FUNCTION__);
+				       __func__);
 				dvb_dmxdev_feed_restart(filter);
 				return ret;
 			}
@@ -620,9 +658,10 @@
 
 		if (otype == DMX_OUT_TS_TAP)
 			ts_type |= TS_PACKET;
-
-		if (otype == DMX_OUT_TAP)
-			ts_type |= TS_PAYLOAD_ONLY | TS_PACKET;
+		else if (otype == DMX_OUT_TSDEMUX_TAP)
+			ts_type |= TS_PACKET | TS_DEMUX;
+		else if (otype == DMX_OUT_TAP)
+			ts_type |= TS_PACKET | TS_DEMUX | TS_PAYLOAD_ONLY;
 
 		ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux,
 						      tsfeed,
@@ -732,7 +771,7 @@
 				 struct dmxdev_filter *dmxdevfilter,
 				 struct dmx_sct_filter_params *params)
 {
-	dprintk("function : %s\n", __FUNCTION__);
+	dprintk("function : %s\n", __func__);
 
 	dvb_dmxdev_filter_stop(dmxdevfilter);
 
@@ -1007,6 +1046,7 @@
 {
 	struct dvb_device *dvbdev = file->private_data;
 	struct dmxdev *dmxdev = dvbdev->priv;
+	unsigned long arg = (unsigned long)parg;
 	int ret;
 
 	if (mutex_lock_interruptible(&dmxdev->mutex))
@@ -1014,8 +1054,7 @@
 
 	switch (cmd) {
 	case DMX_SET_BUFFER_SIZE:
-		// FIXME: implement
-		ret = 0;
+		ret = dvb_dvr_set_buffer_size(dmxdev, arg);
 		break;
 
 	default:
@@ -1038,7 +1077,7 @@
 	struct dmxdev *dmxdev = dvbdev->priv;
 	unsigned int mask = 0;
 
-	dprintk("function : %s\n", __FUNCTION__);
+	dprintk("function : %s\n", __func__);
 
 	poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
 
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
index 89437fd..8cbdb0e 100644
--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
@@ -250,7 +250,7 @@
 	unsigned long timeout;
 	unsigned long start;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	/* loop until timeout elapsed */
 	start = jiffies;
@@ -263,7 +263,7 @@
 
 		/* if we got the flags, it was successful! */
 		if (res & waitfor) {
-			dprintk("%s succeeded timeout:%lu\n", __FUNCTION__, jiffies - start);
+			dprintk("%s succeeded timeout:%lu\n", __func__, jiffies - start);
 			return 0;
 		}
 
@@ -276,7 +276,7 @@
 		msleep(1);
 	}
 
-	dprintk("%s failed timeout:%lu\n", __FUNCTION__, jiffies - start);
+	dprintk("%s failed timeout:%lu\n", __func__, jiffies - start);
 
 	/* if we get here, we've timed out */
 	return -ETIMEDOUT;
@@ -297,7 +297,7 @@
 	int buf_size;
 	u8 buf[2];
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	/* we'll be determining these during this function */
 	ca->slot_info[slot].da_irq_supported = 0;
@@ -549,7 +549,7 @@
 {
 	int configoption;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	/* set the config option */
 	ca->pub->write_attribute_mem(ca->pub, slot,
@@ -587,7 +587,7 @@
 	u8 buf[HOST_LINK_BUF_SIZE];
 	int i;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	/* check if we have space for a link buf in the rx_buffer */
 	if (ebuf == NULL) {
@@ -708,7 +708,7 @@
 	int status;
 	int i;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 
 	// sanity check
@@ -785,7 +785,7 @@
  */
 static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private *ca, int slot)
 {
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	ca->pub->slot_shutdown(ca->pub, slot);
 	ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
@@ -892,7 +892,7 @@
 static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca)
 {
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	ca->wakeup = 1;
 	mb();
@@ -964,7 +964,7 @@
 	int pktcount;
 	void *rxbuf;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	/* choose the correct initial delay */
 	dvb_ca_en50221_thread_update_delay(ca);
@@ -1172,7 +1172,7 @@
 	int err = 0;
 	int slot;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	switch (cmd) {
 	case CA_RESET:
@@ -1266,7 +1266,7 @@
 	unsigned long timeout;
 	int written;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	/* Incoming packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */
 	if (count < 2)
@@ -1401,7 +1401,7 @@
 	int pktlen;
 	int dispose = 0;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	/* Outgoing packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */
 	if (count < 2)
@@ -1490,7 +1490,7 @@
 	int err;
 	int i;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	if (!try_module_get(ca->pub->owner))
 		return -EIO;
@@ -1534,7 +1534,7 @@
 	struct dvb_ca_private *ca = dvbdev->priv;
 	int err;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	/* mark the CA device as closed */
 	ca->open = 0;
@@ -1564,7 +1564,7 @@
 	int slot;
 	int result = 0;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) {
 		mask |= POLLIN;
@@ -1626,7 +1626,7 @@
 	struct dvb_ca_private *ca = NULL;
 	int i;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	if (slot_count < 1)
 		return -EINVAL;
@@ -1704,7 +1704,7 @@
 	struct dvb_ca_private *ca = pubca->private;
 	int i;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	/* shutdown the thread if there was one */
 	kthread_stop(ca->thread);
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 7959020..934e15f 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -368,7 +368,7 @@
 #define DVR_FEED(f)							\
 	(((f)->type == DMX_TYPE_TS) &&					\
 	((f)->feed.ts.is_filtering) &&					\
-	(((f)->ts_type & (TS_PACKET|TS_PAYLOAD_ONLY)) == TS_PACKET))
+	(((f)->ts_type & (TS_PACKET | TS_DEMUX)) == TS_PACKET))
 
 static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
 {
@@ -553,7 +553,7 @@
 	spin_lock_irq(&feed->demux->lock);
 	if (dvb_demux_feed_find(feed)) {
 		printk(KERN_ERR "%s: feed already in list (type=%x state=%x pid=%x)\n",
-		       __FUNCTION__, feed->type, feed->state, feed->pid);
+		       __func__, feed->type, feed->state, feed->pid);
 		goto out;
 	}
 
@@ -567,7 +567,7 @@
 	spin_lock_irq(&feed->demux->lock);
 	if (!(dvb_demux_feed_find(feed))) {
 		printk(KERN_ERR "%s: feed not in list (type=%x state=%x pid=%x)\n",
-		       __FUNCTION__, feed->type, feed->state, feed->pid);
+		       __func__, feed->type, feed->state, feed->pid);
 		goto out;
 	}
 
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 925cfa6..2dddd08 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -135,7 +135,7 @@
 	struct dvb_frontend_event *e;
 	int wp;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	if (mutex_lock_interruptible (&events->mtx))
 		return;
@@ -171,7 +171,7 @@
 	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 	struct dvb_fe_events *events = &fepriv->events;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	if (events->overflow) {
 		events->overflow = 0;
@@ -237,7 +237,7 @@
 {
 	int q2;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	if (locked)
 		(fepriv->quality) = (fepriv->quality * 220 + 36*256) / 256;
@@ -329,7 +329,7 @@
 
 	dprintk("%s: drift:%i inversion:%i auto_step:%i "
 		"auto_sub_step:%i started_auto_step:%i\n",
-		__FUNCTION__, fepriv->lnb_drift, fepriv->inversion,
+		__func__, fepriv->lnb_drift, fepriv->inversion,
 		fepriv->auto_step, fepriv->auto_sub_step, fepriv->started_auto_step);
 
 	/* set the frontend itself */
@@ -511,7 +511,7 @@
 	fe_status_t s;
 	struct dvb_frontend_parameters *params;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	fepriv->check_wrapped = 0;
 	fepriv->quality = 0;
@@ -597,7 +597,7 @@
 {
 	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	fepriv->exit = 1;
 	mb();
@@ -665,7 +665,7 @@
 	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 	struct task_struct *fe_thread;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	if (fepriv->thread) {
 		if (!fepriv->exit)
@@ -763,7 +763,7 @@
 	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 	int err = -EOPNOTSUPP;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	if (fepriv->exit)
 		return -ENODEV;
@@ -895,7 +895,7 @@
 			int i;
 			u8 last = 1;
 			if (dvb_frontend_debug)
-				printk("%s switch command: 0x%04lx\n", __FUNCTION__, cmd);
+				printk("%s switch command: 0x%04lx\n", __func__, cmd);
 			do_gettimeofday(&nexttime);
 			if (dvb_frontend_debug)
 				memcpy(&tv[0], &nexttime, sizeof(struct timeval));
@@ -919,7 +919,7 @@
 			}
 			if (dvb_frontend_debug) {
 				printk("%s(%d): switch delay (should be 32k followed by all 8k\n",
-					__FUNCTION__, fe->dvb->num);
+					__func__, fe->dvb->num);
 				for (i = 1; i < 10; i++)
 					printk("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i]));
 			}
@@ -1037,7 +1037,7 @@
 	struct dvb_frontend *fe = dvbdev->priv;
 	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	poll_wait (file, &fepriv->events.wait_queue, wait);
 
@@ -1054,7 +1054,7 @@
 	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 	int ret;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) {
 		if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0)
@@ -1095,7 +1095,7 @@
 	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 	int ret;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	if ((file->f_flags & O_ACCMODE) != O_RDONLY)
 		fepriv->release_jiffies = jiffies;
@@ -1135,7 +1135,7 @@
 		.kernel_ioctl = dvb_frontend_ioctl
 	};
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	if (mutex_lock_interruptible(&frontend_mutex))
 		return -ERESTARTSYS;
@@ -1169,7 +1169,7 @@
 int dvb_unregister_frontend(struct dvb_frontend* fe)
 {
 	struct dvb_frontend_private *fepriv = fe->frontend_priv;
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	mutex_lock(&frontend_mutex);
 	dvb_frontend_stop (fe);
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index 4c8b62e..56d871c 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -354,7 +354,7 @@
 #ifdef ULE_DEBUG
 	/* The code inside ULE_DEBUG keeps a history of the last 100 TS cells processed. */
 	static unsigned char ule_hist[100*TS_SZ];
-	static unsigned char *ule_where = ule_hist, ule_dump = 0;
+	static unsigned char *ule_where = ule_hist, ule_dump;
 #endif
 
 	/* For all TS cells in current buffer.
@@ -965,17 +965,17 @@
 	struct dmx_demux *demux = priv->demux;
 	unsigned char *mac = (unsigned char *) dev->dev_addr;
 
-	dprintk("%s: rx_mode %i\n", __FUNCTION__, priv->rx_mode);
+	dprintk("%s: rx_mode %i\n", __func__, priv->rx_mode);
 	mutex_lock(&priv->mutex);
 	if (priv->tsfeed || priv->secfeed || priv->secfilter || priv->multi_secfilter[0])
-		printk("%s: BUG %d\n", __FUNCTION__, __LINE__);
+		printk("%s: BUG %d\n", __func__, __LINE__);
 
 	priv->secfeed=NULL;
 	priv->secfilter=NULL;
 	priv->tsfeed = NULL;
 
 	if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) {
-		dprintk("%s: alloc secfeed\n", __FUNCTION__);
+		dprintk("%s: alloc secfeed\n", __func__);
 		ret=demux->allocate_section_feed(demux, &priv->secfeed,
 					 dvb_net_sec_callback);
 		if (ret<0) {
@@ -993,38 +993,38 @@
 		}
 
 		if (priv->rx_mode != RX_MODE_PROMISC) {
-			dprintk("%s: set secfilter\n", __FUNCTION__);
+			dprintk("%s: set secfilter\n", __func__);
 			dvb_net_filter_sec_set(dev, &priv->secfilter, mac, mask_normal);
 		}
 
 		switch (priv->rx_mode) {
 		case RX_MODE_MULTI:
 			for (i = 0; i < priv->multi_num; i++) {
-				dprintk("%s: set multi_secfilter[%d]\n", __FUNCTION__, i);
+				dprintk("%s: set multi_secfilter[%d]\n", __func__, i);
 				dvb_net_filter_sec_set(dev, &priv->multi_secfilter[i],
 						       priv->multi_macs[i], mask_normal);
 			}
 			break;
 		case RX_MODE_ALL_MULTI:
 			priv->multi_num=1;
-			dprintk("%s: set multi_secfilter[0]\n", __FUNCTION__);
+			dprintk("%s: set multi_secfilter[0]\n", __func__);
 			dvb_net_filter_sec_set(dev, &priv->multi_secfilter[0],
 					       mac_allmulti, mask_allmulti);
 			break;
 		case RX_MODE_PROMISC:
 			priv->multi_num=0;
-			dprintk("%s: set secfilter\n", __FUNCTION__);
+			dprintk("%s: set secfilter\n", __func__);
 			dvb_net_filter_sec_set(dev, &priv->secfilter, mac, mask_promisc);
 			break;
 		}
 
-		dprintk("%s: start filtering\n", __FUNCTION__);
+		dprintk("%s: start filtering\n", __func__);
 		priv->secfeed->start_filtering(priv->secfeed);
 	} else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) {
 		struct timespec timeout = { 0, 10000000 }; // 10 msec
 
 		/* we have payloads encapsulated in TS */
-		dprintk("%s: alloc tsfeed\n", __FUNCTION__);
+		dprintk("%s: alloc tsfeed\n", __func__);
 		ret = demux->allocate_ts_feed(demux, &priv->tsfeed, dvb_net_ts_callback);
 		if (ret < 0) {
 			printk("%s: could not allocate ts feed\n", dev->name);
@@ -1048,7 +1048,7 @@
 			goto error;
 		}
 
-		dprintk("%s: start filtering\n", __FUNCTION__);
+		dprintk("%s: start filtering\n", __func__);
 		priv->tsfeed->start_filtering(priv->tsfeed);
 	} else
 		ret = -EINVAL;
@@ -1063,17 +1063,17 @@
 	struct dvb_net_priv *priv = dev->priv;
 	int i, ret = 0;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 	mutex_lock(&priv->mutex);
 	if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) {
 		if (priv->secfeed) {
 			if (priv->secfeed->is_filtering) {
-				dprintk("%s: stop secfeed\n", __FUNCTION__);
+				dprintk("%s: stop secfeed\n", __func__);
 				priv->secfeed->stop_filtering(priv->secfeed);
 			}
 
 			if (priv->secfilter) {
-				dprintk("%s: release secfilter\n", __FUNCTION__);
+				dprintk("%s: release secfilter\n", __func__);
 				priv->secfeed->release_filter(priv->secfeed,
 							      priv->secfilter);
 				priv->secfilter=NULL;
@@ -1082,7 +1082,7 @@
 			for (i=0; i<priv->multi_num; i++) {
 				if (priv->multi_secfilter[i]) {
 					dprintk("%s: release multi_filter[%d]\n",
-						__FUNCTION__, i);
+						__func__, i);
 					priv->secfeed->release_filter(priv->secfeed,
 								      priv->multi_secfilter[i]);
 					priv->multi_secfilter[i] = NULL;
@@ -1096,7 +1096,7 @@
 	} else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) {
 		if (priv->tsfeed) {
 			if (priv->tsfeed->is_filtering) {
-				dprintk("%s: stop tsfeed\n", __FUNCTION__);
+				dprintk("%s: stop tsfeed\n", __func__);
 				priv->tsfeed->stop_filtering(priv->tsfeed);
 			}
 			priv->demux->release_ts_feed(priv->demux, priv->tsfeed);
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
index ac9d93c..872985b 100644
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
+++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
@@ -90,7 +90,11 @@
 	rbuf->error = 0;
 }
 
-
+void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf)
+{
+	rbuf->pread = rbuf->pwrite = 0;
+	rbuf->error = 0;
+}
 
 void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf)
 {
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
index d97714e..8908262 100644
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
+++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
@@ -69,6 +69,7 @@
 **     to lock read or write operations.
 **     Two or more readers must be locked against each other.
 **     Flushing the buffer counts as a read operation.
+**     Resetting the buffer counts as a read and write operation.
 **     Two or more writers must be locked against each other.
 */
 
@@ -85,6 +86,13 @@
 extern ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf);
 
 
+/*
+** Reset the read and write pointers to zero and flush the buffer
+** This counts as a read and write operation
+*/
+extern void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf);
+
+
 /* read routines & macros */
 /* ---------------------- */
 /* flush buffer */
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
index 18738fa..8b56d92 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/drivers/media/dvb/dvb-core/dvbdev.c
@@ -49,7 +49,6 @@
 	"net", "osd"
 };
 
-#define DVB_MAX_ADAPTERS	8
 #define DVB_MAX_IDS		4
 #define nums2minor(num,type,id)	((num << 6) | (id << 4) | type)
 #define MAX_DVB_MINORS		(DVB_MAX_ADAPTERS*64)
@@ -97,7 +96,7 @@
 }
 
 
-static struct file_operations dvb_device_fops =
+static const struct file_operations dvb_device_fops =
 {
 	.owner =	THIS_MODULE,
 	.open =		dvb_device_open,
@@ -196,7 +195,7 @@
 	if ((id = dvbdev_get_free_id (adap, type)) < 0){
 		mutex_unlock(&dvbdev_register_lock);
 		*pdvbdev = NULL;
-		printk(KERN_ERR "%s: couldn't find free device id\n", __FUNCTION__);
+		printk(KERN_ERR "%s: couldn't find free device id\n", __func__);
 		return -ENFILE;
 	}
 
@@ -235,7 +234,7 @@
 			       "dvb%d.%s%d", adap->num, dnames[type], id);
 	if (IS_ERR(clsdev)) {
 		printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n",
-		       __FUNCTION__, adap->num, dnames[type], id, PTR_ERR(clsdev));
+		       __func__, adap->num, dnames[type], id, PTR_ERR(clsdev));
 		return PTR_ERR(clsdev);
 	}
 
@@ -262,18 +261,25 @@
 }
 EXPORT_SYMBOL(dvb_unregister_device);
 
+static int dvbdev_check_free_adapter_num(int num)
+{
+	struct list_head *entry;
+	list_for_each(entry, &dvb_adapter_list) {
+		struct dvb_adapter *adap;
+		adap = list_entry(entry, struct dvb_adapter, list_head);
+		if (adap->num == num)
+			return 0;
+	}
+	return 1;
+}
 
 static int dvbdev_get_free_adapter_num (void)
 {
 	int num = 0;
 
 	while (num < DVB_MAX_ADAPTERS) {
-		struct dvb_adapter *adap;
-		list_for_each_entry(adap, &dvb_adapter_list, list_head)
-			if (adap->num == num)
-				goto skip;
-		return num;
-skip:
+		if (dvbdev_check_free_adapter_num(num))
+			return num;
 		num++;
 	}
 
@@ -281,13 +287,28 @@
 }
 
 
-int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct module *module, struct device *device)
+int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
+			 struct module *module, struct device *device,
+			 short *adapter_nums)
 {
-	int num;
+	int i, num;
 
 	mutex_lock(&dvbdev_register_lock);
 
-	if ((num = dvbdev_get_free_adapter_num ()) < 0) {
+	for (i = 0; i < DVB_MAX_ADAPTERS; ++i) {
+		num = adapter_nums[i];
+		if (num >= 0  &&  num < DVB_MAX_ADAPTERS) {
+		/* use the one the driver asked for */
+			if (dvbdev_check_free_adapter_num(num))
+				break;
+		} else {
+			num = dvbdev_get_free_adapter_num();
+			break;
+		}
+		num = -1;
+	}
+
+	if (num < 0) {
 		mutex_unlock(&dvbdev_register_lock);
 		return -ENFILE;
 	}
diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h
index 6dff10e..5f9a737 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.h
+++ b/drivers/media/dvb/dvb-core/dvbdev.h
@@ -31,6 +31,10 @@
 
 #define DVB_MAJOR 212
 
+#define DVB_MAX_ADAPTERS 8
+
+#define DVB_UNSET (-1)
+
 #define DVB_DEVICE_VIDEO      0
 #define DVB_DEVICE_AUDIO      1
 #define DVB_DEVICE_SEC        2
@@ -41,6 +45,11 @@
 #define DVB_DEVICE_NET        7
 #define DVB_DEVICE_OSD        8
 
+#define DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr) \
+	static short adapter_nr[] = \
+		{[0 ... (DVB_MAX_ADAPTERS - 1)] = DVB_UNSET }; \
+	module_param_array(adapter_nr, short, NULL, 0444); \
+	MODULE_PARM_DESC(adapter_nr, "DVB adapter numbers")
 
 struct dvb_adapter {
 	int num;
@@ -78,7 +87,9 @@
 };
 
 
-extern int dvb_register_adapter (struct dvb_adapter *adap, const char *name, struct module *module, struct device *device);
+extern int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
+				struct module *module, struct device *device,
+				short *adapter_nums);
 extern int dvb_unregister_adapter (struct dvb_adapter *adap);
 
 extern int dvb_register_device (struct dvb_adapter *adap,
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index d73934d..3c8493d 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -105,6 +105,7 @@
 	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
 	select DVB_MT352 if !DVB_FE_CUSTOMISE
 	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+	select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
 	help
 	  Say Y here to support the Conexant USB2.0 hybrid reference design.
 	  Currently, only DVB and ATSC modes are supported, analog mode
diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c
index a6c5f19..dc8c878 100644
--- a/drivers/media/dvb/dvb-usb/a800.c
+++ b/drivers/media/dvb/dvb-usb/a800.c
@@ -18,6 +18,9 @@
 static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (rc=1 (or-able))." DVB_USB_DEBUG_STATUS);
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 #define deb_rc(args...)   dprintk(debug,0x01,args)
 
 static int a800_power_ctrl(struct dvb_usb_device *d, int onoff)
@@ -94,7 +97,8 @@
 static int a800_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
-	return dvb_usb_device_init(intf,&a800_properties,THIS_MODULE,NULL);
+	return dvb_usb_device_init(intf, &a800_properties,
+				   THIS_MODULE, NULL, adapter_nr);
 }
 
 /* do not change the order of the ID table */
diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c
index e7f76f5..cfe71fe 100644
--- a/drivers/media/dvb/dvb-usb/af9005.c
+++ b/drivers/media/dvb/dvb-usb/af9005.c
@@ -39,6 +39,8 @@
 module_param_named(dump_eeprom, dvb_usb_af9005_dump_eeprom, int, 0);
 MODULE_PARM_DESC(dump_eeprom, "dump contents of the eeprom.");
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 /* remote control decoder */
 int (*rc_decode) (struct dvb_usb_device * d, u8 * data, int len, u32 * event,
 		  int *state);
@@ -1020,7 +1022,8 @@
 static int af9005_usb_probe(struct usb_interface *intf,
 			    const struct usb_device_id *id)
 {
-	return dvb_usb_device_init(intf, &af9005_properties, THIS_MODULE, NULL);
+	return dvb_usb_device_init(intf, &af9005_properties,
+				   THIS_MODULE, NULL, adapter_nr);
 }
 
 static struct usb_device_id af9005_usb_table[] = {
diff --git a/drivers/media/dvb/dvb-usb/au6610.c b/drivers/media/dvb/dvb-usb/au6610.c
index f3ff813..2ccb90f 100644
--- a/drivers/media/dvb/dvb-usb/au6610.c
+++ b/drivers/media/dvb/dvb-usb/au6610.c
@@ -19,6 +19,8 @@
 module_param_named(debug, dvb_usb_au6610_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
 			  u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
 {
@@ -163,7 +165,9 @@
 	if (intf->num_altsetting < AU6610_ALTSETTING_COUNT)
 		return -ENODEV;
 
-	if ((ret = dvb_usb_device_init(intf, &au6610_properties, THIS_MODULE, &d)) == 0) {
+	ret = dvb_usb_device_init(intf, &au6610_properties, THIS_MODULE, &d,
+				  adapter_nr);
+	if (ret == 0) {
 		alt = usb_altnum_to_altsetting(intf, AU6610_ALTSETTING);
 
 		if (alt == NULL) {
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index c583650..720fcd1 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -23,6 +23,8 @@
  *
  * see Documentation/dvb/README.dvb-usb for more information
  */
+#include <media/tuner.h>
+
 #include "cxusb.h"
 
 #include "cx22702.h"
@@ -31,12 +33,15 @@
 #include "mt352_priv.h"
 #include "zl10353.h"
 #include "tuner-xc2028.h"
-#include "tuner-xc2028-types.h"
+#include "tuner-simple.h"
 
 /* debug */
 static int dvb_usb_cxusb_debug;
 module_param_named(debug, dvb_usb_cxusb_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 #define deb_info(args...)   dprintk(dvb_usb_cxusb_debug,0x01,args)
 #define deb_i2c(args...)    if (d->udev->descriptor.idVendor == USB_VID_MEDION) \
 				dprintk(dvb_usb_cxusb_debug,0x01,args)
@@ -450,8 +455,9 @@
 /* Callbacks for DVB USB */
 static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
 {
-	dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap,
-		   DVB_PLL_FMD1216ME);
+	dvb_attach(simple_tuner_attach, adap->fe,
+		   &adap->dev->i2c_adap, 0x61,
+		   TUNER_PHILIPS_FMD1216ME_MK3);
 	return 0;
 }
 
@@ -477,8 +483,8 @@
 
 static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap)
 {
-	dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap,
-		   DVB_PLL_LG_TDVS_H06XF);
+	dvb_attach(simple_tuner_attach, adap->fe,
+		   &adap->dev->i2c_adap, 0x61, TUNER_LG_TDVS_H06XF);
 	return 0;
 }
 
@@ -488,14 +494,14 @@
 
 	switch (command) {
 	case XC2028_TUNER_RESET:
-		deb_info("%s: XC2028_TUNER_RESET %d\n", __FUNCTION__, arg);
+		deb_info("%s: XC2028_TUNER_RESET %d\n", __func__, arg);
 		cxusb_bluebird_gpio_pulse(d, 0x01, 1);
 		break;
 	case XC2028_RESET_CLK:
-		deb_info("%s: XC2028_RESET_CLK %d\n", __FUNCTION__, arg);
+		deb_info("%s: XC2028_RESET_CLK %d\n", __func__, arg);
 		break;
 	default:
-		deb_info("%s: unknown command %d, arg %d\n", __FUNCTION__,
+		deb_info("%s: unknown command %d, arg %d\n", __func__,
 			 command, arg);
 		return -EINVAL;
 	}
@@ -509,13 +515,12 @@
 	struct xc2028_config	  cfg = {
 		.i2c_adap  = &adap->dev->i2c_adap,
 		.i2c_addr  = 0x61,
-		.video_dev = adap->dev,
 		.callback  = dvico_bluebird_xc2028_callback,
 	};
 	static struct xc2028_ctrl ctl = {
 		.fname       = "xc3028-dvico-au-01.fw",
 		.max_len     = 64,
-		.scode_table = ZARLINK456,
+		.scode_table = XC3028_FE_ZARLINK456,
 	};
 
 	fe = dvb_attach(xc2028_attach, adap->fe, &cfg);
@@ -720,16 +725,24 @@
 static int cxusb_probe(struct usb_interface *intf,
 		       const struct usb_device_id *id)
 {
-	if (dvb_usb_device_init(intf,&cxusb_medion_properties,THIS_MODULE,NULL) == 0 ||
-		dvb_usb_device_init(intf,&cxusb_bluebird_lgh064f_properties,THIS_MODULE,NULL) == 0 ||
-		dvb_usb_device_init(intf,&cxusb_bluebird_dee1601_properties,THIS_MODULE,NULL) == 0 ||
-		dvb_usb_device_init(intf,&cxusb_bluebird_lgz201_properties,THIS_MODULE,NULL) == 0 ||
-		dvb_usb_device_init(intf,&cxusb_bluebird_dtt7579_properties,THIS_MODULE,NULL) == 0 ||
-		dvb_usb_device_init(intf,&cxusb_bluebird_dualdig4_properties,THIS_MODULE,NULL) == 0 ||
-		dvb_usb_device_init(intf,&cxusb_bluebird_nano2_properties,THIS_MODULE,NULL) == 0 ||
-		dvb_usb_device_init(intf,&cxusb_bluebird_nano2_needsfirmware_properties,THIS_MODULE,NULL) == 0) {
+	if (0 == dvb_usb_device_init(intf, &cxusb_medion_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &cxusb_bluebird_lgh064f_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &cxusb_bluebird_dee1601_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &cxusb_bluebird_lgz201_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &cxusb_bluebird_dtt7579_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &cxusb_bluebird_dualdig4_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &cxusb_bluebird_nano2_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf,
+				&cxusb_bluebird_nano2_needsfirmware_properties,
+				     THIS_MODULE, NULL, adapter_nr))
 		return 0;
-	}
 
 	return -EINVAL;
 }
diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h
index 4a903ea..66d4dc6 100644
--- a/drivers/media/dvb/dvb-usb/dib0700.h
+++ b/drivers/media/dvb/dvb-usb/dib0700.h
@@ -37,6 +37,7 @@
 	u8 channel_state;
 	u16 mt2060_if1[2];
 	u8 rc_toggle;
+	u8 rc_counter;
 	u8 is_dib7000pc;
 };
 
@@ -44,12 +45,15 @@
 extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3);
 extern int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen);
 extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw);
+extern int dib0700_rc_setup(struct dvb_usb_device *d);
 extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff);
 extern struct i2c_algorithm dib0700_i2c_algo;
 extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
 			struct dvb_usb_device_description **desc, int *cold);
 
 extern int dib0700_device_count;
+extern int dvb_usb_dib0700_ir_proto;
 extern struct dvb_usb_device_properties dib0700_devices[];
 extern struct usb_device_id dib0700_usb_id_table[];
+
 #endif
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
index c9857d5..595a046 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
@@ -13,10 +13,12 @@
 module_param_named(debug,dvb_usb_dib0700_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-able))." DVB_USB_DEBUG_STATUS);
 
-static int dvb_usb_dib0700_ir_proto = 1;
+int dvb_usb_dib0700_ir_proto = 1;
 module_param(dvb_usb_dib0700_ir_proto, int, 0644);
 MODULE_PARM_DESC(dvb_usb_dib0700_ir_proto, "set ir protocol (0=NEC, 1=RC5 (default), 2=RC6).");
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 /* expecting rx buffer: request data[0] data[1] ... data[2] */
 static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen)
 {
@@ -261,7 +263,7 @@
 	return dib0700_ctrl_wr(adap->dev, b, 4);
 }
 
-static int dib0700_rc_setup(struct dvb_usb_device *d)
+int dib0700_rc_setup(struct dvb_usb_device *d)
 {
 	u8 rc_setup[3] = {REQUEST_SET_RC, dvb_usb_dib0700_ir_proto, 0};
 	int i = dib0700_ctrl_wr(d, rc_setup, 3);
@@ -279,7 +281,8 @@
 	struct dvb_usb_device *dev;
 
 	for (i = 0; i < dib0700_device_count; i++)
-		if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, &dev) == 0)
+		if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE,
+					&dev, adapter_nr) == 0)
 		{
 			dib0700_rc_setup(dev);
 			return 0;
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index e709382..6477fc6 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -13,6 +13,7 @@
 #include "dib7000p.h"
 #include "mt2060.h"
 #include "mt2266.h"
+#include "tuner-xc2028.h"
 #include "dib0070.h"
 
 static int force_lna_activation;
@@ -297,10 +298,156 @@
 		&stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0;;
 }
 
+/* STK7700-PH: Digital/Analog Hybrid Tuner, e.h. Cinergy HT USB HE */
+struct dibx000_agc_config xc3028_agc_config = {
+	BAND_VHF | BAND_UHF,       /* band_caps */
+
+	/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=0,
+	 * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
+	 * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
+	(0 << 15) | (0 << 14) | (0 << 11) | (0 << 10) | (0 << 9) | (0 << 8) |
+	(3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), /* setup */
+
+	712,	/* inv_gain */
+	21,	/* time_stabiliz */
+
+	0,	/* alpha_level */
+	118,	/* thlock */
+
+	0,	/* wbd_inv */
+	2867,	/* wbd_ref */
+	0,	/* wbd_sel */
+	2,	/* wbd_alpha */
+
+	0,	/* agc1_max */
+	0,	/* agc1_min */
+	39718,	/* agc2_max */
+	9930,	/* agc2_min */
+	0,	/* agc1_pt1 */
+	0,	/* agc1_pt2 */
+	0,	/* agc1_pt3 */
+	0,	/* agc1_slope1 */
+	0,	/* agc1_slope2 */
+	0,	/* agc2_pt1 */
+	128,	/* agc2_pt2 */
+	29,	/* agc2_slope1 */
+	29,	/* agc2_slope2 */
+
+	17,	/* alpha_mant */
+	27,	/* alpha_exp */
+	23,	/* beta_mant */
+	51,	/* beta_exp */
+
+	1,	/* perform_agc_softsplit */
+};
+
+/* PLL Configuration for COFDM BW_MHz = 8.00 with external clock = 30.00 */
+struct dibx000_bandwidth_config xc3028_bw_config = {
+	60000, 30000, /* internal, sampling */
+	1, 8, 3, 1, 0, /* pll_cfg: prediv, ratio, range, reset, bypass */
+	0, 0, 1, 1, 0, /* misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc,
+			  modulo */
+	(3 << 14) | (1 << 12) | (524 << 0), /* sad_cfg: refsel, sel, freq_15k */
+	(1 << 25) | 5816102, /* ifreq = 5.200000 MHz */
+	20452225, /* timf */
+	30000000, /* xtal_hz */
+};
+
+static struct dib7000p_config stk7700ph_dib7700_xc3028_config = {
+	.output_mpeg2_in_188_bytes = 1,
+	.tuner_is_baseband = 1,
+
+	.agc_config_count = 1,
+	.agc = &xc3028_agc_config,
+	.bw  = &xc3028_bw_config,
+
+	.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+	.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+	.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+};
+
+static int stk7700ph_xc3028_callback(void *ptr, int command, int arg)
+{
+	struct dvb_usb_adapter *adap = ptr;
+
+	switch (command) {
+	case XC2028_TUNER_RESET:
+		/* Send the tuner in then out of reset */
+		dib7000p_set_gpio(adap->fe, 8, 0, 0); msleep(10);
+		dib7000p_set_gpio(adap->fe, 8, 0, 1);
+		break;
+	case XC2028_RESET_CLK:
+		break;
+	default:
+		err("%s: unknown command %d, arg %d\n", __func__,
+			command, arg);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static struct xc2028_ctrl stk7700ph_xc3028_ctrl = {
+	.fname = XC2028_DEFAULT_FIRMWARE,
+	.max_len = 64,
+	.demod = XC3028_FE_DIBCOM52,
+};
+
+static struct xc2028_config stk7700ph_xc3028_config = {
+	.i2c_addr = 0x61,
+	.callback = stk7700ph_xc3028_callback,
+	.ctrl = &stk7700ph_xc3028_ctrl,
+};
+
+static int stk7700ph_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct usb_device_descriptor *desc = &adap->dev->udev->descriptor;
+
+	if (desc->idVendor  == USB_VID_PINNACLE &&
+	    desc->idProduct == USB_PID_PINNACLE_EXPRESSCARD_320CX)
+	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
+	else
+	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+	msleep(20);
+	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+	msleep(20);
+	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+	msleep(10);
+
+	dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
+		&stk7700ph_dib7700_xc3028_config);
+
+	adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
+		&stk7700ph_dib7700_xc3028_config);
+
+	return adap->fe == NULL ? -ENODEV : 0;
+}
+
+static int stk7700ph_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct i2c_adapter *tun_i2c;
+
+	tun_i2c = dib7000p_get_i2c_master(adap->fe,
+		DIBX000_I2C_INTERFACE_TUNER, 1);
+
+	stk7700ph_xc3028_config.i2c_adap = tun_i2c;
+	stk7700ph_xc3028_config.video_dev = adap;
+
+	return dvb_attach(xc2028_attach, adap->fe, &stk7700ph_xc3028_config)
+		== NULL ? -ENODEV : 0;
+}
+
 #define DEFAULT_RC_INTERVAL 150
 
 static u8 rc_request[] = { REQUEST_POLL_RC, 0 };
 
+/* Number of keypresses to ignore before start repeating */
+#define RC_REPEAT_DELAY 2
+
 static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
 	u8 key[4];
@@ -314,18 +461,67 @@
 		err("RC Query Failed");
 		return -1;
 	}
+
+	/* losing half of KEY_0 events from Philipps rc5 remotes.. */
 	if (key[0]==0 && key[1]==0 && key[2]==0 && key[3]==0) return 0;
-	if (key[3-1]!=st->rc_toggle) {
+
+	/* info("%d: %2X %2X %2X %2X",dvb_usb_dib0700_ir_proto,(int)key[3-2],(int)key[3-3],(int)key[3-1],(int)key[3]);  */
+
+	dib0700_rc_setup(d); /* reset ir sensor data to prevent false events */
+
+	switch (dvb_usb_dib0700_ir_proto) {
+	case 0: {
+		/* NEC protocol sends repeat code as 0 0 0 FF */
+		if ((key[3-2] == 0x00) && (key[3-3] == 0x00) &&
+		    (key[3] == 0xFF)) {
+			st->rc_counter++;
+			if (st->rc_counter > RC_REPEAT_DELAY) {
+				*event = d->last_event;
+				*state = REMOTE_KEY_PRESSED;
+				st->rc_counter = RC_REPEAT_DELAY;
+			}
+			return 0;
+		}
 		for (i=0;i<d->props.rc_key_map_size; i++) {
 			if (keymap[i].custom == key[3-2] && keymap[i].data == key[3-3]) {
+				st->rc_counter = 0;
 				*event = keymap[i].event;
 				*state = REMOTE_KEY_PRESSED;
-				st->rc_toggle=key[3-1];
+				d->last_event = keymap[i].event;
 				return 0;
 			}
 		}
-		err("Unknown remote controller key : %2X %2X",(int)key[3-2],(int)key[3-3]);
+		break;
 	}
+	default: {
+		/* RC-5 protocol changes toggle bit on new keypress */
+		for (i = 0; i < d->props.rc_key_map_size; i++) {
+			if (keymap[i].custom == key[3-2] && keymap[i].data == key[3-3]) {
+				if (d->last_event == keymap[i].event &&
+					key[3-1] == st->rc_toggle) {
+					st->rc_counter++;
+					/* prevents unwanted double hits */
+					if (st->rc_counter > RC_REPEAT_DELAY) {
+						*event = d->last_event;
+						*state = REMOTE_KEY_PRESSED;
+						st->rc_counter = RC_REPEAT_DELAY;
+					}
+
+					return 0;
+				}
+				st->rc_counter = 0;
+				*event = keymap[i].event;
+				*state = REMOTE_KEY_PRESSED;
+				st->rc_toggle = key[3-1];
+				d->last_event = keymap[i].event;
+				return 0;
+			}
+		}
+		break;
+	}
+	}
+	err("Unknown remote controller key: %2X %2X %2X %2X", (int) key[3-2], (int) key[3-3], (int) key[3-1], (int) key[3]);
+	d->last_event = 0;
 	return 0;
 }
 
@@ -794,6 +990,10 @@
 /* STK7070P */
 static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap)
 {
+	if (adap->dev->udev->descriptor.idVendor  == USB_VID_PINNACLE &&
+	adap->dev->udev->descriptor.idProduct == USB_PID_PINNACLE_PCTV72E)
+	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
+	else
 	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
 	msleep(10);
 	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
@@ -808,9 +1008,11 @@
 	msleep(10);
 	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
 
-	dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, &dib7070p_dib7000p_config);
+	dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
+		&dib7070p_dib7000p_config);
 
-	adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &dib7070p_dib7000p_config);
+	adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
+		&dib7070p_dib7000p_config);
 	return adap->fe == NULL ? -ENODEV : 0;
 }
 
@@ -878,34 +1080,43 @@
 /* DVB-USB and USB stuff follows */
 struct usb_device_id dib0700_usb_id_table[] = {
 /* 0 */	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7700P) },
-		{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7700P_PC) },
-
-		{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500) },
-		{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_2) },
-		{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK) },
+	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7700P_PC) },
+	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500) },
+	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_2) },
+	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK) },
 /* 5 */	{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) },
-		{ USB_DEVICE(USB_VID_COMPRO,    USB_PID_COMPRO_VIDEOMATE_U500) },
-		{ USB_DEVICE(USB_VID_UNIWILL,   USB_PID_UNIWILL_STK7700P) },
-		{ USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV_DONGLE_STK7700P) },
-		{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_2) },
+	{ USB_DEVICE(USB_VID_COMPRO,    USB_PID_COMPRO_VIDEOMATE_U500) },
+	{ USB_DEVICE(USB_VID_UNIWILL,   USB_PID_UNIWILL_STK7700P) },
+	{ USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV_DONGLE_STK7700P) },
+	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_2) },
 /* 10 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) },
-		{ USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV2000E) },
-		{ USB_DEVICE(USB_VID_TERRATEC,  USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY) },
-		{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK) },
-		{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7700D) },
+	{ USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV2000E) },
+	{ USB_DEVICE(USB_VID_TERRATEC,
+			USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY) },
+	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK) },
+	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7700D) },
 /* 15 */{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7070P) },
-		{ USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV_DVB_T_FLASH) },
-		{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7070PD) },
-		{ USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) },
-		{ USB_DEVICE(USB_VID_COMPRO,    USB_PID_COMPRO_VIDEOMATE_U500_PC) },
+	{ USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV_DVB_T_FLASH) },
+	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7070PD) },
+	{ USB_DEVICE(USB_VID_PINNACLE,
+			USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) },
+	{ USB_DEVICE(USB_VID_COMPRO,    USB_PID_COMPRO_VIDEOMATE_U500_PC) },
 /* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) },
-		{ USB_DEVICE(USB_VID_GIGABYTE,  USB_PID_GIGABYTE_U7000) },
-		{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14BR) },
-		{ USB_DEVICE(USB_VID_ASUS,      USB_PID_ASUS_U3000) },
-		{ USB_DEVICE(USB_VID_ASUS,      USB_PID_ASUS_U3100) },
-/* 25 */	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_3) },
-		{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_MYTV_T) },
-		{ 0 }		/* Terminating entry */
+	{ USB_DEVICE(USB_VID_GIGABYTE,  USB_PID_GIGABYTE_U7000) },
+	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14BR) },
+	{ USB_DEVICE(USB_VID_ASUS,      USB_PID_ASUS_U3000) },
+	{ USB_DEVICE(USB_VID_ASUS,      USB_PID_ASUS_U3100) },
+/* 25 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_3) },
+	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_MYTV_T) },
+	{ USB_DEVICE(USB_VID_TERRATEC,  USB_PID_TERRATEC_CINERGY_HT_USB_XE) },
+	{ USB_DEVICE(USB_VID_PINNACLE,	USB_PID_PINNACLE_EXPRESSCARD_320CX) },
+	{ USB_DEVICE(USB_VID_PINNACLE,	USB_PID_PINNACLE_PCTV72E) },
+/* 30 */{ USB_DEVICE(USB_VID_PINNACLE,	USB_PID_PINNACLE_PCTV73E) },
+	{ USB_DEVICE(USB_VID_YUAN,	USB_PID_YUAN_EC372S) },
+	{ USB_DEVICE(USB_VID_TERRATEC,	USB_PID_TERRATEC_CINERGY_HT_EXPRESS) },
+	{ USB_DEVICE(USB_VID_TERRATEC,	USB_PID_TERRATEC_CINERGY_T_XXS) },
+	{ USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV_DONGLE_STK7700P_2) },
+	{ 0 }		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
 
@@ -969,7 +1180,7 @@
 				{ NULL },
 			},
 			{   "Leadtek Winfast DTV Dongle (STK7700P based)",
-				{ &dib0700_usb_id_table[8], NULL },
+				{ &dib0700_usb_id_table[8], &dib0700_usb_id_table[34] },
 				{ NULL },
 			},
 			{   "AVerMedia AVerTV DVB-T Express",
@@ -1069,12 +1280,16 @@
 			},
 		},
 
-		.num_device_descs = 1,
+		.num_device_descs = 2,
 		.devices = {
 			{   "ASUS My Cinema U3000 Mini DVBT Tuner",
 				{ &dib0700_usb_id_table[23], NULL },
 				{ NULL },
 			},
+			{   "Yuan EC372S",
+				{ &dib0700_usb_id_table[31], NULL },
+				{ NULL },
+			}
 		}
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 
@@ -1090,7 +1305,7 @@
 			},
 		},
 
-		.num_device_descs = 6,
+		.num_device_descs = 9,
 		.devices = {
 			{   "DiBcom STK7070P reference design",
 				{ &dib0700_usb_id_table[15], NULL },
@@ -1116,6 +1331,18 @@
 				{ &dib0700_usb_id_table[26], NULL },
 				{ NULL },
 			},
+			{   "Pinnacle PCTV 72e",
+				{ &dib0700_usb_id_table[29], NULL },
+				{ NULL },
+			},
+			{   "Pinnacle PCTV 73e",
+				{ &dib0700_usb_id_table[30], NULL },
+				{ NULL },
+			},
+			{   "Terratec Cinergy T USB XXS",
+				{ &dib0700_usb_id_table[33], NULL },
+				{ NULL },
+			},
 		},
 
 		.rc_interval      = DEFAULT_RC_INTERVAL,
@@ -1155,6 +1382,40 @@
 				{ NULL },
 			}
 		}
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+		.num_adapters = 1,
+		.adapter = {
+			{
+				.frontend_attach  = stk7700ph_frontend_attach,
+				.tuner_attach     = stk7700ph_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+				.size_of_priv = sizeof(struct
+						dib0700_adapter_state),
+			},
+		},
+
+		.num_device_descs = 3,
+		.devices = {
+			{   "Terratec Cinergy HT USB XE",
+				{ &dib0700_usb_id_table[27], NULL },
+				{ NULL },
+			},
+			{   "Pinnacle Expresscard 320cx",
+				{ &dib0700_usb_id_table[28], NULL },
+				{ NULL },
+			},
+			{   "Terratec Cinergy HT Express",
+				{ &dib0700_usb_id_table[32], NULL },
+				{ NULL },
+			},
+		},
+		.rc_interval      = DEFAULT_RC_INTERVAL,
+		.rc_key_map       = dib0700_rc_keys,
+		.rc_key_map_size  = ARRAY_SIZE(dib0700_rc_keys),
+		.rc_query         = dib0700_rc_query
 	},
 };
 
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c
index 043cada..eeef50b 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mb.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c
@@ -14,6 +14,8 @@
  */
 #include "dibusb.h"
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 static int dib3000mb_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
 {
 	struct dvb_usb_adapter *adap = fe->dvb->priv;
@@ -107,10 +109,14 @@
 static int dibusb_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
-	if (dvb_usb_device_init(intf,&dibusb1_1_properties,THIS_MODULE,NULL) == 0 ||
-		dvb_usb_device_init(intf,&dibusb1_1_an2235_properties,THIS_MODULE,NULL) == 0 ||
-		dvb_usb_device_init(intf,&dibusb2_0b_properties,THIS_MODULE,NULL) == 0 ||
-		dvb_usb_device_init(intf,&artec_t1_usb2_properties,THIS_MODULE,NULL) == 0)
+	if (0 == dvb_usb_device_init(intf, &dibusb1_1_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &dibusb1_1_an2235_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &dibusb2_0b_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &artec_t1_usb2_properties,
+				     THIS_MODULE, NULL, adapter_nr))
 		return 0;
 
 	return -EINVAL;
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mc.c b/drivers/media/dvb/dvb-usb/dibusb-mc.c
index e7ea3e7..059cec9 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mc.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mc.c
@@ -14,13 +14,16 @@
  */
 #include "dibusb.h"
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 /* USB Driver stuff */
 static struct dvb_usb_device_properties dibusb_mc_properties;
 
 static int dibusb_mc_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
-	return dvb_usb_device_init(intf,&dibusb_mc_properties,THIS_MODULE,NULL);
+	return dvb_usb_device_init(intf, &dibusb_mc_properties, THIS_MODULE,
+				   NULL, adapter_nr);
 }
 
 /* do not change the order of the ID table */
diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
index 3acbda4..b545cf3 100644
--- a/drivers/media/dvb/dvb-usb/digitv.c
+++ b/drivers/media/dvb/dvb-usb/digitv.c
@@ -20,6 +20,9 @@
 static int dvb_usb_digitv_debug;
 module_param_named(debug,dvb_usb_digitv_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 #define deb_rc(args...)   dprintk(dvb_usb_digitv_debug,0x01,args)
 
 static int digitv_ctrl_msg(struct dvb_usb_device *d,
@@ -256,8 +259,9 @@
 		const struct usb_device_id *id)
 {
 	struct dvb_usb_device *d;
-	int ret;
-	if ((ret = dvb_usb_device_init(intf,&digitv_properties,THIS_MODULE,&d)) == 0) {
+	int ret = dvb_usb_device_init(intf, &digitv_properties, THIS_MODULE, &d,
+				      adapter_nr);
+	if (ret == 0) {
 		u8 b[4] = { 0 };
 
 		if (d != NULL) { /* do that only when the firmware is loaded */
diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c
index d86cf9b..81a6cbf 100644
--- a/drivers/media/dvb/dvb-usb/dtt200u.c
+++ b/drivers/media/dvb/dvb-usb/dtt200u.c
@@ -18,6 +18,8 @@
 module_param_named(debug,dvb_usb_dtt200u_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2 (or-able))." DVB_USB_DEBUG_STATUS);
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 static int dtt200u_power_ctrl(struct dvb_usb_device *d, int onoff)
 {
 	u8 b = SET_INIT;
@@ -101,11 +103,16 @@
 static int dtt200u_usb_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
-	if (dvb_usb_device_init(intf,&dtt200u_properties,THIS_MODULE,NULL) == 0 ||
-		dvb_usb_device_init(intf,&wt220u_properties,THIS_MODULE,NULL) == 0 ||
-		dvb_usb_device_init(intf,&wt220u_fc_properties,THIS_MODULE,NULL) == 0 ||
-		dvb_usb_device_init(intf,&wt220u_zl0353_properties,THIS_MODULE,NULL) == 0 ||
-		dvb_usb_device_init(intf,&wt220u_miglia_properties,THIS_MODULE,NULL) == 0)
+	if (0 == dvb_usb_device_init(intf, &dtt200u_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &wt220u_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &wt220u_fc_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &wt220u_zl0353_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &wt220u_miglia_properties,
+				     THIS_MODULE, NULL, adapter_nr))
 		return 0;
 
 	return -ENODEV;
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-common.h b/drivers/media/dvb/dvb-usb/dvb-usb-common.h
index 35ab68f..6b7b2a8 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-common.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-common.h
@@ -40,7 +40,8 @@
 extern int dvb_usb_i2c_init(struct dvb_usb_device *);
 extern int dvb_usb_i2c_exit(struct dvb_usb_device *);
 
-extern int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap);
+extern int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap,
+				    short *adapter_nums);
 extern int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap);
 extern int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap);
 extern int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
index 4561a67..ce8cd0c 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
@@ -77,12 +77,13 @@
 	return dvb_usb_ctrl_feed(dvbdmxfeed,0);
 }
 
-int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap)
+int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums)
 {
-	int ret;
+	int ret = dvb_register_adapter(&adap->dvb_adap, adap->dev->desc->name,
+				       adap->dev->owner, &adap->dev->udev->dev,
+				       adapter_nums);
 
-	if ((ret = dvb_register_adapter(&adap->dvb_adap, adap->dev->desc->name,
-			adap->dev->owner, &adap->dev->udev->dev)) < 0) {
+	if (ret < 0) {
 		deb_info("dvb_register_adapter failed: error %d", ret);
 		goto err;
 	}
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index aa4844e..34245d1 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -40,14 +40,15 @@
 #define USB_VID_MSI				0x0db0
 #define USB_VID_OPERA1				0x695c
 #define USB_VID_PINNACLE			0x2304
+#define USB_VID_TECHNOTREND			0x0b48
 #define USB_VID_TERRATEC			0x0ccd
 #define USB_VID_VISIONPLUS			0x13d3
 #define USB_VID_TWINHAN				0x1822
 #define USB_VID_ULTIMA_ELECTRONIC		0x05d8
 #define USB_VID_UNIWILL				0x1584
 #define USB_VID_WIDEVIEW			0x14aa
-/* dom : pour gigabyte u7000 */
 #define USB_VID_GIGABYTE			0x1044
+#define USB_VID_YUAN				0x1164
 
 
 /* Product IDs */
@@ -134,10 +135,17 @@
 #define USB_PID_AVERMEDIA_EXPRESS			0xb568
 #define USB_PID_AVERMEDIA_VOLAR				0xa807
 #define USB_PID_AVERMEDIA_VOLAR_2			0xb808
+#define USB_PID_TECHNOTREND_CONNECT_S2400               0x3006
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY	0x005a
+#define USB_PID_TERRATEC_CINERGY_HT_USB_XE		0x0058
+#define USB_PID_TERRATEC_CINERGY_HT_EXPRESS		0x0060
+#define USB_PID_TERRATEC_CINERGY_T_XXS			0x0078
+#define USB_PID_PINNACLE_EXPRESSCARD_320CX		0x022e
 #define USB_PID_PINNACLE_PCTV2000E			0x022c
 #define USB_PID_PINNACLE_PCTV_DVB_T_FLASH		0x0228
 #define USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T	0x0229
+#define USB_PID_PINNACLE_PCTV72E			0x0236
+#define USB_PID_PINNACLE_PCTV73E			0x0237
 #define USB_PID_PCTV_200E				0x020e
 #define USB_PID_PCTV_400E				0x020f
 #define USB_PID_PCTV_450E				0x0222
@@ -172,6 +180,7 @@
 #define USB_PID_WINFAST_DTV_DONGLE_COLD			0x6025
 #define USB_PID_WINFAST_DTV_DONGLE_WARM			0x6026
 #define USB_PID_WINFAST_DTV_DONGLE_STK7700P		0x6f00
+#define USB_PID_WINFAST_DTV_DONGLE_STK7700P_2		0x6f01
 #define USB_PID_GENPIX_8PSK_REV_1_COLD			0x0200
 #define USB_PID_GENPIX_8PSK_REV_1_WARM			0x0201
 #define USB_PID_GENPIX_8PSK_REV_2			0x0202
@@ -183,9 +192,9 @@
 #define USB_PID_OPERA1_WARM				0x3829
 #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD		0x0514
 #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM		0x0513
-/* dom pour gigabyte u7000 */
 #define USB_PID_GIGABYTE_U7000				0x7001
 #define USB_PID_ASUS_U3000				0x171f
 #define USB_PID_ASUS_U3100				0x173f
+#define USB_PID_YUAN_EC372S				0x1edc
 
 #endif
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
index cdd717c..e331db8 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
@@ -26,7 +26,7 @@
 module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, int, 0444);
 MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a PID filter, if any (default: 0).");
 
-static int dvb_usb_adapter_init(struct dvb_usb_device *d)
+static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
 {
 	struct dvb_usb_adapter *adap;
 	int ret,n;
@@ -72,7 +72,7 @@
 		}
 
 		if ((ret = dvb_usb_adapter_stream_init(adap)) ||
-			(ret = dvb_usb_adapter_dvb_init(adap)) ||
+			(ret = dvb_usb_adapter_dvb_init(adap, adapter_nrs)) ||
 			(ret = dvb_usb_adapter_frontend_init(adap))) {
 			return ret;
 		}
@@ -122,7 +122,7 @@
 	return 0;
 }
 
-static int dvb_usb_init(struct dvb_usb_device *d)
+static int dvb_usb_init(struct dvb_usb_device *d, short *adapter_nums)
 {
 	int ret = 0;
 
@@ -143,7 +143,7 @@
 	dvb_usb_device_power_ctrl(d, 1);
 
 	if ((ret = dvb_usb_i2c_init(d)) ||
-		(ret = dvb_usb_adapter_init(d))) {
+		(ret = dvb_usb_adapter_init(d, adapter_nums))) {
 		dvb_usb_exit(d);
 		return ret;
 	}
@@ -213,8 +213,10 @@
 /*
  * USB
  */
-int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_device_properties
-		*props, struct module *owner,struct dvb_usb_device **du)
+int dvb_usb_device_init(struct usb_interface *intf,
+			struct dvb_usb_device_properties *props,
+			struct module *owner, struct dvb_usb_device **du,
+			short *adapter_nums)
 {
 	struct usb_device *udev = interface_to_usbdev(intf);
 	struct dvb_usb_device *d = NULL;
@@ -254,7 +256,7 @@
 	if (du != NULL)
 		*du = d;
 
-	ret = dvb_usb_init(d);
+	ret = dvb_usb_init(d, adapter_nums);
 
 	if (ret == 0)
 		info("%s successfully initialized and connected.",desc->name);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
index d1b3c7b..b1de0f7 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb.h
@@ -372,7 +372,10 @@
 	void *priv;
 };
 
-extern int dvb_usb_device_init(struct usb_interface *, struct dvb_usb_device_properties *, struct module *, struct dvb_usb_device **);
+extern int dvb_usb_device_init(struct usb_interface *,
+			       struct dvb_usb_device_properties *,
+			       struct module *, struct dvb_usb_device **,
+			       short *adapter_nums);
 extern void dvb_usb_device_exit(struct usb_interface *);
 
 /* the generic read/write method for device control */
diff --git a/drivers/media/dvb/dvb-usb/gl861.c b/drivers/media/dvb/dvb-usb/gl861.c
index 6b99d9f..0a8ac64 100644
--- a/drivers/media/dvb/dvb-usb/gl861.c
+++ b/drivers/media/dvb/dvb-usb/gl861.c
@@ -16,6 +16,8 @@
 module_param_named(debug,dvb_usb_gl861_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr,
 			 u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
 {
@@ -140,7 +142,9 @@
 	if (intf->num_altsetting < 2)
 		return -ENODEV;
 
-	if ((ret = dvb_usb_device_init(intf, &gl861_properties, THIS_MODULE, &d)) == 0) {
+	ret = dvb_usb_device_init(intf, &gl861_properties, THIS_MODULE, &d,
+				  adapter_nr);
+	if (ret == 0) {
 		alt = usb_altnum_to_altsetting(intf, 0);
 
 		if (alt == NULL) {
diff --git a/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/drivers/media/dvb/dvb-usb/gp8psk-fe.c
index e37142d..262a858 100644
--- a/drivers/media/dvb/dvb-usb/gp8psk-fe.c
+++ b/drivers/media/dvb/dvb-usb/gp8psk-fe.c
@@ -152,7 +152,7 @@
 {
 	struct gp8psk_fe_state *st = fe->demodulator_priv;
 
-	deb_fe("%s\n",__FUNCTION__);
+	deb_fe("%s\n",__func__);
 
 	if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, m->msg[0], 0,
 			m->msg, m->msg_len)) {
@@ -167,7 +167,7 @@
 	struct gp8psk_fe_state *st = fe->demodulator_priv;
 	u8 cmd;
 
-	deb_fe("%s\n",__FUNCTION__);
+	deb_fe("%s\n",__func__);
 
 	/* These commands are certainly wrong */
 	cmd = (burst == SEC_MINI_A) ? 0x00 : 0x01;
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c
index 83e8535..9a942af 100644
--- a/drivers/media/dvb/dvb-usb/gp8psk.c
+++ b/drivers/media/dvb/dvb-usb/gp8psk.c
@@ -22,6 +22,8 @@
 module_param_named(debug,dvb_usb_gp8psk_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
 {
 	int ret = 0,try = 0;
@@ -190,7 +192,8 @@
 {
 	int ret;
 	struct usb_device *udev = interface_to_usbdev(intf);
-	ret =  dvb_usb_device_init(intf,&gp8psk_properties,THIS_MODULE,NULL);
+	ret = dvb_usb_device_init(intf, &gp8psk_properties,
+				  THIS_MODULE, NULL, adapter_nr);
 	if (ret == 0) {
 		info("found Genpix USB device pID = %x (hex)",
 			le16_to_cpu(udev->descriptor.idProduct));
diff --git a/drivers/media/dvb/dvb-usb/m920x.c b/drivers/media/dvb/dvb-usb/m920x.c
index a956bc5..a12e6f7 100644
--- a/drivers/media/dvb/dvb-usb/m920x.c
+++ b/drivers/media/dvb/dvb-usb/m920x.c
@@ -22,6 +22,8 @@
 module_param_named(debug,dvb_usb_m920x_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 static int m920x_set_filter(struct dvb_usb_device *d, int type, int idx, int pid);
 
 static inline int m920x_read(struct usb_device *udev, u8 request, u16 value,
@@ -477,7 +479,7 @@
 /* Callbacks for DVB USB */
 static int m920x_mt352_frontend_attach(struct dvb_usb_adapter *adap)
 {
-	deb("%s\n",__FUNCTION__);
+	deb("%s\n",__func__);
 
 	if ((adap->fe = dvb_attach(mt352_attach,
 				   &m920x_mt352_config,
@@ -489,7 +491,7 @@
 
 static int m920x_tda10046_08_frontend_attach(struct dvb_usb_adapter *adap)
 {
-	deb("%s\n",__FUNCTION__);
+	deb("%s\n",__func__);
 
 	if ((adap->fe = dvb_attach(tda10046_attach,
 				   &m920x_tda10046_08_config,
@@ -501,7 +503,7 @@
 
 static int m920x_tda10046_0b_frontend_attach(struct dvb_usb_adapter *adap)
 {
-	deb("%s\n",__FUNCTION__);
+	deb("%s\n",__func__);
 
 	if ((adap->fe = dvb_attach(tda10046_attach,
 				   &m920x_tda10046_0b_config,
@@ -513,7 +515,7 @@
 
 static int m920x_qt1010_tuner_attach(struct dvb_usb_adapter *adap)
 {
-	deb("%s\n",__FUNCTION__);
+	deb("%s\n",__func__);
 
 	if (dvb_attach(qt1010_attach, adap->fe, &adap->dev->i2c_adap, &m920x_qt1010_config) == NULL)
 		return -ENODEV;
@@ -523,7 +525,7 @@
 
 static int m920x_tda8275_60_tuner_attach(struct dvb_usb_adapter *adap)
 {
-	deb("%s\n",__FUNCTION__);
+	deb("%s\n",__func__);
 
 	if (dvb_attach(tda827x_attach, adap->fe, 0x60, &adap->dev->i2c_adap, NULL) == NULL)
 		return -ENODEV;
@@ -533,7 +535,7 @@
 
 static int m920x_tda8275_61_tuner_attach(struct dvb_usb_adapter *adap)
 {
-	deb("%s\n",__FUNCTION__);
+	deb("%s\n",__func__);
 
 	if (dvb_attach(tda827x_attach, adap->fe, 0x61, &adap->dev->i2c_adap, NULL) == NULL)
 		return -ENODEV;
@@ -618,27 +620,31 @@
 		 * multi-tuner device
 		 */
 
-		if ((ret = dvb_usb_device_init(intf, &megasky_properties,
-					       THIS_MODULE, &d)) == 0) {
+		ret = dvb_usb_device_init(intf, &megasky_properties,
+					  THIS_MODULE, &d, adapter_nr);
+		if (ret == 0) {
 			rc_init_seq = megasky_rc_init;
 			goto found;
 		}
 
-		if ((ret = dvb_usb_device_init(intf, &digivox_mini_ii_properties,
-					       THIS_MODULE, &d)) == 0) {
+		ret = dvb_usb_device_init(intf, &digivox_mini_ii_properties,
+					  THIS_MODULE, &d, adapter_nr);
+		if (ret == 0) {
 			/* No remote control, so no rc_init_seq */
 			goto found;
 		}
 
 		/* This configures both tuners on the TV Walker Twin */
-		if ((ret = dvb_usb_device_init(intf, &tvwalkertwin_properties,
-					       THIS_MODULE, &d)) == 0) {
+		ret = dvb_usb_device_init(intf, &tvwalkertwin_properties,
+					  THIS_MODULE, &d, adapter_nr);
+		if (ret == 0) {
 			rc_init_seq = tvwalkertwin_rc_init;
 			goto found;
 		}
 
-		if ((ret = dvb_usb_device_init(intf, &dposh_properties,
-					       THIS_MODULE, &d)) == 0) {
+		ret = dvb_usb_device_init(intf, &dposh_properties,
+					  THIS_MODULE, &d, adapter_nr);
+		if (ret == 0) {
 			/* Remote controller not supported yet. */
 			goto found;
 		}
diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
index badc468..07fb843 100644
--- a/drivers/media/dvb/dvb-usb/nova-t-usb2.c
+++ b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
@@ -15,6 +15,8 @@
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=rc,2=eeprom (|-able))." DVB_USB_DEBUG_STATUS);
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 #define deb_rc(args...) dprintk(debug,0x01,args)
 #define deb_ee(args...) dprintk(debug,0x02,args)
 
@@ -142,7 +144,8 @@
 static int nova_t_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
-	return dvb_usb_device_init(intf,&nova_t_properties,THIS_MODULE,NULL);
+	return dvb_usb_device_init(intf, &nova_t_properties,
+				   THIS_MODULE, NULL, adapter_nr);
 }
 
 /* do not change the order of the ID table */
diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c
index 302cc67..7e32d11 100644
--- a/drivers/media/dvb/dvb-usb/opera1.c
+++ b/drivers/media/dvb/dvb-usb/opera1.c
@@ -46,6 +46,9 @@
 		 "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))."
 		 DVB_USB_DEBUG_STATUS);
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+
 static int opera1_xilinx_rw(struct usb_device *dev, u8 request, u16 value,
 			    u8 * data, u16 len, int flags)
 {
@@ -243,7 +246,7 @@
 	.mclk = 88000000UL,
 	.invert = 1,
 	.skip_reinit = 0,
-	.lock_output = STV0229_LOCKOUTPUT_0,
+	.lock_output = STV0299_LOCKOUTPUT_0,
 	.volt13_op0_op1 = STV0299_VOLT13_OP0,
 	.inittab = opera1_inittab,
 	.set_symbol_rate = opera1_stv0299_set_symbol_rate,
@@ -548,7 +551,8 @@
 		return -EINVAL;
 	}
 
-	if (dvb_usb_device_init(intf, &opera1_properties, THIS_MODULE, NULL) != 0)
+	if (0 != dvb_usb_device_init(intf, &opera1_properties,
+				     THIS_MODULE, NULL, adapter_nr))
 		return -EINVAL;
 	return 0;
 }
diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c b/drivers/media/dvb/dvb-usb/ttusb2.c
index 3b9da9c..20ca9d9 100644
--- a/drivers/media/dvb/dvb-usb/ttusb2.c
+++ b/drivers/media/dvb/dvb-usb/ttusb2.c
@@ -37,6 +37,8 @@
 module_param_named(debug,dvb_usb_ttusb2_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))." DVB_USB_DEBUG_STATUS);
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 struct ttusb2_state {
 	u8 id;
 };
@@ -145,6 +147,7 @@
 	.demod_address = 0x0e,
 	.invert = 0,
 	.diseqc_tone = 1,
+	.xtal_freq = TDA10086_XTAL_16M,
 };
 
 static int ttusb2_frontend_attach(struct dvb_usb_adapter *adap)
@@ -176,17 +179,25 @@
 
 /* DVB USB Driver stuff */
 static struct dvb_usb_device_properties ttusb2_properties;
+static struct dvb_usb_device_properties ttusb2_properties_s2400;
 
 static int ttusb2_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
-	return dvb_usb_device_init(intf,&ttusb2_properties,THIS_MODULE,NULL);
+	if (0 == dvb_usb_device_init(intf, &ttusb2_properties,
+				     THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &ttusb2_properties_s2400,
+				     THIS_MODULE, NULL, adapter_nr))
+		return 0;
+	return -ENODEV;
 }
 
 static struct usb_device_id ttusb2_table [] = {
-		{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_400E) },
-		{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_450E) },
-		{}		/* Terminating entry */
+	{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_400E) },
+	{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_450E) },
+	{ USB_DEVICE(USB_VID_TECHNOTREND,
+		USB_PID_TECHNOTREND_CONNECT_S2400) },
+	{}		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, ttusb2_table);
 
@@ -242,6 +253,54 @@
 	}
 };
 
+static struct dvb_usb_device_properties ttusb2_properties_s2400 = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl = CYPRESS_FX2,
+	.firmware = "dvb-usb-tt-s2400-01.fw",
+
+	.size_of_priv = sizeof(struct ttusb2_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.streaming_ctrl   = NULL,
+
+			.frontend_attach  = ttusb2_frontend_attach,
+			.tuner_attach     = ttusb2_tuner_attach,
+
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_ISOC,
+				.count = 5,
+				.endpoint = 0x02,
+				.u = {
+					.isoc = {
+						.framesperurb = 4,
+						.framesize = 940,
+						.interval = 1,
+					}
+				}
+			}
+		}
+	},
+
+	.power_ctrl       = ttusb2_power_ctrl,
+	.identify_state   = ttusb2_identify_state,
+
+	.i2c_algo         = &ttusb2_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "Technotrend TT-connect S-2400",
+			{ &ttusb2_table[2], NULL },
+			{ NULL },
+		},
+	}
+};
+
 static struct usb_driver ttusb2_driver = {
 	.name		= "dvb_usb_ttusb2",
 	.probe		= ttusb2_probe,
diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c
index 0dcab3d..9e7653b 100644
--- a/drivers/media/dvb/dvb-usb/umt-010.c
+++ b/drivers/media/dvb/dvb-usb/umt-010.c
@@ -13,6 +13,8 @@
 
 #include "mt352.h"
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 static int umt_mt352_demod_init(struct dvb_frontend *fe)
 {
 	static u8 mt352_clock_config[] = { 0x89, 0xb8, 0x2d };
@@ -75,7 +77,8 @@
 static int umt_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
-	if (dvb_usb_device_init(intf,&umt_properties,THIS_MODULE,NULL) == 0)
+	if (0 == dvb_usb_device_init(intf, &umt_properties,
+				     THIS_MODULE, NULL, adapter_nr))
 		return 0;
 	return -EINVAL;
 }
diff --git a/drivers/media/dvb/dvb-usb/vp702x-fe.c b/drivers/media/dvb/dvb-usb/vp702x-fe.c
index c3fdc7c..ccc7e44 100644
--- a/drivers/media/dvb/dvb-usb/vp702x-fe.c
+++ b/drivers/media/dvb/dvb-usb/vp702x-fe.c
@@ -67,7 +67,7 @@
 {
 	struct vp702x_fe_state *st = fe->demodulator_priv;
 	vp702x_fe_refresh_state(st);
-	deb_fe("%s\n",__FUNCTION__);
+	deb_fe("%s\n",__func__);
 
 	if (st->lock == 0)
 		*status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER;
@@ -121,7 +121,7 @@
 
 static int vp702x_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
 {
-	deb_fe("%s\n",__FUNCTION__);
+	deb_fe("%s\n",__func__);
 	tune->min_delay_ms = 2000;
 	return 0;
 }
@@ -183,21 +183,21 @@
 static int vp702x_fe_init(struct dvb_frontend *fe)
 {
 	struct vp702x_fe_state *st = fe->demodulator_priv;
-	deb_fe("%s\n",__FUNCTION__);
+	deb_fe("%s\n",__func__);
 	vp702x_usb_in_op(st->d, RESET_TUNER, 0, 0, NULL, 0);
 	return 0;
 }
 
 static int vp702x_fe_sleep(struct dvb_frontend *fe)
 {
-	deb_fe("%s\n",__FUNCTION__);
+	deb_fe("%s\n",__func__);
 	return 0;
 }
 
 static int vp702x_fe_get_frontend(struct dvb_frontend* fe,
 				  struct dvb_frontend_parameters *fep)
 {
-	deb_fe("%s\n",__FUNCTION__);
+	deb_fe("%s\n",__func__);
 	return 0;
 }
 
@@ -208,7 +208,7 @@
 	u8 cmd[8],ibuf[10];
 	memset(cmd,0,8);
 
-	deb_fe("%s\n",__FUNCTION__);
+	deb_fe("%s\n",__func__);
 
 	if (m->msg_len > 4)
 		return -EINVAL;
@@ -230,7 +230,7 @@
 
 static int vp702x_fe_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
 {
-	deb_fe("%s\n",__FUNCTION__);
+	deb_fe("%s\n",__func__);
 	return 0;
 }
 
@@ -238,7 +238,7 @@
 {
 	struct vp702x_fe_state *st = fe->demodulator_priv;
 	u8 ibuf[10];
-	deb_fe("%s\n",__FUNCTION__);
+	deb_fe("%s\n",__func__);
 
 	st->tone_mode = tone;
 
@@ -263,7 +263,7 @@
 {
 	struct vp702x_fe_state *st = fe->demodulator_priv;
 	u8 ibuf[10];
-	deb_fe("%s\n",__FUNCTION__);
+	deb_fe("%s\n",__func__);
 
 	st->voltage = voltage;
 
diff --git a/drivers/media/dvb/dvb-usb/vp702x.c b/drivers/media/dvb/dvb-usb/vp702x.c
index e553c13..986fff9 100644
--- a/drivers/media/dvb/dvb-usb/vp702x.c
+++ b/drivers/media/dvb/dvb-usb/vp702x.c
@@ -21,6 +21,8 @@
 module_param_named(debug,dvb_usb_vp702x_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 struct vp702x_state {
 	int pid_filter_count;
 	int pid_filter_can_bypass;
@@ -238,7 +240,8 @@
 static int vp702x_usb_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
-	return dvb_usb_device_init(intf,&vp702x_properties,THIS_MODULE,NULL);
+	return dvb_usb_device_init(intf, &vp702x_properties,
+				   THIS_MODULE, NULL, adapter_nr);
 }
 
 static struct usb_device_id vp702x_usb_table [] = {
diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c
index c172bab..acb3455 100644
--- a/drivers/media/dvb/dvb-usb/vp7045.c
+++ b/drivers/media/dvb/dvb-usb/vp7045.c
@@ -18,6 +18,9 @@
 static int dvb_usb_vp7045_debug;
 module_param_named(debug,dvb_usb_vp7045_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 #define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args)
 #define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args)
 #define deb_rc(args...)   dprintk(dvb_usb_vp7045_debug,0x04,args)
@@ -219,7 +222,8 @@
 static int vp7045_usb_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
-	return dvb_usb_device_init(intf,&vp7045_properties,THIS_MODULE,NULL);
+	return dvb_usb_device_init(intf, &vp7045_properties,
+				   THIS_MODULE, NULL, adapter_nr);
 }
 
 static struct usb_device_id vp7045_usb_table [] = {
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index 9ad86ce..68fab61 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -188,6 +188,14 @@
 	  A DVB-T tuner module. Designed for mobile usage. Say Y when you want
 	  to support this frontend.
 
+config DVB_TDA10048
+	tristate "Philips TDA10048HN based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	select FW_LOADER
+	help
+	  A DVB-T tuner module. Say Y when you want to support this frontend.
+
 comment "DVB-C (cable) frontends"
 	depends on DVB_CORE
 
@@ -291,6 +299,14 @@
 	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
 	  to support this frontend.
 
+config DVB_AU8522
+	tristate "Auvitek AU8522 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+	  to support this frontend.
+
 comment "Tuners/PLL support"
 	depends on DVB_CORE
 
@@ -369,6 +385,11 @@
 	  This device is only used inside a SiP called togther with a
 	  demodulator for now.
 
+config DVB_TUNER_ITD1000
+	tristate "Integrant ITD1000 Zero IF tuner for DVB-S/DSS"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+
 comment "Miscellaneous devices"
 	depends on DVB_CORE
 
@@ -379,6 +400,13 @@
 	help
 	  An SEC control chip.
 
+config DVB_ISL6405
+	tristate "ISL6405 SEC controller"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  An SEC control chip.
+
 config DVB_ISL6421
 	tristate "ISL6421 SEC controller"
 	depends on DVB_CORE && I2C
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 16bd107..2f873fc0 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -38,6 +38,7 @@
 obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
 obj-$(CONFIG_DVB_CX24123) += cx24123.o
 obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
+obj-$(CONFIG_DVB_ISL6405) += isl6405.o
 obj-$(CONFIG_DVB_ISL6421) += isl6421.o
 obj-$(CONFIG_DVB_TDA10086) += tda10086.o
 obj-$(CONFIG_DVB_TDA826X) += tda826x.o
@@ -51,3 +52,6 @@
 obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o
 obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
 obj-$(CONFIG_DVB_TUNER_XC5000) += xc5000.o
+obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o
+obj-$(CONFIG_DVB_AU8522) += au8522.o
+obj-$(CONFIG_DVB_TDA10048) += tda10048.o
diff --git a/drivers/media/dvb/frontends/au8522.c b/drivers/media/dvb/frontends/au8522.c
new file mode 100644
index 0000000..084a280
--- /dev/null
+++ b/drivers/media/dvb/frontends/au8522.c
@@ -0,0 +1,692 @@
+/*
+    Auvitek AU8522 QAM/8VSB demodulator driver
+
+    Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include "dvb_frontend.h"
+#include "dvb-pll.h"
+#include "au8522.h"
+
+struct au8522_state {
+
+	struct i2c_adapter *i2c;
+
+	/* configuration settings */
+	const struct au8522_config *config;
+
+	struct dvb_frontend frontend;
+
+	u32 current_frequency;
+	fe_modulation_t current_modulation;
+
+};
+
+static int debug;
+
+#define dprintk(arg...) do {		\
+	if (debug) 			\
+		 printk(arg); 		\
+	} while (0)
+
+/* 16 bit registers, 8 bit values */
+static int au8522_writereg(struct au8522_state *state, u16 reg, u8 data)
+{
+	int ret;
+	u8 buf [] = { reg >> 8, reg & 0xff, data };
+
+	struct i2c_msg msg = { .addr = state->config->demod_address,
+			       .flags = 0, .buf = buf, .len = 3 };
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+
+	if (ret != 1)
+		printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, "
+		       "ret == %i)\n", __func__, reg, data, ret);
+
+	return (ret != 1) ? -1 : 0;
+}
+
+static u8 au8522_readreg(struct au8522_state *state, u16 reg)
+{
+	int ret;
+	u8 b0 [] = { reg >> 8, reg & 0xff };
+	u8 b1 [] = { 0 };
+
+	struct i2c_msg msg [] = {
+		{ .addr = state->config->demod_address, .flags = 0,
+		  .buf = b0, .len = 2 },
+		{ .addr = state->config->demod_address, .flags = I2C_M_RD,
+		  .buf = b1, .len = 1 } };
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2)
+		printk(KERN_ERR "%s: readreg error (ret == %i)\n",
+		       __func__, ret);
+	return b1[0];
+}
+
+static int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+
+	dprintk("%s(%d)\n", __func__, enable);
+
+	if (enable)
+		return au8522_writereg(state, 0x106, 1);
+	else
+		return au8522_writereg(state, 0x106, 0);
+}
+
+struct mse2snr_tab {
+	u16 val;
+	u16 data;
+};
+
+/* VSB SNR lookup table */
+static struct mse2snr_tab vsb_mse2snr_tab[] = {
+	{   0, 270 },
+	{   2, 250 },
+	{   3, 240 },
+	{   5, 230 },
+	{   7, 220 },
+	{   9, 210 },
+	{  12, 200 },
+	{  13, 195 },
+	{  15, 190 },
+	{  17, 185 },
+	{  19, 180 },
+	{  21, 175 },
+	{  24, 170 },
+	{  27, 165 },
+	{  31, 160 },
+	{  32, 158 },
+	{  33, 156 },
+	{  36, 152 },
+	{  37, 150 },
+	{  39, 148 },
+	{  40, 146 },
+	{  41, 144 },
+	{  43, 142 },
+	{  44, 140 },
+	{  48, 135 },
+	{  50, 130 },
+	{  43, 142 },
+	{  53, 125 },
+	{  56, 120 },
+	{ 256, 115 },
+};
+
+/* QAM64 SNR lookup table */
+static struct mse2snr_tab qam64_mse2snr_tab[] = {
+	{  15,   0 },
+	{  16, 290 },
+	{  17, 288 },
+	{  18, 286 },
+	{  19, 284 },
+	{  20, 282 },
+	{  21, 281 },
+	{  22, 279 },
+	{  23, 277 },
+	{  24, 275 },
+	{  25, 273 },
+	{  26, 271 },
+	{  27, 269 },
+	{  28, 268 },
+	{  29, 266 },
+	{  30, 264 },
+	{  31, 262 },
+	{  32, 260 },
+	{  33, 259 },
+	{  34, 258 },
+	{  35, 256 },
+	{  36, 255 },
+	{  37, 254 },
+	{  38, 252 },
+	{  39, 251 },
+	{  40, 250 },
+	{  41, 249 },
+	{  42, 248 },
+	{  43, 246 },
+	{  44, 245 },
+	{  45, 244 },
+	{  46, 242 },
+	{  47, 241 },
+	{  48, 240 },
+	{  50, 239 },
+	{  51, 238 },
+	{  53, 237 },
+	{  54, 236 },
+	{  56, 235 },
+	{  57, 234 },
+	{  59, 233 },
+	{  60, 232 },
+	{  62, 231 },
+	{  63, 230 },
+	{  65, 229 },
+	{  67, 228 },
+	{  68, 227 },
+	{  70, 226 },
+	{  71, 225 },
+	{  73, 224 },
+	{  74, 223 },
+	{  76, 222 },
+	{  78, 221 },
+	{  80, 220 },
+	{  82, 219 },
+	{  85, 218 },
+	{  88, 217 },
+	{  90, 216 },
+	{  92, 215 },
+	{  93, 214 },
+	{  94, 212 },
+	{  95, 211 },
+	{  97, 210 },
+	{  99, 209 },
+	{ 101, 208 },
+	{ 102, 207 },
+	{ 104, 206 },
+	{ 107, 205 },
+	{ 111, 204 },
+	{ 114, 203 },
+	{ 118, 202 },
+	{ 122, 201 },
+	{ 125, 200 },
+	{ 128, 199 },
+	{ 130, 198 },
+	{ 132, 197 },
+	{ 256, 190 },
+};
+
+/* QAM256 SNR lookup table */
+static struct mse2snr_tab qam256_mse2snr_tab[] = {
+	{  16,   0 },
+	{  17, 400 },
+	{  18, 398 },
+	{  19, 396 },
+	{  20, 394 },
+	{  21, 392 },
+	{  22, 390 },
+	{  23, 388 },
+	{  24, 386 },
+	{  25, 384 },
+	{  26, 382 },
+	{  27, 380 },
+	{  28, 379 },
+	{  29, 378 },
+	{  30, 377 },
+	{  31, 376 },
+	{  32, 375 },
+	{  33, 374 },
+	{  34, 373 },
+	{  35, 372 },
+	{  36, 371 },
+	{  37, 370 },
+	{  38, 362 },
+	{  39, 354 },
+	{  40, 346 },
+	{  41, 338 },
+	{  42, 330 },
+	{  43, 328 },
+	{  44, 326 },
+	{  45, 324 },
+	{  46, 322 },
+	{  47, 320 },
+	{  48, 319 },
+	{  49, 318 },
+	{  50, 317 },
+	{  51, 316 },
+	{  52, 315 },
+	{  53, 314 },
+	{  54, 313 },
+	{  55, 312 },
+	{  56, 311 },
+	{  57, 310 },
+	{  58, 308 },
+	{  59, 306 },
+	{  60, 304 },
+	{  61, 302 },
+	{  62, 300 },
+	{  63, 298 },
+	{  65, 295 },
+	{  68, 294 },
+	{  70, 293 },
+	{  73, 292 },
+	{  76, 291 },
+	{  78, 290 },
+	{  79, 289 },
+	{  81, 288 },
+	{  82, 287 },
+	{  83, 286 },
+	{  84, 285 },
+	{  85, 284 },
+	{  86, 283 },
+	{  88, 282 },
+	{  89, 281 },
+	{ 256, 280 },
+};
+
+static int au8522_mse2snr_lookup(struct mse2snr_tab *tab, int sz, int mse,
+				 u16 *snr)
+{
+	int i, ret = -EINVAL;
+	dprintk("%s()\n", __func__);
+
+	for (i = 0; i < sz; i++) {
+		if (mse < tab[i].val) {
+			*snr = tab[i].data;
+			ret = 0;
+			break;
+		}
+	}
+	dprintk("%s() snr=%d\n", __func__, *snr);
+	return ret;
+}
+
+/* VSB Modulation table */
+static struct {
+	u16 reg;
+	u16 data;
+} VSB_mod_tab[] = {
+	{ 0x8090, 0x84 },
+	{ 0x4092, 0x11 },
+	{ 0x2005, 0x00 },
+	{ 0x8091, 0x80 },
+	{ 0x80a3, 0x0c },
+	{ 0x80a4, 0xe8 },
+	{ 0x8081, 0xc4 },
+	{ 0x80a5, 0x40 },
+	{ 0x80a7, 0x40 },
+	{ 0x80a6, 0x67 },
+	{ 0x8262, 0x20 },
+	{ 0x821c, 0x30 },
+	{ 0x80d8, 0x1a },
+	{ 0x8227, 0xa0 },
+	{ 0x8121, 0xff },
+	{ 0x80a8, 0xf0 },
+	{ 0x80a9, 0x05 },
+	{ 0x80aa, 0x77 },
+	{ 0x80ab, 0xf0 },
+	{ 0x80ac, 0x05 },
+	{ 0x80ad, 0x77 },
+	{ 0x80ae, 0x41 },
+	{ 0x80af, 0x66 },
+	{ 0x821b, 0xcc },
+	{ 0x821d, 0x80 },
+	{ 0x80b5, 0xfb },
+	{ 0x80b6, 0x8e },
+	{ 0x80b7, 0x39 },
+	{ 0x80a4, 0xe8 },
+	{ 0x8231, 0x13 },
+};
+
+/* QAM Modulation table */
+static struct {
+	u16 reg;
+	u16 data;
+} QAM_mod_tab[] = {
+	{ 0x80a3, 0x09 },
+	{ 0x80a4, 0x00 },
+	{ 0x8081, 0xc4 },
+	{ 0x80a5, 0x40 },
+	{ 0x80b5, 0xfb },
+	{ 0x80b6, 0x8e },
+	{ 0x80b7, 0x39 },
+	{ 0x80aa, 0x77 },
+	{ 0x80ad, 0x77 },
+	{ 0x80a6, 0x67 },
+	{ 0x8262, 0x20 },
+	{ 0x821c, 0x30 },
+	{ 0x80b8, 0x3e },
+	{ 0x80b9, 0xf0 },
+	{ 0x80ba, 0x01 },
+	{ 0x80bb, 0x18 },
+	{ 0x80bc, 0x50 },
+	{ 0x80bd, 0x00 },
+	{ 0x80be, 0xea },
+	{ 0x80bf, 0xef },
+	{ 0x80c0, 0xfc },
+	{ 0x80c1, 0xbd },
+	{ 0x80c2, 0x1f },
+	{ 0x80c3, 0xfc },
+	{ 0x80c4, 0xdd },
+	{ 0x80c5, 0xaf },
+	{ 0x80c6, 0x00 },
+	{ 0x80c7, 0x38 },
+	{ 0x80c8, 0x30 },
+	{ 0x80c9, 0x05 },
+	{ 0x80ca, 0x4a },
+	{ 0x80cb, 0xd0 },
+	{ 0x80cc, 0x01 },
+	{ 0x80cd, 0xd9 },
+	{ 0x80ce, 0x6f },
+	{ 0x80cf, 0xf9 },
+	{ 0x80d0, 0x70 },
+	{ 0x80d1, 0xdf },
+	{ 0x80d2, 0xf7 },
+	{ 0x80d3, 0xc2 },
+	{ 0x80d4, 0xdf },
+	{ 0x80d5, 0x02 },
+	{ 0x80d6, 0x9a },
+	{ 0x80d7, 0xd0 },
+	{ 0x8250, 0x0d },
+	{ 0x8251, 0xcd },
+	{ 0x8252, 0xe0 },
+	{ 0x8253, 0x05 },
+	{ 0x8254, 0xa7 },
+	{ 0x8255, 0xff },
+	{ 0x8256, 0xed },
+	{ 0x8257, 0x5b },
+	{ 0x8258, 0xae },
+	{ 0x8259, 0xe6 },
+	{ 0x825a, 0x3d },
+	{ 0x825b, 0x0f },
+	{ 0x825c, 0x0d },
+	{ 0x825d, 0xea },
+	{ 0x825e, 0xf2 },
+	{ 0x825f, 0x51 },
+	{ 0x8260, 0xf5 },
+	{ 0x8261, 0x06 },
+	{ 0x821a, 0x00 },
+	{ 0x8546, 0x40 },
+	{ 0x8210, 0x26 },
+	{ 0x8211, 0xf6 },
+	{ 0x8212, 0x84 },
+	{ 0x8213, 0x02 },
+	{ 0x8502, 0x01 },
+	{ 0x8121, 0x04 },
+	{ 0x8122, 0x04 },
+	{ 0x852e, 0x10 },
+	{ 0x80a4, 0xca },
+	{ 0x80a7, 0x40 },
+	{ 0x8526, 0x01 },
+};
+
+static int au8522_enable_modulation(struct dvb_frontend *fe,
+				    fe_modulation_t m)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+	int i;
+
+	dprintk("%s(0x%08x)\n", __func__, m);
+
+	switch (m) {
+	case VSB_8:
+		dprintk("%s() VSB_8\n", __func__);
+		for (i = 0; i < ARRAY_SIZE(VSB_mod_tab); i++)
+			au8522_writereg(state,
+				VSB_mod_tab[i].reg,
+				VSB_mod_tab[i].data);
+		break;
+	case QAM_64:
+	case QAM_256:
+		dprintk("%s() QAM 64/256\n", __func__);
+		for (i = 0; i < ARRAY_SIZE(QAM_mod_tab); i++)
+			au8522_writereg(state,
+				QAM_mod_tab[i].reg,
+				QAM_mod_tab[i].data);
+		break;
+	default:
+		dprintk("%s() Invalid modulation\n", __func__);
+		return -EINVAL;
+	}
+
+	state->current_modulation = m;
+
+	return 0;
+}
+
+/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
+static int au8522_set_frontend(struct dvb_frontend *fe,
+			       struct dvb_frontend_parameters *p)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+
+	dprintk("%s(frequency=%d)\n", __func__, p->frequency);
+
+	state->current_frequency = p->frequency;
+
+	au8522_enable_modulation(fe, p->u.vsb.modulation);
+
+	/* Allow the demod to settle */
+	msleep(100);
+
+	if (fe->ops.tuner_ops.set_params) {
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+		fe->ops.tuner_ops.set_params(fe, p);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	return 0;
+}
+
+/* Reset the demod hardware and reset all of the configuration registers
+   to a default state. */
+static int au8522_init(struct dvb_frontend *fe)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+	dprintk("%s()\n", __func__);
+
+	au8522_writereg(state, 0xa4, 1 << 5);
+
+	au8522_i2c_gate_ctrl(fe, 1);
+
+	return 0;
+}
+
+static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+	u8 reg;
+	u32 tuner_status = 0;
+
+	*status = 0;
+
+	if (state->current_modulation == VSB_8) {
+		dprintk("%s() Checking VSB_8\n", __func__);
+		reg = au8522_readreg(state, 0x4088);
+		if (reg & 0x01)
+			*status |= FE_HAS_VITERBI;
+		if (reg & 0x02)
+			*status |= FE_HAS_LOCK | FE_HAS_SYNC;
+	} else {
+		dprintk("%s() Checking QAM\n", __func__);
+		reg = au8522_readreg(state, 0x4541);
+		if (reg & 0x80)
+			*status |= FE_HAS_VITERBI;
+		if (reg & 0x20)
+			*status |= FE_HAS_LOCK | FE_HAS_SYNC;
+	}
+
+	switch (state->config->status_mode) {
+	case AU8522_DEMODLOCKING:
+		dprintk("%s() DEMODLOCKING\n", __func__);
+		if (*status & FE_HAS_VITERBI)
+			*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+		break;
+	case AU8522_TUNERLOCKING:
+		/* Get the tuner status */
+		dprintk("%s() TUNERLOCKING\n", __func__);
+		if (fe->ops.tuner_ops.get_status) {
+			if (fe->ops.i2c_gate_ctrl)
+				fe->ops.i2c_gate_ctrl(fe, 1);
+
+			fe->ops.tuner_ops.get_status(fe, &tuner_status);
+
+			if (fe->ops.i2c_gate_ctrl)
+				fe->ops.i2c_gate_ctrl(fe, 0);
+		}
+		if (tuner_status)
+			*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+		break;
+	}
+
+	dprintk("%s() status 0x%08x\n", __func__, *status);
+
+	return 0;
+}
+
+static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+	int ret = -EINVAL;
+
+	dprintk("%s()\n", __func__);
+
+	if (state->current_modulation == QAM_256)
+		ret = au8522_mse2snr_lookup(qam256_mse2snr_tab,
+					    ARRAY_SIZE(qam256_mse2snr_tab),
+					    au8522_readreg(state, 0x4522),
+					    snr);
+	else if (state->current_modulation == QAM_64)
+		ret = au8522_mse2snr_lookup(qam64_mse2snr_tab,
+					    ARRAY_SIZE(qam64_mse2snr_tab),
+					    au8522_readreg(state, 0x4522),
+					    snr);
+	else /* VSB_8 */
+		ret = au8522_mse2snr_lookup(vsb_mse2snr_tab,
+					    ARRAY_SIZE(vsb_mse2snr_tab),
+					    au8522_readreg(state, 0x4311),
+					    snr);
+
+	return ret;
+}
+
+static int au8522_read_signal_strength(struct dvb_frontend *fe,
+				       u16 *signal_strength)
+{
+	return au8522_read_snr(fe, signal_strength);
+}
+
+static int au8522_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+
+	if (state->current_modulation == VSB_8)
+		*ucblocks = au8522_readreg(state, 0x4087);
+	else
+		*ucblocks = au8522_readreg(state, 0x4543);
+
+	return 0;
+}
+
+static int au8522_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	return au8522_read_ucblocks(fe, ber);
+}
+
+static int au8522_get_frontend(struct dvb_frontend *fe,
+				struct dvb_frontend_parameters *p)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+
+	p->frequency = state->current_frequency;
+	p->u.vsb.modulation = state->current_modulation;
+
+	return 0;
+}
+
+static int au8522_get_tune_settings(struct dvb_frontend *fe,
+				    struct dvb_frontend_tune_settings *tune)
+{
+	tune->min_delay_ms = 1000;
+	return 0;
+}
+
+static void au8522_release(struct dvb_frontend *fe)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops au8522_ops;
+
+struct dvb_frontend *au8522_attach(const struct au8522_config *config,
+				   struct i2c_adapter *i2c)
+{
+	struct au8522_state *state = NULL;
+
+	/* allocate memory for the internal state */
+	state = kmalloc(sizeof(struct au8522_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &au8522_ops,
+	       sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+
+	if (au8522_init(&state->frontend) != 0) {
+		printk(KERN_ERR "%s: Failed to initialize correctly\n",
+			__func__);
+		goto error;
+	}
+
+	/* Note: Leaving the I2C gate open here. */
+	au8522_i2c_gate_ctrl(&state->frontend, 1);
+
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(au8522_attach);
+
+static struct dvb_frontend_ops au8522_ops = {
+
+	.info = {
+		.name			= "Auvitek AU8522 QAM/8VSB Frontend",
+		.type			= FE_ATSC,
+		.frequency_min		= 54000000,
+		.frequency_max		= 858000000,
+		.frequency_stepsize	= 62500,
+		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+	},
+
+	.init                 = au8522_init,
+	.i2c_gate_ctrl        = au8522_i2c_gate_ctrl,
+	.set_frontend         = au8522_set_frontend,
+	.get_frontend         = au8522_get_frontend,
+	.get_tune_settings    = au8522_get_tune_settings,
+	.read_status          = au8522_read_status,
+	.read_ber             = au8522_read_ber,
+	.read_signal_strength = au8522_read_signal_strength,
+	.read_snr             = au8522_read_snr,
+	.read_ucblocks        = au8522_read_ucblocks,
+	.release              = au8522_release,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+
+MODULE_DESCRIPTION("Auvitek AU8522 QAM-B/ATSC Demodulator driver");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/au8522.h b/drivers/media/dvb/frontends/au8522.h
new file mode 100644
index 0000000..d7affa3
--- /dev/null
+++ b/drivers/media/dvb/frontends/au8522.h
@@ -0,0 +1,56 @@
+/*
+    Auvitek AU8522 QAM/8VSB demodulator driver
+
+    Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __AU8522_H__
+#define __AU8522_H__
+
+#include <linux/dvb/frontend.h>
+
+struct au8522_config {
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* Return lock status based on tuner lock, or demod lock */
+#define AU8522_TUNERLOCKING 0
+#define AU8522_DEMODLOCKING 1
+	u8 status_mode;
+};
+
+#if defined(CONFIG_DVB_AU8522) || 				\
+	    (defined(CONFIG_DVB_AU8522_MODULE) && defined(MODULE))
+extern struct dvb_frontend *au8522_attach(const struct au8522_config *config,
+					  struct i2c_adapter *i2c);
+#else
+static inline
+struct dvb_frontend *au8522_attach(const struct au8522_config *config,
+				   struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_AU8522 */
+
+#endif /* __AU8522_H__ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
diff --git a/drivers/media/dvb/frontends/bcm3510.c b/drivers/media/dvb/frontends/bcm3510.c
index a913f49..d268e65 100644
--- a/drivers/media/dvb/frontends/bcm3510.c
+++ b/drivers/media/dvb/frontends/bcm3510.c
@@ -91,7 +91,7 @@
 	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
 
 		deb_info("%s: i2c write error (addr %02x, reg %02x, err == %i)\n",
-			__FUNCTION__, state->config->demod_address, reg,  err);
+			__func__, state->config->demod_address, reg,  err);
 		return -EREMOTEIO;
 	}
 
@@ -110,7 +110,7 @@
 
 	if ((err = i2c_transfer (state->i2c, msg, 2)) != 2) {
 		deb_info("%s: i2c read error (addr %02x, reg %02x, err == %i)\n",
-			__FUNCTION__, state->config->demod_address, reg,  err);
+			__func__, state->config->demod_address, reg,  err);
 		return -EREMOTEIO;
 	}
 	deb_i2c("i2c rd %02x: ",reg);
diff --git a/drivers/media/dvb/frontends/bcm3510.h b/drivers/media/dvb/frontends/bcm3510.h
index 7e4f95e..f4575c0 100644
--- a/drivers/media/dvb/frontends/bcm3510.h
+++ b/drivers/media/dvb/frontends/bcm3510.h
@@ -41,7 +41,7 @@
 static inline struct dvb_frontend* bcm3510_attach(const struct bcm3510_config* config,
 						  struct i2c_adapter* i2c)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_BCM3510
diff --git a/drivers/media/dvb/frontends/bsbe1.h b/drivers/media/dvb/frontends/bsbe1.h
index d8f6573..5e431eb 100644
--- a/drivers/media/dvb/frontends/bsbe1.h
+++ b/drivers/media/dvb/frontends/bsbe1.h
@@ -1,5 +1,5 @@
 /*
- * bsbe1.h - ALPS BSBE1 tuner support (moved from av7110.c)
+ * bsbe1.h - ALPS BSBE1 tuner support
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -26,44 +26,24 @@
 #define BSBE1_H
 
 static u8 alps_bsbe1_inittab[] = {
-	0x01, 0x15,
-	0x02, 0x30,
-	0x03, 0x00,
+	0x01, 0x15,   /* XTAL = 4MHz, VCO = 352 MHz */
+	0x02, 0x30,   /* MCLK = 88 MHz */
+	0x03, 0x00,   /* ACR output 0 */
 	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 */
+	0x05, 0x05,   /* I2CT = 0, SCLT = 1, SDAT = 1 */
+	0x06, 0x00,   /* DAC output 0 */
 	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,
+	0x0c, 0x51,   /* OP1/OP0 normal, val = 1 (LNB power on) */
+	0x0d, 0x82,   /* DC offset compensation = on, beta_agc1 = 2 */
+	0x0f, 0x92,   /* AGC1R */
+	0x10, 0x34,   /* AGC2O */
+	0x11, 0x84,   /* TLSR */
+	0x12, 0xb9,   /* CFD */
+	0x15, 0xc9,   /* lock detector threshold */
+	0x28, 0x00,   /* out imp: normal, type: parallel, FEC mode: QPSK */
+	0x33, 0xfc,   /* RS control */
+	0x34, 0x93,   /* count viterbi bit errors per 2E18 bytes */
 	0xff, 0xff
 };
 
@@ -100,11 +80,11 @@
 	if ((params->frequency < 950000) || (params->frequency > 2150000))
 		return -EINVAL;
 
-	div = (params->frequency + (125 - 1)) / 125; // round correctly
+	div = params->frequency / 1000;
 	data[0] = (div >> 8) & 0x7f;
 	data[1] = div & 0xff;
-	data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
-	data[3] = (params->frequency > 1530000) ? 0xE0 : 0xE4;
+	data[2] = 0x80 | ((div & 0x18000) >> 10) | 0x1;
+	data[3] = 0xe0;
 
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
diff --git a/drivers/media/dvb/frontends/bsru6.h b/drivers/media/dvb/frontends/bsru6.h
index e231cd8..45a6dfd 100644
--- a/drivers/media/dvb/frontends/bsru6.h
+++ b/drivers/media/dvb/frontends/bsru6.h
@@ -133,7 +133,7 @@
 	.mclk = 88000000UL,
 	.invert = 1,
 	.skip_reinit = 0,
-	.lock_output = STV0229_LOCKOUTPUT_1,
+	.lock_output = STV0299_LOCKOUTPUT_1,
 	.volt13_op0_op1 = STV0299_VOLT13_OP1,
 	.min_delay_ms = 100,
 	.set_symbol_rate = alps_bsru6_set_symbol_rate,
diff --git a/drivers/media/dvb/frontends/cx22700.c b/drivers/media/dvb/frontends/cx22700.c
index 11a4968..ace5cb1 100644
--- a/drivers/media/dvb/frontends/cx22700.c
+++ b/drivers/media/dvb/frontends/cx22700.c
@@ -73,13 +73,13 @@
 	u8 buf [] = { reg, data };
 	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	ret = i2c_transfer (state->i2c, &msg, 1);
 
 	if (ret != 1)
 		printk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
-			__FUNCTION__, reg, data, ret);
+			__func__, reg, data, ret);
 
 	return (ret != 1) ? -1 : 0;
 }
@@ -92,7 +92,7 @@
 	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
 			   { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	ret = i2c_transfer (state->i2c, msg, 2);
 
@@ -105,7 +105,7 @@
 {
 	u8 val;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	switch (inversion) {
 	case INVERSION_AUTO:
@@ -127,7 +127,7 @@
 	static const u8 fec_tab [6] = { 0, 1, 2, 0, 3, 4 };
 	u8 val;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	if (p->code_rate_HP < FEC_1_2 || p->code_rate_HP > FEC_7_8)
 		return -EINVAL;
@@ -191,7 +191,7 @@
 						    FEC_5_6, FEC_7_8 };
 	u8 val;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	if (!(cx22700_readreg(state, 0x07) & 0x20))  /*  tps valid? */
 		return -EAGAIN;
diff --git a/drivers/media/dvb/frontends/cx22700.h b/drivers/media/dvb/frontends/cx22700.h
index 7ac3369..4757a93 100644
--- a/drivers/media/dvb/frontends/cx22700.h
+++ b/drivers/media/dvb/frontends/cx22700.h
@@ -38,7 +38,7 @@
 static inline struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
 					   struct i2c_adapter* i2c)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_CX22700
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
index 1dc164d..cc1db4e 100644
--- a/drivers/media/dvb/frontends/cx22702.c
+++ b/drivers/media/dvb/frontends/cx22702.c
@@ -48,7 +48,7 @@
 	u8 prevUCBlocks;
 };
 
-static int debug = 0;
+static int debug;
 #define dprintk	if (debug) printk
 
 /* Register values to initialise the demod */
@@ -90,7 +90,7 @@
 
 	if (ret != 1)
 		printk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
-			__FUNCTION__, reg, data, ret);
+			__func__, reg, data, ret);
 
 	return (ret != 1) ? -1 : 0;
 }
@@ -108,7 +108,7 @@
 	ret = i2c_transfer(state->i2c, msg, 2);
 
 	if (ret != 2)
-		printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
+		printk("%s: readreg error (ret == %i)\n", __func__, ret);
 
 	return b1[0];
 }
@@ -195,7 +195,7 @@
 static int cx22702_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
 {
 	struct cx22702_state* state = fe->demodulator_priv;
-	dprintk ("%s(%d)\n", __FUNCTION__, enable);
+	dprintk ("%s(%d)\n", __func__, enable);
 	if (enable)
 		return cx22702_writereg (state, 0x0D, cx22702_readreg(state, 0x0D) & 0xfe);
 	else
@@ -228,7 +228,7 @@
 		cx22702_writereg(state, 0x0C, cx22702_readreg(state, 0x0C) &0xcf );
 		break;
 	default:
-		dprintk ("%s: invalid bandwidth\n",__FUNCTION__);
+		dprintk ("%s: invalid bandwidth\n",__func__);
 		return -EINVAL;
 	}
 
@@ -250,7 +250,7 @@
 		cx22702_writereg(state, 0x0B, cx22702_readreg(state, 0x0B) & 0xfc );
 		cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40 );
 		cx22702_writereg(state, 0x00, 0x01); /* Begin aquisition */
-		dprintk("%s: Autodetecting\n",__FUNCTION__);
+		dprintk("%s: Autodetecting\n",__func__);
 		return 0;
 	}
 
@@ -261,7 +261,7 @@
 		case QAM_16: val = (val&0xe7)|0x08; break;
 		case QAM_64: val = (val&0xe7)|0x10; break;
 		default:
-			dprintk ("%s: invalid constellation\n",__FUNCTION__);
+			dprintk ("%s: invalid constellation\n",__func__);
 			return -EINVAL;
 	}
 	switch(p->u.ofdm.hierarchy_information) {
@@ -270,7 +270,7 @@
 		case    HIERARCHY_2: val = (val&0xf8)|2; break;
 		case    HIERARCHY_4: val = (val&0xf8)|3; break;
 		default:
-			dprintk ("%s: invalid hierarchy\n",__FUNCTION__);
+			dprintk ("%s: invalid hierarchy\n",__func__);
 			return -EINVAL;
 	}
 	cx22702_writereg (state, 0x06, val);
@@ -284,7 +284,7 @@
 		case FEC_5_6: val = (val&0xc7)|0x18; break;
 		case FEC_7_8: val = (val&0xc7)|0x20; break;
 		default:
-			dprintk ("%s: invalid code_rate_HP\n",__FUNCTION__);
+			dprintk ("%s: invalid code_rate_HP\n",__func__);
 			return -EINVAL;
 	}
 	switch(p->u.ofdm.code_rate_LP) {
@@ -295,7 +295,7 @@
 		case FEC_5_6: val = (val&0xf8)|3; break;
 		case FEC_7_8: val = (val&0xf8)|4; break;
 		default:
-			dprintk ("%s: invalid code_rate_LP\n",__FUNCTION__);
+			dprintk ("%s: invalid code_rate_LP\n",__func__);
 			return -EINVAL;
 	}
 	cx22702_writereg (state, 0x07, val);
@@ -307,14 +307,14 @@
 		case  GUARD_INTERVAL_1_8: val = (val&0xf3)|0x08; break;
 		case  GUARD_INTERVAL_1_4: val = (val&0xf3)|0x0c; break;
 		default:
-			dprintk ("%s: invalid guard_interval\n",__FUNCTION__);
+			dprintk ("%s: invalid guard_interval\n",__func__);
 			return -EINVAL;
 	}
 	switch(p->u.ofdm.transmission_mode) {
 		case TRANSMISSION_MODE_2K: val = (val&0xfc); break;
 		case TRANSMISSION_MODE_8K: val = (val&0xfc)|1; break;
 		default:
-			dprintk ("%s: invalid transmission_mode\n",__FUNCTION__);
+			dprintk ("%s: invalid transmission_mode\n",__func__);
 			return -EINVAL;
 	}
 	cx22702_writereg(state, 0x08, val);
@@ -360,7 +360,7 @@
 	reg23 = cx22702_readreg (state, 0x23);
 
 	dprintk ("%s: status demod=0x%02x agc=0x%02x\n"
-		,__FUNCTION__,reg0A,reg23);
+		,__func__,reg0A,reg23);
 
 	if(reg0A & 0x10) {
 		*status |= FE_HAS_LOCK;
diff --git a/drivers/media/dvb/frontends/cx22702.h b/drivers/media/dvb/frontends/cx22702.h
index 9cd64da..8af766a 100644
--- a/drivers/media/dvb/frontends/cx22702.h
+++ b/drivers/media/dvb/frontends/cx22702.h
@@ -48,7 +48,7 @@
 static inline struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
 					   struct i2c_adapter* i2c)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_CX22702
diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c
index b03d828..87ae29d 100644
--- a/drivers/media/dvb/frontends/cx24110.c
+++ b/drivers/media/dvb/frontends/cx24110.c
@@ -121,7 +121,7 @@
 
 	if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
 		dprintk ("%s: writereg error (err == %i, reg == 0x%02x,"
-			 " data == 0x%02x)\n", __FUNCTION__, err, reg, data);
+			 " data == 0x%02x)\n", __func__, err, reg, data);
 		return -EREMOTEIO;
 	}
 
@@ -247,7 +247,7 @@
 	static const u32 bands[]={5000000UL,15000000UL,90999000UL/2};
 	int i;
 
-	dprintk("cx24110 debug: entering %s(%d)\n",__FUNCTION__,srate);
+	dprintk("cx24110 debug: entering %s(%d)\n",__func__,srate);
 	if (srate>90999000UL/2)
 		srate=90999000UL/2;
 	if (srate<500000)
@@ -358,7 +358,7 @@
 /* fixme (low): error handling */
 	int i;
 
-	dprintk("%s: init chip\n", __FUNCTION__);
+	dprintk("%s: init chip\n", __func__);
 
 	for(i = 0; i < ARRAY_SIZE(cx24110_regdata); i++) {
 		cx24110_writereg(state, cx24110_regdata[i].reg, cx24110_regdata[i].data);
diff --git a/drivers/media/dvb/frontends/cx24110.h b/drivers/media/dvb/frontends/cx24110.h
index 0ca3af4..1792adb 100644
--- a/drivers/media/dvb/frontends/cx24110.h
+++ b/drivers/media/dvb/frontends/cx24110.h
@@ -48,7 +48,7 @@
 static inline struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
 						  struct i2c_adapter* i2c)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_CX24110
diff --git a/drivers/media/dvb/frontends/cx24113.h b/drivers/media/dvb/frontends/cx24113.h
new file mode 100644
index 0000000..5ab3dd1
--- /dev/null
+++ b/drivers/media/dvb/frontends/cx24113.h
@@ -0,0 +1,48 @@
+/*
+ *  Driver for Conexant CX24113/CX24128 Tuner (Satelite)
+ *
+ *  Copyright (C) 2007-8 Patrick Boettcher <pb@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef CX24113_H
+#define CX24113_H
+
+struct dvb_frontend;
+
+struct cx24113_config {
+	u8 i2c_addr; /* 0x14 or 0x54 */
+
+	u32 xtal_khz;
+};
+
+/* TODO: #if defined(CONFIG_DVB_TUNER_CX24113) || \
+ * (defined(CONFIG_DVB_TUNER_CX24113_MODULE) && defined(MODULE)) */
+
+static inline struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe,
+	const struct cx24113_config *config, struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+static inline void cx24113_agc_callback(struct dvb_frontend *fe)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+}
+
+#endif /* CX24113_H */
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
index d74fdbd..7f68d78 100644
--- a/drivers/media/dvb/frontends/cx24123.c
+++ b/drivers/media/dvb/frontends/cx24123.c
@@ -1,24 +1,26 @@
 /*
-    Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver
-
-    Copyright (C) 2005 Steven Toth <stoth@hauppauge.com>
-
-    Support for KWorld DVB-S 100 by Vadim Catana <skystar@moldova.cc>
-
-    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.
-*/
+ *   Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver
+ *
+ *   Copyright (C) 2005 Steven Toth <stoth@hauppauge.com>
+ *
+ *   Support for KWorld DVB-S 100 by Vadim Catana <skystar@moldova.cc>
+ *
+ *   Support for CX24123/CX24113-NIM by Patrick Boettcher <pb@linuxtv.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/slab.h>
 #include <linux/kernel.h>
@@ -32,9 +34,16 @@
 
 static int force_band;
 static int debug;
+
+#define info(args...) do { printk(KERN_INFO "CX24123: " args); } while (0)
+#define err(args...)  do { printk(KERN_ERR  "CX24123: " args); } while (0)
+
 #define dprintk(args...) \
 	do { \
-		if (debug) printk (KERN_DEBUG "cx24123: " args); \
+		if (debug) { \
+			printk(KERN_DEBUG "CX24123: %s: ", __func__); \
+			printk(args); \
+		} \
 	} while (0)
 
 struct cx24123_state
@@ -51,6 +60,10 @@
 	u32 pllarg;
 	u32 FILTune;
 
+	struct i2c_adapter tuner_i2c_adapter;
+
+	u8 demod_rev;
+
 	/* The Demod/Tuner can't easily provide these, we cache them */
 	u32 currentfreq;
 	u32 currentsymbolrate;
@@ -225,48 +238,52 @@
 	{0x67, 0x83}, /* Non-DCII symbol clock */
 };
 
-static int cx24123_writereg(struct cx24123_state* state, int reg, int data)
+static int cx24123_i2c_writereg(struct cx24123_state *state,
+	u8 i2c_addr, int reg, int data)
 {
 	u8 buf[] = { reg, data };
-	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+	struct i2c_msg msg = {
+		.addr = i2c_addr, .flags = 0, .buf = buf, .len = 2
+	};
 	int err;
 
-	if (debug>1)
-		printk("cx24123: %s:  write reg 0x%02x, value 0x%02x\n",
-						__FUNCTION__,reg, data);
+	/* printk(KERN_DEBUG "wr(%02x): %02x %02x\n", i2c_addr, reg, data); */
 
 	if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
 		printk("%s: writereg error(err == %i, reg == 0x%02x,"
-			 " data == 0x%02x)\n", __FUNCTION__, err, reg, data);
-		return -EREMOTEIO;
+			 " data == 0x%02x)\n", __func__, err, reg, data);
+		return err;
 	}
 
 	return 0;
 }
 
-static int cx24123_readreg(struct cx24123_state* state, u8 reg)
+static int cx24123_i2c_readreg(struct cx24123_state *state, u8 i2c_addr, u8 reg)
 {
 	int ret;
-	u8 b0[] = { reg };
-	u8 b1[] = { 0 };
+	u8 b = 0;
 	struct i2c_msg msg[] = {
-		{ .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
-		{ .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 }
+		{ .addr = i2c_addr, .flags = 0, .buf = &reg, .len = 1 },
+		{ .addr = i2c_addr, .flags = I2C_M_RD, .buf = &b, .len = 1 }
 	};
 
 	ret = i2c_transfer(state->i2c, msg, 2);
 
 	if (ret != 2) {
-		printk("%s: reg=0x%x (error=%d)\n", __FUNCTION__, reg, ret);
+		err("%s: reg=0x%x (error=%d)\n", __func__, reg, ret);
 		return ret;
 	}
 
-	if (debug>1)
-		printk("cx24123: read reg 0x%02x, value 0x%02x\n",reg, ret);
+	/* printk(KERN_DEBUG "rd(%02x): %02x %02x\n", i2c_addr, reg, b); */
 
-	return b1[0];
+	return b;
 }
 
+#define cx24123_readreg(state, reg) \
+	cx24123_i2c_readreg(state, state->config->demod_address, reg)
+#define cx24123_writereg(state, reg, val) \
+	cx24123_i2c_writereg(state, state->config->demod_address, reg, val)
+
 static int cx24123_set_inversion(struct cx24123_state* state, fe_spectral_inversion_t inversion)
 {
 	u8 nom_reg = cx24123_readreg(state, 0x0e);
@@ -274,17 +291,17 @@
 
 	switch (inversion) {
 	case INVERSION_OFF:
-		dprintk("%s:  inversion off\n",__FUNCTION__);
+		dprintk("inversion off\n");
 		cx24123_writereg(state, 0x0e, nom_reg & ~0x80);
 		cx24123_writereg(state, 0x10, auto_reg | 0x80);
 		break;
 	case INVERSION_ON:
-		dprintk("%s:  inversion on\n",__FUNCTION__);
+		dprintk("inversion on\n");
 		cx24123_writereg(state, 0x0e, nom_reg | 0x80);
 		cx24123_writereg(state, 0x10, auto_reg | 0x80);
 		break;
 	case INVERSION_AUTO:
-		dprintk("%s:  inversion auto\n",__FUNCTION__);
+		dprintk("inversion auto\n");
 		cx24123_writereg(state, 0x10, auto_reg & ~0x80);
 		break;
 	default:
@@ -301,10 +318,10 @@
 	val = cx24123_readreg(state, 0x1b) >> 7;
 
 	if (val == 0) {
-		dprintk("%s:  read inversion off\n",__FUNCTION__);
+		dprintk("read inversion off\n");
 		*inversion = INVERSION_OFF;
 	} else {
-		dprintk("%s:  read inversion on\n",__FUNCTION__);
+		dprintk("read inversion on\n");
 		*inversion = INVERSION_ON;
 	}
 
@@ -326,42 +343,42 @@
 
 	switch (fec) {
 	case FEC_1_2:
-		dprintk("%s:  set FEC to 1/2\n",__FUNCTION__);
+		dprintk("set FEC to 1/2\n");
 		cx24123_writereg(state, 0x0e, nom_reg | 0x01);
 		cx24123_writereg(state, 0x0f, 0x02);
 		break;
 	case FEC_2_3:
-		dprintk("%s:  set FEC to 2/3\n",__FUNCTION__);
+		dprintk("set FEC to 2/3\n");
 		cx24123_writereg(state, 0x0e, nom_reg | 0x02);
 		cx24123_writereg(state, 0x0f, 0x04);
 		break;
 	case FEC_3_4:
-		dprintk("%s:  set FEC to 3/4\n",__FUNCTION__);
+		dprintk("set FEC to 3/4\n");
 		cx24123_writereg(state, 0x0e, nom_reg | 0x03);
 		cx24123_writereg(state, 0x0f, 0x08);
 		break;
 	case FEC_4_5:
-		dprintk("%s:  set FEC to 4/5\n",__FUNCTION__);
+		dprintk("set FEC to 4/5\n");
 		cx24123_writereg(state, 0x0e, nom_reg | 0x04);
 		cx24123_writereg(state, 0x0f, 0x10);
 		break;
 	case FEC_5_6:
-		dprintk("%s:  set FEC to 5/6\n",__FUNCTION__);
+		dprintk("set FEC to 5/6\n");
 		cx24123_writereg(state, 0x0e, nom_reg | 0x05);
 		cx24123_writereg(state, 0x0f, 0x20);
 		break;
 	case FEC_6_7:
-		dprintk("%s:  set FEC to 6/7\n",__FUNCTION__);
+		dprintk("set FEC to 6/7\n");
 		cx24123_writereg(state, 0x0e, nom_reg | 0x06);
 		cx24123_writereg(state, 0x0f, 0x40);
 		break;
 	case FEC_7_8:
-		dprintk("%s:  set FEC to 7/8\n",__FUNCTION__);
+		dprintk("set FEC to 7/8\n");
 		cx24123_writereg(state, 0x0e, nom_reg | 0x07);
 		cx24123_writereg(state, 0x0f, 0x80);
 		break;
 	case FEC_AUTO:
-		dprintk("%s:  set FEC to auto\n",__FUNCTION__);
+		dprintk("set FEC to auto\n");
 		cx24123_writereg(state, 0x0f, 0xfe);
 		break;
 	default:
@@ -490,7 +507,8 @@
 	tmp = cx24123_readreg(state, 0x0c) & ~0xe0;
 	cx24123_writereg(state, 0x0c, tmp | sample_gain << 5);
 
-	dprintk("%s: srate=%d, ratio=0x%08x, sample_rate=%i sample_gain=%d\n", __FUNCTION__, srate, ratio, sample_rate, sample_gain);
+	dprintk("srate=%d, ratio=0x%08x, sample_rate=%i sample_gain=%d\n",
+		srate, ratio, sample_rate, sample_gain);
 
 	return 0;
 }
@@ -570,7 +588,7 @@
 	struct cx24123_state *state = fe->demodulator_priv;
 	unsigned long timeout;
 
-	dprintk("%s:  pll writereg called, data=0x%08x\n",__FUNCTION__,data);
+	dprintk("pll writereg called, data=0x%08x\n", data);
 
 	/* align the 21 bytes into to bit23 boundary */
 	data = data << 3;
@@ -583,7 +601,8 @@
 	cx24123_writereg(state, 0x22, (data >> 16) & 0xff);
 	while ((cx24123_readreg(state, 0x20) & 0x40) == 0) {
 		if (time_after(jiffies, timeout)) {
-			printk("%s:  demodulator is not responding, possibly hung, aborting.\n", __FUNCTION__);
+			err("%s:  demodulator is not responding, "\
+				"possibly hung, aborting.\n", __func__);
 			return -EREMOTEIO;
 		}
 		msleep(10);
@@ -594,7 +613,8 @@
 	cx24123_writereg(state, 0x22, (data>>8) & 0xff );
 	while ((cx24123_readreg(state, 0x20) & 0x40) == 0) {
 		if (time_after(jiffies, timeout)) {
-			printk("%s:  demodulator is not responding, possibly hung, aborting.\n", __FUNCTION__);
+			err("%s:  demodulator is not responding, "\
+				"possibly hung, aborting.\n", __func__);
 			return -EREMOTEIO;
 		}
 		msleep(10);
@@ -605,7 +625,8 @@
 	cx24123_writereg(state, 0x22, (data) & 0xff );
 	while ((cx24123_readreg(state, 0x20) & 0x80)) {
 		if (time_after(jiffies, timeout)) {
-			printk("%s:  demodulator is not responding, possibly hung, aborting.\n", __FUNCTION__);
+			err("%s:  demodulator is not responding," \
+				"possibly hung, aborting.\n", __func__);
 			return -EREMOTEIO;
 		}
 		msleep(10);
@@ -626,7 +647,7 @@
 	dprintk("frequency=%i\n", p->frequency);
 
 	if (cx24123_pll_calculate(fe, p) != 0) {
-		printk("%s: cx24123_pll_calcutate failed\n",__FUNCTION__);
+		err("%s: cx24123_pll_calcutate failed\n", __func__);
 		return -EINVAL;
 	}
 
@@ -643,18 +664,38 @@
 	cx24123_writereg(state, 0x27, state->FILTune >> 2);
 	cx24123_writereg(state, 0x28, val | (state->FILTune & 0x3));
 
-	dprintk("%s:  pll tune VCA=%d, band=%d, pll=%d\n",__FUNCTION__,state->VCAarg,
-			state->bandselectarg,state->pllarg);
+	dprintk("pll tune VCA=%d, band=%d, pll=%d\n", state->VCAarg,
+			state->bandselectarg, state->pllarg);
 
 	return 0;
 }
 
+
+/*
+ * 0x23:
+ *    [7:7] = BTI enabled
+ *    [6:6] = I2C repeater enabled
+ *    [5:5] = I2C repeater start
+ *    [0:0] = BTI start
+ */
+
+/* mode == 1 -> i2c-repeater, 0 -> bti */
+static int cx24123_repeater_mode(struct cx24123_state *state, u8 mode, u8 start)
+{
+	u8 r = cx24123_readreg(state, 0x23) & 0x1e;
+	if (mode)
+		r |= (1 << 6) | (start << 5);
+	else
+		r |= (1 << 7) | (start);
+	return cx24123_writereg(state, 0x23, r);
+}
+
 static int cx24123_initfe(struct dvb_frontend* fe)
 {
 	struct cx24123_state *state = fe->demodulator_priv;
 	int i;
 
-	dprintk("%s:  init frontend\n",__FUNCTION__);
+	dprintk("init frontend\n");
 
 	/* Configure the demod to a good set of defaults */
 	for (i = 0; i < ARRAY_SIZE(cx24123_regdata); i++)
@@ -664,6 +705,9 @@
 	if(state->config->lnb_polarity)
 		cx24123_writereg(state, 0x32, cx24123_readreg(state, 0x32) | 0x02);
 
+	if (state->config->dont_use_pll)
+	cx24123_repeater_mode(state, 1, 0);
+
 	return 0;
 }
 
@@ -676,10 +720,10 @@
 
 	switch (voltage) {
 	case SEC_VOLTAGE_13:
-		dprintk("%s: setting voltage 13V\n", __FUNCTION__);
+		dprintk("setting voltage 13V\n");
 		return cx24123_writereg(state, 0x29, val & 0x7f);
 	case SEC_VOLTAGE_18:
-		dprintk("%s: setting voltage 18V\n", __FUNCTION__);
+		dprintk("setting voltage 18V\n");
 		return cx24123_writereg(state, 0x29, val | 0x80);
 	case SEC_VOLTAGE_OFF:
 		/* already handled in cx88-dvb */
@@ -697,7 +741,8 @@
 	unsigned long timeout = jiffies + msecs_to_jiffies(200);
 	while (!(cx24123_readreg(state, 0x29) & 0x40)) {
 		if(time_after(jiffies, timeout)) {
-			printk("%s: diseqc queue not ready, command may be lost.\n", __FUNCTION__);
+			err("%s: diseqc queue not ready, " \
+				"command may be lost.\n", __func__);
 			break;
 		}
 		msleep(10);
@@ -709,7 +754,7 @@
 	struct cx24123_state *state = fe->demodulator_priv;
 	int i, val, tone;
 
-	dprintk("%s:\n",__FUNCTION__);
+	dprintk("\n");
 
 	/* stop continuous tone if enabled */
 	tone = cx24123_readreg(state, 0x29);
@@ -744,7 +789,7 @@
 	struct cx24123_state *state = fe->demodulator_priv;
 	int val, tone;
 
-	dprintk("%s:\n", __FUNCTION__);
+	dprintk("\n");
 
 	/* stop continuous tone if enabled */
 	tone = cx24123_readreg(state, 0x29);
@@ -778,13 +823,21 @@
 static int cx24123_read_status(struct dvb_frontend* fe, fe_status_t* status)
 {
 	struct cx24123_state *state = fe->demodulator_priv;
-
 	int sync = cx24123_readreg(state, 0x14);
-	int lock = cx24123_readreg(state, 0x20);
 
 	*status = 0;
-	if (lock & 0x01)
-		*status |= FE_HAS_SIGNAL;
+	if (state->config->dont_use_pll) {
+		u32 tun_status = 0;
+		if (fe->ops.tuner_ops.get_status)
+			fe->ops.tuner_ops.get_status(fe, &tun_status);
+		if (tun_status & TUNER_STATUS_LOCKED)
+			*status |= FE_HAS_SIGNAL;
+	} else {
+		int lock = cx24123_readreg(state, 0x20);
+		if (lock & 0x01)
+			*status |= FE_HAS_SIGNAL;
+	}
+
 	if (sync & 0x02)
 		*status |= FE_HAS_CARRIER;	/* Phase locked */
 	if (sync & 0x04)
@@ -803,7 +856,7 @@
  * Configured to return the measurement of errors in blocks, because no UCBLOCKS value
  * is available, so this value doubles up to satisfy both measurements
  */
-static int cx24123_read_ber(struct dvb_frontend* fe, u32* ber)
+static int cx24123_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
 	struct cx24123_state *state = fe->demodulator_priv;
 
@@ -813,23 +866,24 @@
 		(cx24123_readreg(state, 0x1d) << 8 |
 		 cx24123_readreg(state, 0x1e));
 
-	dprintk("%s:  BER = %d\n",__FUNCTION__,*ber);
+	dprintk("BER = %d\n", *ber);
 
 	return 0;
 }
 
-static int cx24123_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
+static int cx24123_read_signal_strength(struct dvb_frontend *fe,
+	u16 *signal_strength)
 {
 	struct cx24123_state *state = fe->demodulator_priv;
 
 	*signal_strength = cx24123_readreg(state, 0x3b) << 8; /* larger = better */
 
-	dprintk("%s:  Signal strength = %d\n",__FUNCTION__,*signal_strength);
+	dprintk("Signal strength = %d\n", *signal_strength);
 
 	return 0;
 }
 
-static int cx24123_read_snr(struct dvb_frontend* fe, u16* snr)
+static int cx24123_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
 	struct cx24123_state *state = fe->demodulator_priv;
 
@@ -838,16 +892,17 @@
 	*snr = 65535 - (((u16)cx24123_readreg(state, 0x18) << 8) |
 			 (u16)cx24123_readreg(state, 0x19));
 
-	dprintk("%s:  read S/N index = %d\n",__FUNCTION__,*snr);
+	dprintk("read S/N index = %d\n", *snr);
 
 	return 0;
 }
 
-static int cx24123_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int cx24123_set_frontend(struct dvb_frontend *fe,
+	struct dvb_frontend_parameters *p)
 {
 	struct cx24123_state *state = fe->demodulator_priv;
 
-	dprintk("%s:  set_frontend\n",__FUNCTION__);
+	dprintk("\n");
 
 	if (state->config->set_ts_params)
 		state->config->set_ts_params(fe, 0);
@@ -858,13 +913,22 @@
 	cx24123_set_inversion(state, p->inversion);
 	cx24123_set_fec(state, p->u.qpsk.fec_inner);
 	cx24123_set_symbolrate(state, p->u.qpsk.symbol_rate);
-	cx24123_pll_tune(fe, p);
+
+	if (!state->config->dont_use_pll)
+		cx24123_pll_tune(fe, p);
+	else if (fe->ops.tuner_ops.set_params)
+		fe->ops.tuner_ops.set_params(fe, p);
+	else
+		err("it seems I don't have a tuner...");
 
 	/* Enable automatic aquisition and reset cycle */
 	cx24123_writereg(state, 0x03, (cx24123_readreg(state, 0x03) | 0x07));
 	cx24123_writereg(state, 0x00, 0x10);
 	cx24123_writereg(state, 0x00, 0);
 
+	if (state->config->agc_callback)
+		state->config->agc_callback(fe);
+
 	return 0;
 }
 
@@ -872,14 +936,14 @@
 {
 	struct cx24123_state *state = fe->demodulator_priv;
 
-	dprintk("%s:  get_frontend\n",__FUNCTION__);
+	dprintk("\n");
 
 	if (cx24123_get_inversion(state, &p->inversion) != 0) {
-		printk("%s: Failed to get inversion status\n",__FUNCTION__);
+		err("%s: Failed to get inversion status\n", __func__);
 		return -EREMOTEIO;
 	}
 	if (cx24123_get_fec(state, &p->u.qpsk.fec_inner) != 0) {
-		printk("%s: Failed to get fec status\n",__FUNCTION__);
+		err("%s: Failed to get fec status\n", __func__);
 		return -EREMOTEIO;
 	}
 	p->frequency = state->currentfreq;
@@ -900,13 +964,13 @@
 
 	switch (tone) {
 	case SEC_TONE_ON:
-		dprintk("%s: setting tone on\n", __FUNCTION__);
+		dprintk("setting tone on\n");
 		return cx24123_writereg(state, 0x29, val | 0x10);
 	case SEC_TONE_OFF:
-		dprintk("%s: setting tone off\n",__FUNCTION__);
+		dprintk("setting tone off\n");
 		return cx24123_writereg(state, 0x29, val & 0xef);
 	default:
-		printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
+		err("CASE reached default with tone=%d\n", tone);
 		return -EINVAL;
 	}
 
@@ -939,47 +1003,86 @@
 static void cx24123_release(struct dvb_frontend* fe)
 {
 	struct cx24123_state* state = fe->demodulator_priv;
-	dprintk("%s\n",__FUNCTION__);
+	dprintk("\n");
+	i2c_del_adapter(&state->tuner_i2c_adapter);
 	kfree(state);
 }
 
+static int cx24123_tuner_i2c_tuner_xfer(struct i2c_adapter *i2c_adap,
+	struct i2c_msg msg[], int num)
+{
+	struct cx24123_state *state = i2c_get_adapdata(i2c_adap);
+	/* this repeater closes after the first stop */
+    cx24123_repeater_mode(state, 1, 1);
+	return i2c_transfer(state->i2c, msg, num);
+}
+
+static u32 cx24123_tuner_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm cx24123_tuner_i2c_algo = {
+	.master_xfer   = cx24123_tuner_i2c_tuner_xfer,
+	.functionality = cx24123_tuner_i2c_func,
+};
+
+struct i2c_adapter *
+	cx24123_get_tuner_i2c_adapter(struct dvb_frontend *fe)
+{
+	struct cx24123_state *state = fe->demodulator_priv;
+	return &state->tuner_i2c_adapter;
+}
+EXPORT_SYMBOL(cx24123_get_tuner_i2c_adapter);
+
 static struct dvb_frontend_ops cx24123_ops;
 
 struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
 				    struct i2c_adapter* i2c)
 {
-	struct cx24123_state* state = NULL;
-	int ret;
+	struct cx24123_state *state =
+		kzalloc(sizeof(struct cx24123_state), GFP_KERNEL);
 
-	dprintk("%s\n",__FUNCTION__);
-
+	dprintk("\n");
 	/* allocate memory for the internal state */
-	state = kmalloc(sizeof(struct cx24123_state), GFP_KERNEL);
 	if (state == NULL) {
-		printk("Unable to kmalloc\n");
+		err("Unable to kmalloc\n");
 		goto error;
 	}
 
 	/* setup the state */
 	state->config = config;
 	state->i2c = i2c;
-	state->VCAarg = 0;
-	state->VGAarg = 0;
-	state->bandselectarg = 0;
-	state->pllarg = 0;
-	state->currentfreq = 0;
-	state->currentsymbolrate = 0;
 
 	/* check if the demod is there */
-	ret = cx24123_readreg(state, 0x00);
-	if ((ret != 0xd1) && (ret != 0xe1)) {
-		printk("Version != d1 or e1\n");
+	state->demod_rev = cx24123_readreg(state, 0x00);
+	switch (state->demod_rev) {
+	case 0xe1: info("detected CX24123C\n"); break;
+	case 0xd1: info("detected CX24123\n"); break;
+	default:
+		err("wrong demod revision: %x\n", state->demod_rev);
 		goto error;
 	}
 
 	/* create dvb_frontend */
 	memcpy(&state->frontend.ops, &cx24123_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
+
+    /* create tuner i2c adapter */
+    if (config->dont_use_pll)
+	cx24123_repeater_mode(state, 1, 0);
+
+	strncpy(state->tuner_i2c_adapter.name,
+		"CX24123 tuner I2C bus", I2C_NAME_SIZE);
+	state->tuner_i2c_adapter.class     = I2C_CLASS_TV_DIGITAL,
+	state->tuner_i2c_adapter.algo      = &cx24123_tuner_i2c_algo;
+	state->tuner_i2c_adapter.algo_data = NULL;
+	i2c_set_adapdata(&state->tuner_i2c_adapter, state);
+	if (i2c_add_adapter(&state->tuner_i2c_adapter) < 0) {
+	err("tuner i2c bus could not be initialized\n");
+		goto error;
+	}
+
 	return &state->frontend;
 
 error:
@@ -1029,7 +1132,8 @@
 module_param(force_band, int, 0644);
 MODULE_PARM_DESC(force_band, "Force a specific band select (1-9, default:off).");
 
-MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24123/cx24109 hardware");
+MODULE_DESCRIPTION("DVB Frontend module for Conexant " \
+	"CX24123/CX24109/CX24113 hardware");
 MODULE_AUTHOR("Steven Toth");
 MODULE_LICENSE("GPL");
 
diff --git a/drivers/media/dvb/frontends/cx24123.h b/drivers/media/dvb/frontends/cx24123.h
index 84f9e4f..81ebc3d 100644
--- a/drivers/media/dvb/frontends/cx24123.h
+++ b/drivers/media/dvb/frontends/cx24123.h
@@ -33,16 +33,27 @@
 
 	/* 0 = LNB voltage normal, 1 = LNB voltage inverted */
 	int lnb_polarity;
+
+	/* this device has another tuner */
+	u8 dont_use_pll;
+	void (*agc_callback) (struct dvb_frontend *);
 };
 
 #if defined(CONFIG_DVB_CX24123) || (defined(CONFIG_DVB_CX24123_MODULE) && defined(MODULE))
-extern struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
-					   struct i2c_adapter* i2c);
+extern struct dvb_frontend *cx24123_attach(const struct cx24123_config *config,
+					   struct i2c_adapter *i2c);
+extern struct i2c_adapter *cx24123_get_tuner_i2c_adapter(struct dvb_frontend *);
 #else
-static inline struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
-						  struct i2c_adapter* i2c)
+static inline struct dvb_frontend *cx24123_attach(
+	const struct cx24123_config *config, struct i2c_adapter *i2c)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+static struct i2c_adapter *
+	cx24123_get_tuner_i2c_adapter(struct dvb_frontend *fe)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_CX24123
diff --git a/drivers/media/dvb/frontends/dib3000.h b/drivers/media/dvb/frontends/dib3000.h
index a6d3854..ba91735 100644
--- a/drivers/media/dvb/frontends/dib3000.h
+++ b/drivers/media/dvb/frontends/dib3000.h
@@ -48,7 +48,7 @@
 static inline struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
 					     struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_DIB3000MB
diff --git a/drivers/media/dvb/frontends/dib3000mc.h b/drivers/media/dvb/frontends/dib3000mc.h
index 72d4757..4142ed7 100644
--- a/drivers/media/dvb/frontends/dib3000mc.h
+++ b/drivers/media/dvb/frontends/dib3000mc.h
@@ -44,7 +44,7 @@
 #else
 static inline struct dvb_frontend * dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib3000mc_config *cfg)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_DIB3000MC
diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c
index 47c23e2..1a0142e 100644
--- a/drivers/media/dvb/frontends/dib7000p.c
+++ b/drivers/media/dvb/frontends/dib7000p.c
@@ -1168,7 +1168,7 @@
 	ret = dib7000p_tune(fe, fep);
 
 	/* make this a config parameter */
-	dib7000p_set_output_mode(state, OUTMODE_MPEG2_FIFO);
+	dib7000p_set_output_mode(state, state->cfg.output_mode);
     return ret;
 }
 
@@ -1330,6 +1330,12 @@
 	st->gpio_val = cfg->gpio_val;
 	st->gpio_dir = cfg->gpio_dir;
 
+	/* Ensure the output mode remains at the previous default if it's
+	 * not specifically set by the caller.
+	 */
+	if (st->cfg.output_mode != OUTMODE_MPEG2_SERIAL)
+		st->cfg.output_mode = OUTMODE_MPEG2_FIFO;
+
 	demod                   = &st->demod;
 	demod->demodulator_priv = st;
 	memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h
index eefcac8..081bd81 100644
--- a/drivers/media/dvb/frontends/dib7000p.h
+++ b/drivers/media/dvb/frontends/dib7000p.h
@@ -31,6 +31,8 @@
 	u8 spur_protect;
 
 	int (*agc_control) (struct dvb_frontend *, u8 before);
+
+	u8 output_mode;
 };
 
 #define DEFAULT_DIB7000P_I2C_ADDRESS 18
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index 8c8d734..a054894 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -44,14 +44,10 @@
 
 static unsigned int dvb_pll_devcount;
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
-static unsigned int input[DVB_PLL_MAX] = { [ 0 ... (DVB_PLL_MAX-1) ] = 0 };
-module_param_array(input, int, NULL, 0644);
-MODULE_PARM_DESC(input,"specify rf input choice, 0 for autoselect (default)");
-
 static unsigned int id[DVB_PLL_MAX] =
 	{ [ 0 ... (DVB_PLL_MAX-1) ] = DVB_PLL_UNDEFINED };
 module_param_array(id, int, NULL, 0644);
@@ -80,23 +76,6 @@
 /* ----------------------------------------------------------- */
 /* descriptions                                                */
 
-/* Set AGC TOP value to 103 dBuV:
-	0x80 = Control Byte
-	0x40 = 250 uA charge pump (irrelevant)
-	0x18 = Aux Byte to follow
-	0x06 = 64.5 kHz divider (irrelevant)
-	0x01 = Disable Vt (aka sleep)
-
-	0x00 = AGC Time constant 2s Iagc = 300 nA (vs 0x80 = 9 nA)
-	0x50 = AGC Take over point = 103 dBuV */
-static u8 tua603x_agc103[] = { 2, 0x80|0x40|0x18|0x06|0x01, 0x00|0x50 };
-
-/*	0x04 = 166.67 kHz divider
-
-	0x80 = AGC Time constant 50ms Iagc = 9 uA
-	0x20 = AGC Take over point = 112 dBuV */
-static u8 tua603x_agc112[] = { 2, 0x80|0x40|0x18|0x04|0x01, 0x80|0x20 };
-
 static struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
 	.name  = "Thomson dtt7579",
 	.min   = 177000000,
@@ -112,19 +91,6 @@
 	},
 };
 
-static struct dvb_pll_desc dvb_pll_thomson_dtt7610 = {
-	.name  = "Thomson dtt7610",
-	.min   =  44000000,
-	.max   = 958000000,
-	.iffreq= 44000000,
-	.count = 3,
-	.entries = {
-		{ 157250000, 62500, 0x8e, 0x39 },
-		{ 454000000, 62500, 0x8e, 0x3a },
-		{ 999999999, 62500, 0x8e, 0x3c },
-	},
-};
-
 static void thomson_dtt759x_bw(struct dvb_frontend *fe, u8 *buf,
 			       const struct dvb_frontend_parameters *params)
 {
@@ -165,34 +131,6 @@
 	},
 };
 
-static struct dvb_pll_desc dvb_pll_microtune_4042 = {
-	.name  = "Microtune 4042 FI5",
-	.min   =  57000000,
-	.max   = 858000000,
-	.iffreq= 44000000,
-	.count = 3,
-	.entries = {
-		{ 162000000, 62500, 0x8e, 0xa1 },
-		{ 457000000, 62500, 0x8e, 0x91 },
-		{ 999999999, 62500, 0x8e, 0x31 },
-	},
-};
-
-static struct dvb_pll_desc dvb_pll_thomson_dtt761x = {
-	/* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
-	.name  = "Thomson dtt761x",
-	.min   =  57000000,
-	.max   = 863000000,
-	.iffreq= 44000000,
-	.count = 3,
-	.initdata = tua603x_agc103,
-	.entries = {
-		{ 147000000, 62500, 0x8e, 0x39 },
-		{ 417000000, 62500, 0x8e, 0x3a },
-		{ 999999999, 62500, 0x8e, 0x3c },
-	},
-};
-
 static struct dvb_pll_desc dvb_pll_unknown_1 = {
 	.name  = "unknown 1", /* used by dntv live dvb-t */
 	.min   = 174000000,
@@ -301,54 +239,6 @@
 	},
 };
 
-/* Infineon TUA6034
- * used in LG TDVS-H061F, LG TDVS-H062F and LG TDVS-H064F
- */
-static struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = {
-	.name  = "LG TDVS-H06xF",
-	.min   =  54000000,
-	.max   = 863000000,
-	.iffreq= 44000000,
-	.initdata = tua603x_agc103,
-	.count = 3,
-	.entries = {
-		{  165000000, 62500, 0xce, 0x01 },
-		{  450000000, 62500, 0xce, 0x02 },
-		{  999999999, 62500, 0xce, 0x04 },
-	},
-};
-
-/* Philips FMD1216ME
- * used in Medion Hybrid PCMCIA card and USB Box
- */
-static void fmd1216me_bw(struct dvb_frontend *fe, u8 *buf,
-			 const struct dvb_frontend_parameters *params)
-{
-	if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ &&
-	    params->frequency >= 158870000)
-		buf[3] |= 0x08;
-}
-
-static struct dvb_pll_desc dvb_pll_fmd1216me = {
-	.name = "Philips FMD1216ME",
-	.min = 50870000,
-	.max = 858000000,
-	.iffreq= 36125000,
-	.set   = fmd1216me_bw,
-	.initdata = tua603x_agc112,
-	.sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 },
-	.count = 7,
-	.entries = {
-		{ 143870000, 166667, 0xbc, 0x41 },
-		{ 158870000, 166667, 0xf4, 0x41 },
-		{ 329870000, 166667, 0xbc, 0x42 },
-		{ 441870000, 166667, 0xf4, 0x42 },
-		{ 625870000, 166667, 0xbc, 0x44 },
-		{ 803870000, 166667, 0xf4, 0x44 },
-		{ 999999999, 166667, 0xfc, 0x44 },
-	}
-};
-
 /* ALPS TDED4
  * used in Nebula-Cards and USB boxes
  */
@@ -391,55 +281,6 @@
 	}
 };
 
-/* Philips TUV1236D
- * used in ATI HDTV Wonder
- */
-static void tuv1236d_rf(struct dvb_frontend *fe, u8 *buf,
-			const struct dvb_frontend_parameters *params)
-{
-	struct dvb_pll_priv *priv = fe->tuner_priv;
-	unsigned int new_rf = input[priv->nr];
-
-	if ((new_rf == 0) || (new_rf > 2)) {
-		switch (params->u.vsb.modulation) {
-			case QAM_64:
-			case QAM_256:
-				new_rf = 1;
-				break;
-			case VSB_8:
-			default:
-				new_rf = 2;
-		}
-	}
-
-	switch (new_rf) {
-		case 1:
-			buf[3] |= 0x08;
-			break;
-		case 2:
-			buf[3] &= ~0x08;
-			break;
-		default:
-			printk(KERN_WARNING
-			       "%s: unhandled rf input selection: %d",
-			       __FUNCTION__, new_rf);
-	}
-}
-
-static struct dvb_pll_desc dvb_pll_tuv1236d = {
-	.name  = "Philips TUV1236D",
-	.min   =  54000000,
-	.max   = 864000000,
-	.iffreq= 44000000,
-	.set   = tuv1236d_rf,
-	.count = 3,
-	.entries = {
-		{ 157250000, 62500, 0xc6, 0x41 },
-		{ 454000000, 62500, 0xc6, 0x42 },
-		{ 999999999, 62500, 0xc6, 0x44 },
-	},
-};
-
 /* Samsung TBMV30111IN / TBMV30712IN1
  * used in Air2PC ATSC - 2nd generation (nxt2002)
  */
@@ -476,64 +317,6 @@
 	},
 };
 
-/*
- * Philips TD1316 Tuner.
- */
-static void td1316_bw(struct dvb_frontend *fe, u8 *buf,
-		      const struct dvb_frontend_parameters *params)
-{
-	u8 band;
-
-	/* determine band */
-	if (params->frequency < 161000000)
-		band = 1;
-	else if (params->frequency < 444000000)
-		band = 2;
-	else
-		band = 4;
-
-	buf[3] |= band;
-
-	/* setup PLL filter */
-	if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
-		buf[3] |= 1 << 3;
-}
-
-static struct dvb_pll_desc dvb_pll_philips_td1316 = {
-	.name  = "Philips TD1316",
-	.min   =  87000000,
-	.max   = 895000000,
-	.iffreq= 36166667,
-	.set   = td1316_bw,
-	.count = 9,
-	.entries = {
-		{  93834000, 166667, 0xca, 0x60},
-		{ 123834000, 166667, 0xca, 0xa0},
-		{ 163834000, 166667, 0xca, 0xc0},
-		{ 253834000, 166667, 0xca, 0x60},
-		{ 383834000, 166667, 0xca, 0xa0},
-		{ 443834000, 166667, 0xca, 0xc0},
-		{ 583834000, 166667, 0xca, 0x60},
-		{ 793834000, 166667, 0xca, 0xa0},
-		{ 858834000, 166667, 0xca, 0xe0},
-	},
-};
-
-/* FE6600 used on DViCO Hybrid */
-static struct dvb_pll_desc dvb_pll_thomson_fe6600 = {
-	.name = "Thomson FE6600",
-	.min =  44250000,
-	.max = 858000000,
-	.iffreq= 36125000,
-	.count = 4,
-	.entries = {
-		{ 250000000, 166667, 0xb4, 0x12 },
-		{ 455000000, 166667, 0xfe, 0x11 },
-		{ 775500000, 166667, 0xbc, 0x18 },
-		{ 999999999, 166667, 0xf4, 0x18 },
-	}
-};
-
 static void opera1_bw(struct dvb_frontend *fe, u8 *buf,
 		      const struct dvb_frontend_parameters *params)
 {
@@ -560,50 +343,23 @@
 	}
 };
 
-/* Philips FCV1236D
- */
-static struct dvb_pll_desc dvb_pll_fcv1236d = {
-/* Bit_0: RF Input select
- * Bit_1: 0=digital, 1=analog
- */
-	.name  = "Philips FCV1236D",
-	.min   =  53000000,
-	.max   = 803000000,
-	.iffreq= 44000000,
-	.count = 3,
-	.entries = {
-		{ 159000000, 62500, 0x8e, 0xa0 },
-		{ 453000000, 62500, 0x8e, 0x90 },
-		{ 999999999, 62500, 0x8e, 0x30 },
-	},
-};
-
 /* ----------------------------------------------------------- */
 
 static struct dvb_pll_desc *pll_list[] = {
 	[DVB_PLL_UNDEFINED]              = NULL,
 	[DVB_PLL_THOMSON_DTT7579]        = &dvb_pll_thomson_dtt7579,
 	[DVB_PLL_THOMSON_DTT759X]        = &dvb_pll_thomson_dtt759x,
-	[DVB_PLL_THOMSON_DTT7610]        = &dvb_pll_thomson_dtt7610,
 	[DVB_PLL_LG_Z201]                = &dvb_pll_lg_z201,
-	[DVB_PLL_MICROTUNE_4042]         = &dvb_pll_microtune_4042,
-	[DVB_PLL_THOMSON_DTT761X]        = &dvb_pll_thomson_dtt761x,
 	[DVB_PLL_UNKNOWN_1]              = &dvb_pll_unknown_1,
 	[DVB_PLL_TUA6010XS]              = &dvb_pll_tua6010xs,
 	[DVB_PLL_ENV57H1XD5]             = &dvb_pll_env57h1xd5,
 	[DVB_PLL_TUA6034]                = &dvb_pll_tua6034,
-	[DVB_PLL_LG_TDVS_H06XF]          = &dvb_pll_lg_tdvs_h06xf,
 	[DVB_PLL_TDA665X]                = &dvb_pll_tda665x,
-	[DVB_PLL_FMD1216ME]              = &dvb_pll_fmd1216me,
 	[DVB_PLL_TDED4]                  = &dvb_pll_tded4,
-	[DVB_PLL_TUV1236D]               = &dvb_pll_tuv1236d,
 	[DVB_PLL_TDHU2]                  = &dvb_pll_tdhu2,
 	[DVB_PLL_SAMSUNG_TBMV]           = &dvb_pll_samsung_tbmv,
 	[DVB_PLL_PHILIPS_SD1878_TDA8261] = &dvb_pll_philips_sd1878_tda8261,
-	[DVB_PLL_PHILIPS_TD1316]         = &dvb_pll_philips_td1316,
-	[DVB_PLL_THOMSON_FE6600]         = &dvb_pll_thomson_fe6600,
 	[DVB_PLL_OPERA1]                 = &dvb_pll_opera1,
-	[DVB_PLL_FCV1236D]               = &dvb_pll_fcv1236d,
 };
 
 /* ----------------------------------------------------------- */
@@ -849,20 +605,6 @@
 		       id[priv->nr] == pll_desc_id ?
 				"insmod option" : "autodetected");
 	}
-	if ((debug) || (input[priv->nr] > 0)) {
-		printk("dvb-pll[%d]", priv->nr);
-		if (i2c != NULL)
-			printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr);
-		printk(": tuner rf input will be ");
-		switch (input[priv->nr]) {
-		case 0:
-			printk("autoselected\n");
-			break;
-		default:
-			printk("set to input %d (insmod option)\n",
-			       input[priv->nr]);
-		}
-	}
 
 	return fe;
 }
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
index e93a810..872ca29 100644
--- a/drivers/media/dvb/frontends/dvb-pll.h
+++ b/drivers/media/dvb/frontends/dvb-pll.h
@@ -11,26 +11,17 @@
 #define DVB_PLL_UNDEFINED               0
 #define DVB_PLL_THOMSON_DTT7579         1
 #define DVB_PLL_THOMSON_DTT759X         2
-#define DVB_PLL_THOMSON_DTT7610         3
-#define DVB_PLL_LG_Z201                 4
-#define DVB_PLL_MICROTUNE_4042          5
-#define DVB_PLL_THOMSON_DTT761X         6
-#define DVB_PLL_UNKNOWN_1               7
-#define DVB_PLL_TUA6010XS               8
-#define DVB_PLL_ENV57H1XD5              9
-#define DVB_PLL_TUA6034                10
-#define DVB_PLL_LG_TDVS_H06XF          11
-#define DVB_PLL_TDA665X                12
-#define DVB_PLL_FMD1216ME              13
-#define DVB_PLL_TDED4                  14
-#define DVB_PLL_TUV1236D               15
-#define DVB_PLL_TDHU2                  16
-#define DVB_PLL_SAMSUNG_TBMV           17
-#define DVB_PLL_PHILIPS_SD1878_TDA8261 18
-#define DVB_PLL_PHILIPS_TD1316         19
-#define DVB_PLL_THOMSON_FE6600         20
-#define DVB_PLL_OPERA1                 21
-#define DVB_PLL_FCV1236D               22
+#define DVB_PLL_LG_Z201                 3
+#define DVB_PLL_UNKNOWN_1               4
+#define DVB_PLL_TUA6010XS               5
+#define DVB_PLL_ENV57H1XD5              6
+#define DVB_PLL_TUA6034                 7
+#define DVB_PLL_TDA665X                 8
+#define DVB_PLL_TDED4                   9
+#define DVB_PLL_TDHU2                  10
+#define DVB_PLL_SAMSUNG_TBMV           11
+#define DVB_PLL_PHILIPS_SD1878_TDA8261 12
+#define DVB_PLL_OPERA1                 13
 
 /**
  * Attach a dvb-pll to the supplied frontend structure.
@@ -52,7 +43,7 @@
 					   struct i2c_adapter *i2c,
 					   unsigned int pll_desc_id)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif
diff --git a/drivers/media/dvb/frontends/isl6405.c b/drivers/media/dvb/frontends/isl6405.c
new file mode 100644
index 0000000..33d33f4
--- /dev/null
+++ b/drivers/media/dvb/frontends/isl6405.c
@@ -0,0 +1,164 @@
+/*
+ * isl6405.c - driver for dual lnb supply and control ic ISL6405
+ *
+ * Copyright (C) 2008 Hartmut Hackmann
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "isl6405.h"
+
+struct isl6405 {
+	u8			config;
+	u8			override_or;
+	u8			override_and;
+	struct i2c_adapter	*i2c;
+	u8			i2c_addr;
+};
+
+static int isl6405_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	struct isl6405 *isl6405 = (struct isl6405 *) fe->sec_priv;
+	struct i2c_msg msg = {	.addr = isl6405->i2c_addr, .flags = 0,
+				.buf = &isl6405->config,
+				.len = sizeof(isl6405->config) };
+
+	if (isl6405->override_or & 0x80) {
+		isl6405->config &= ~(ISL6405_VSEL2 | ISL6405_EN2);
+		switch (voltage) {
+		case SEC_VOLTAGE_OFF:
+			break;
+		case SEC_VOLTAGE_13:
+			isl6405->config |= ISL6405_EN2;
+			break;
+		case SEC_VOLTAGE_18:
+			isl6405->config |= (ISL6405_EN2 | ISL6405_VSEL2);
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else {
+		isl6405->config &= ~(ISL6405_VSEL1 | ISL6405_EN1);
+		switch (voltage) {
+		case SEC_VOLTAGE_OFF:
+			break;
+		case SEC_VOLTAGE_13:
+			isl6405->config |= ISL6405_EN1;
+			break;
+		case SEC_VOLTAGE_18:
+			isl6405->config |= (ISL6405_EN1 | ISL6405_VSEL1);
+			break;
+		default:
+			return -EINVAL;
+		};
+	}
+	isl6405->config |= isl6405->override_or;
+	isl6405->config &= isl6405->override_and;
+
+	return (i2c_transfer(isl6405->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int isl6405_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
+{
+	struct isl6405 *isl6405 = (struct isl6405 *) fe->sec_priv;
+	struct i2c_msg msg = {	.addr = isl6405->i2c_addr, .flags = 0,
+				.buf = &isl6405->config,
+				.len = sizeof(isl6405->config) };
+
+	if (isl6405->override_or & 0x80) {
+		if (arg)
+			isl6405->config |= ISL6405_LLC2;
+		else
+			isl6405->config &= ~ISL6405_LLC2;
+	} else {
+		if (arg)
+			isl6405->config |= ISL6405_LLC1;
+		else
+			isl6405->config &= ~ISL6405_LLC1;
+	}
+	isl6405->config |= isl6405->override_or;
+	isl6405->config &= isl6405->override_and;
+
+	return (i2c_transfer(isl6405->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static void isl6405_release(struct dvb_frontend *fe)
+{
+	/* power off */
+	isl6405_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+	/* free */
+	kfree(fe->sec_priv);
+	fe->sec_priv = NULL;
+}
+
+struct dvb_frontend *isl6405_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c,
+				    u8 i2c_addr, u8 override_set, u8 override_clear)
+{
+	struct isl6405 *isl6405 = kmalloc(sizeof(struct isl6405), GFP_KERNEL);
+	if (!isl6405)
+		return NULL;
+
+	/* default configuration */
+	if (override_set & 0x80)
+		isl6405->config = ISL6405_ISEL2;
+	else
+		isl6405->config = ISL6405_ISEL1;
+	isl6405->i2c = i2c;
+	isl6405->i2c_addr = i2c_addr;
+	fe->sec_priv = isl6405;
+
+	/* bits which should be forced to '1' */
+	isl6405->override_or = override_set;
+
+	/* bits which should be forced to '0' */
+	isl6405->override_and = ~override_clear;
+
+	/* detect if it is present or not */
+	if (isl6405_set_voltage(fe, SEC_VOLTAGE_OFF)) {
+		kfree(isl6405);
+		fe->sec_priv = NULL;
+		return NULL;
+	}
+
+	/* install release callback */
+	fe->ops.release_sec = isl6405_release;
+
+	/* override frontend ops */
+	fe->ops.set_voltage = isl6405_set_voltage;
+	fe->ops.enable_high_lnb_voltage = isl6405_enable_high_lnb_voltage;
+
+	return fe;
+}
+EXPORT_SYMBOL(isl6405_attach);
+
+MODULE_DESCRIPTION("Driver for lnb supply and control ic isl6405");
+MODULE_AUTHOR("Hartmut Hackmann & Oliver Endriss");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/isl6405.h b/drivers/media/dvb/frontends/isl6405.h
new file mode 100644
index 0000000..1c793d3
--- /dev/null
+++ b/drivers/media/dvb/frontends/isl6405.h
@@ -0,0 +1,74 @@
+/*
+ * isl6405.h - driver for dual lnb supply and control ic ISL6405
+ *
+ * Copyright (C) 2008 Hartmut Hackmann
+ * 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 _ISL6405_H
+#define _ISL6405_H
+
+#include <linux/dvb/frontend.h>
+
+/* system register bits */
+
+/* this bit selects register (control) 1 or 2
+   note that the bit maps are different */
+
+#define ISL6405_SR	0x80
+
+/* SR = 0 */
+#define ISL6405_OLF1	0x01
+#define ISL6405_EN1	0x02
+#define ISL6405_VSEL1	0x04
+#define ISL6405_LLC1	0x08
+#define ISL6405_ENT1	0x10
+#define ISL6405_ISEL1	0x20
+#define ISL6405_DCL	0x40
+
+/* SR = 1 */
+#define ISL6405_OLF2	0x01
+#define ISL6405_OTF	0x02
+#define ISL6405_EN2	0x04
+#define ISL6405_VSEL2	0x08
+#define ISL6405_LLC2	0x10
+#define ISL6405_ENT2	0x20
+#define ISL6405_ISEL2	0x40
+
+#if defined(CONFIG_DVB_ISL6405) || (defined(CONFIG_DVB_ISL6405_MODULE) && defined(MODULE))
+/* override_set and override_clear control which system register bits (above)
+ * to always set & clear
+ */
+extern struct dvb_frontend *isl6405_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c,
+					   u8 i2c_addr, u8 override_set, u8 override_clear);
+#else
+static inline struct dvb_frontend *isl6405_attach(struct dvb_frontend *fe,
+						  struct i2c_adapter *i2c, u8 i2c_addr,
+						  u8 override_set, u8 override_clear)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_ISL6405 */
+
+#endif
diff --git a/drivers/media/dvb/frontends/isl6421.h b/drivers/media/dvb/frontends/isl6421.h
index ea7f78a..47e4518 100644
--- a/drivers/media/dvb/frontends/isl6421.h
+++ b/drivers/media/dvb/frontends/isl6421.h
@@ -47,7 +47,7 @@
 static inline struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
 						  u8 override_set, u8 override_clear)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_ISL6421
diff --git a/drivers/media/dvb/frontends/itd1000.c b/drivers/media/dvb/frontends/itd1000.c
new file mode 100644
index 0000000..04c562c
--- /dev/null
+++ b/drivers/media/dvb/frontends/itd1000.c
@@ -0,0 +1,400 @@
+/*
+ *  Driver for the Integrant ITD1000 "Zero-IF Tuner IC for Direct Broadcast Satellite"
+ *
+ *  Copyright (c) 2007-8 Patrick Boettcher <pb@linuxtv.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/moduleparam.h>
+#include <linux/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+
+#include "itd1000.h"
+#include "itd1000_priv.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+#define deb(args...)  do { \
+	if (debug) { \
+		printk(KERN_DEBUG   "ITD1000: " args);\
+		printk("\n"); \
+	} \
+} while (0)
+
+#define warn(args...) do { \
+	printk(KERN_WARNING "ITD1000: " args); \
+	printk("\n"); \
+} while (0)
+
+#define info(args...) do { \
+	printk(KERN_INFO    "ITD1000: " args); \
+	printk("\n"); \
+} while (0)
+
+/* don't write more than one byte with flexcop behind */
+static int itd1000_write_regs(struct itd1000_state *state, u8 reg, u8 v[], u8 len)
+{
+	u8 buf[1+len];
+	struct i2c_msg msg = {
+		.addr = state->cfg->i2c_address, .flags = 0, .buf = buf, .len = len+1
+	};
+	buf[0] = reg;
+	memcpy(&buf[1], v, len);
+
+	/* deb("wr %02x: %02x", reg, v[0]); */
+
+	if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+		printk(KERN_WARNING "itd1000 I2C write failed\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int itd1000_read_reg(struct itd1000_state *state, u8 reg)
+{
+	u8 val;
+	struct i2c_msg msg[2] = {
+		{ .addr = state->cfg->i2c_address, .flags = 0,        .buf = &reg, .len = 1 },
+		{ .addr = state->cfg->i2c_address, .flags = I2C_M_RD, .buf = &val, .len = 1 },
+	};
+
+	/* ugly flexcop workaround */
+	itd1000_write_regs(state, (reg - 1) & 0xff, &state->shadow[(reg - 1) & 0xff], 1);
+
+	if (i2c_transfer(state->i2c, msg, 2) != 2) {
+		warn("itd1000 I2C read failed");
+		return -EREMOTEIO;
+	}
+	return val;
+}
+
+static inline int itd1000_write_reg(struct itd1000_state *state, u8 r, u8 v)
+{
+	int ret = itd1000_write_regs(state, r, &v, 1);
+	state->shadow[r] = v;
+	return ret;
+}
+
+
+static struct {
+	u32 symbol_rate;
+	u8  pgaext  : 4; /* PLLFH */
+	u8  bbgvmin : 4; /* BBGVMIN */
+} itd1000_lpf_pga[] = {
+	{        0, 0x8, 0x3 },
+	{  5200000, 0x8, 0x3 },
+	{ 12200000, 0x4, 0x3 },
+	{ 15400000, 0x2, 0x3 },
+	{ 19800000, 0x2, 0x3 },
+	{ 21500000, 0x2, 0x3 },
+	{ 24500000, 0x2, 0x3 },
+	{ 28400000, 0x2, 0x3 },
+	{ 33400000, 0x2, 0x3 },
+	{ 34400000, 0x1, 0x4 },
+	{ 34400000, 0x1, 0x4 },
+	{ 38400000, 0x1, 0x4 },
+	{ 38400000, 0x1, 0x4 },
+	{ 40400000, 0x1, 0x4 },
+	{ 45400000, 0x1, 0x4 },
+};
+
+static void itd1000_set_lpf_bw(struct itd1000_state *state, u32 symbol_rate)
+{
+	u8 i;
+	u8 con1    = itd1000_read_reg(state, CON1)    & 0xfd;
+	u8 pllfh   = itd1000_read_reg(state, PLLFH)   & 0x0f;
+	u8 bbgvmin = itd1000_read_reg(state, BBGVMIN) & 0xf0;
+	u8 bw      = itd1000_read_reg(state, BW)      & 0xf0;
+
+	deb("symbol_rate = %d", symbol_rate);
+
+	/* not sure what is that ? - starting to download the table */
+	itd1000_write_reg(state, CON1, con1 | (1 << 1));
+
+	for (i = 0; i < ARRAY_SIZE(itd1000_lpf_pga); i++)
+		if (symbol_rate < itd1000_lpf_pga[i].symbol_rate) {
+			deb("symrate: index: %d pgaext: %x, bbgvmin: %x", i, itd1000_lpf_pga[i].pgaext, itd1000_lpf_pga[i].bbgvmin);
+			itd1000_write_reg(state, PLLFH,   pllfh | (itd1000_lpf_pga[i].pgaext << 4));
+			itd1000_write_reg(state, BBGVMIN, bbgvmin | (itd1000_lpf_pga[i].bbgvmin));
+			itd1000_write_reg(state, BW,      bw | (i & 0x0f));
+			break;
+		}
+
+	itd1000_write_reg(state, CON1, con1 | (0 << 1));
+}
+
+static struct {
+	u8 vcorg;
+	u32 fmax_rg;
+} itd1000_vcorg[] = {
+	{  1,  920000 },
+	{  2,  971000 },
+	{  3, 1031000 },
+	{  4, 1091000 },
+	{  5, 1171000 },
+	{  6, 1281000 },
+	{  7, 1381000 },
+	{  8,  500000 },	/* this is intentional. */
+	{  9, 1451000 },
+	{ 10, 1531000 },
+	{ 11, 1631000 },
+	{ 12, 1741000 },
+	{ 13, 1891000 },
+	{ 14, 2071000 },
+	{ 15, 2250000 },
+};
+
+static void itd1000_set_vco(struct itd1000_state *state, u32 freq_khz)
+{
+	u8 i;
+	u8 gvbb_i2c     = itd1000_read_reg(state, GVBB_I2C) & 0xbf;
+	u8 vco_chp1_i2c = itd1000_read_reg(state, VCO_CHP1_I2C) & 0x0f;
+	u8 adcout;
+
+	/* reserved bit again (reset ?) */
+	itd1000_write_reg(state, GVBB_I2C, gvbb_i2c | (1 << 6));
+
+	for (i = 0; i < ARRAY_SIZE(itd1000_vcorg); i++) {
+		if (freq_khz < itd1000_vcorg[i].fmax_rg) {
+			itd1000_write_reg(state, VCO_CHP1_I2C, vco_chp1_i2c | (itd1000_vcorg[i].vcorg << 4));
+			msleep(1);
+
+			adcout = itd1000_read_reg(state, PLLLOCK) & 0x0f;
+
+			deb("VCO: %dkHz: %d -> ADCOUT: %d %02x", freq_khz, itd1000_vcorg[i].vcorg, adcout, vco_chp1_i2c);
+
+			if (adcout > 13) {
+				if (!(itd1000_vcorg[i].vcorg == 7 || itd1000_vcorg[i].vcorg == 15))
+					itd1000_write_reg(state, VCO_CHP1_I2C, vco_chp1_i2c | ((itd1000_vcorg[i].vcorg + 1) << 4));
+			} else if (adcout < 2) {
+				if (!(itd1000_vcorg[i].vcorg == 1 || itd1000_vcorg[i].vcorg == 9))
+					itd1000_write_reg(state, VCO_CHP1_I2C, vco_chp1_i2c | ((itd1000_vcorg[i].vcorg - 1) << 4));
+			}
+			break;
+		}
+	}
+}
+
+struct {
+	u32 freq;
+	u8 values[10]; /* RFTR, RFST1 - RFST9 */
+} itd1000_fre_values[] = {
+	{ 1075000, { 0x59, 0x1d, 0x1c, 0x17, 0x16, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a } },
+	{ 1250000, { 0x89, 0x1e, 0x1d, 0x17, 0x15, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a } },
+	{ 1450000, { 0x89, 0x1e, 0x1d, 0x17, 0x15, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a } },
+	{ 1650000, { 0x69, 0x1e, 0x1d, 0x17, 0x15, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a } },
+	{ 1750000, { 0x69, 0x1e, 0x17, 0x15, 0x14, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a } },
+	{ 1850000, { 0x69, 0x1d, 0x17, 0x16, 0x14, 0x0f, 0x0e, 0x0d, 0x0b, 0x0a } },
+	{ 1900000, { 0x69, 0x1d, 0x17, 0x15, 0x14, 0x0f, 0x0e, 0x0d, 0x0b, 0x0a } },
+	{ 1950000, { 0x69, 0x1d, 0x17, 0x16, 0x14, 0x13, 0x0e, 0x0d, 0x0b, 0x0a } },
+	{ 2050000, { 0x69, 0x1e, 0x1d, 0x17, 0x16, 0x14, 0x13, 0x0e, 0x0b, 0x0a } },
+	{ 2150000, { 0x69, 0x1d, 0x1c, 0x17, 0x15, 0x14, 0x13, 0x0f, 0x0e, 0x0b } }
+};
+
+
+#define FREF 16
+
+static void itd1000_set_lo(struct itd1000_state *state, u32 freq_khz)
+{
+	int i, j;
+	u32 plln, pllf;
+	u64 tmp;
+
+	plln = (freq_khz * 1000) / 2 / FREF;
+
+	/* Compute the factional part times 1000 */
+	tmp  = plln % 1000000;
+	plln /= 1000000;
+
+	tmp *= 1048576;
+	do_div(tmp, 1000000);
+	pllf = (u32) tmp;
+
+	state->frequency = ((plln * 1000) + (pllf * 1000)/1048576) * 2*FREF;
+	deb("frequency: %dkHz (wanted) %dkHz (set), PLLF = %d, PLLN = %d", freq_khz, state->frequency, pllf, plln);
+
+	itd1000_write_reg(state, PLLNH, 0x80); /* PLLNH */;
+	itd1000_write_reg(state, PLLNL, plln & 0xff);
+	itd1000_write_reg(state, PLLFH, (itd1000_read_reg(state, PLLFH) & 0xf0) | ((pllf >> 16) & 0x0f));
+	itd1000_write_reg(state, PLLFM, (pllf >> 8) & 0xff);
+	itd1000_write_reg(state, PLLFL, (pllf >> 0) & 0xff);
+
+	for (i = 0; i < ARRAY_SIZE(itd1000_fre_values); i++) {
+		if (freq_khz <= itd1000_fre_values[i].freq) {
+			deb("fre_values: %d", i);
+			itd1000_write_reg(state, RFTR, itd1000_fre_values[i].values[0]);
+			for (j = 0; j < 9; j++)
+				itd1000_write_reg(state, RFST1+j, itd1000_fre_values[i].values[j+1]);
+			break;
+		}
+	}
+
+	itd1000_set_vco(state, freq_khz);
+}
+
+static int itd1000_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+{
+	struct itd1000_state *state = fe->tuner_priv;
+	u8 pllcon1;
+
+	itd1000_set_lo(state, p->frequency);
+	itd1000_set_lpf_bw(state, p->u.qpsk.symbol_rate);
+
+	pllcon1 = itd1000_read_reg(state, PLLCON1) & 0x7f;
+	itd1000_write_reg(state, PLLCON1, pllcon1 | (1 << 7));
+	itd1000_write_reg(state, PLLCON1, pllcon1);
+
+	return 0;
+}
+
+static int itd1000_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct itd1000_state *state = fe->tuner_priv;
+	*frequency = state->frequency;
+	return 0;
+}
+
+static int itd1000_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	return 0;
+}
+
+static u8 itd1000_init_tab[][2] = {
+	{ PLLCON1,       0x65 }, /* Register does not change */
+	{ PLLNH,         0x80 }, /* Bits [7:6] do not change */
+	{ RESERVED_0X6D, 0x3b },
+	{ VCO_CHP2_I2C,  0x12 },
+	{ 0x72,          0xf9 }, /* No such regsister defined */
+	{ RESERVED_0X73, 0xff },
+	{ RESERVED_0X74, 0xb2 },
+	{ RESERVED_0X75, 0xc7 },
+	{ EXTGVBBRF,     0xf0 },
+	{ DIVAGCCK,      0x80 },
+	{ BBTR,          0xa0 },
+	{ RESERVED_0X7E, 0x4f },
+	{ 0x82,          0x88 }, /* No such regsister defined */
+	{ 0x83,          0x80 }, /* No such regsister defined */
+	{ 0x84,          0x80 }, /* No such regsister defined */
+	{ RESERVED_0X85, 0x74 },
+	{ RESERVED_0X86, 0xff },
+	{ RESERVED_0X88, 0x02 },
+	{ RESERVED_0X89, 0x16 },
+	{ RFST0,         0x1f },
+	{ RESERVED_0X94, 0x66 },
+	{ RESERVED_0X95, 0x66 },
+	{ RESERVED_0X96, 0x77 },
+	{ RESERVED_0X97, 0x99 },
+	{ RESERVED_0X98, 0xff },
+	{ RESERVED_0X99, 0xfc },
+	{ RESERVED_0X9A, 0xba },
+	{ RESERVED_0X9B, 0xaa },
+};
+
+static u8 itd1000_reinit_tab[][2] = {
+	{ VCO_CHP1_I2C, 0x8a },
+	{ BW,           0x87 },
+	{ GVBB_I2C,     0x03 },
+	{ BBGVMIN,      0x03 },
+	{ CON1,         0x2e },
+};
+
+
+static int itd1000_init(struct dvb_frontend *fe)
+{
+	struct itd1000_state *state = fe->tuner_priv;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(itd1000_init_tab); i++)
+		itd1000_write_reg(state, itd1000_init_tab[i][0], itd1000_init_tab[i][1]);
+
+	for (i = 0; i < ARRAY_SIZE(itd1000_reinit_tab); i++)
+		itd1000_write_reg(state, itd1000_reinit_tab[i][0], itd1000_reinit_tab[i][1]);
+
+	return 0;
+}
+
+static int itd1000_sleep(struct dvb_frontend *fe)
+{
+	return 0;
+}
+
+static int itd1000_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static const struct dvb_tuner_ops itd1000_tuner_ops = {
+	.info = {
+		.name           = "Integrant ITD1000",
+		.frequency_min  = 950000,
+		.frequency_max  = 2150000,
+		.frequency_step = 125,     /* kHz for QPSK frontends */
+	},
+
+	.release       = itd1000_release,
+
+	.init          = itd1000_init,
+	.sleep         = itd1000_sleep,
+
+	.set_params    = itd1000_set_parameters,
+	.get_frequency = itd1000_get_frequency,
+	.get_bandwidth = itd1000_get_bandwidth
+};
+
+
+struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct itd1000_config *cfg)
+{
+	struct itd1000_state *state = NULL;
+	u8 i = 0;
+
+	state = kzalloc(sizeof(struct itd1000_state), GFP_KERNEL);
+	if (state == NULL)
+		return NULL;
+
+	state->cfg = cfg;
+	state->i2c = i2c;
+
+	i = itd1000_read_reg(state, 0);
+	if (i != 0) {
+		kfree(state);
+		return NULL;
+	}
+	info("successfully identified (ID: %d)", i);
+
+	memset(state->shadow, 0xff, sizeof(state->shadow));
+	for (i = 0x65; i < 0x9c; i++)
+		state->shadow[i] = itd1000_read_reg(state, i);
+
+	memcpy(&fe->ops.tuner_ops, &itd1000_tuner_ops, sizeof(struct dvb_tuner_ops));
+
+	fe->tuner_priv = state;
+
+	return fe;
+}
+EXPORT_SYMBOL(itd1000_attach);
+
+MODULE_AUTHOR("Patrick Boettcher <pb@linuxtv.org>");
+MODULE_DESCRIPTION("Integrant ITD1000 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/itd1000.h b/drivers/media/dvb/frontends/itd1000.h
new file mode 100644
index 0000000..5e18df0
--- /dev/null
+++ b/drivers/media/dvb/frontends/itd1000.h
@@ -0,0 +1,42 @@
+/*
+ *  Driver for the Integrant ITD1000 "Zero-IF Tuner IC for Direct Broadcast Satellite"
+ *
+ *  Copyright (c) 2007 Patrick Boettcher <pb@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef ITD1000_H
+#define ITD1000_H
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+struct itd1000_config {
+	u8 i2c_address;
+};
+
+#if defined(CONFIG_DVB_TUNER_ITD1000) || (defined(CONFIG_DVB_TUNER_ITD1000_MODULE) && defined(MODULE))
+extern struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct itd1000_config *cfg);
+#else
+static inline struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct itd1000_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/dvb/frontends/itd1000_priv.h b/drivers/media/dvb/frontends/itd1000_priv.h
new file mode 100644
index 0000000..8cdc54e
--- /dev/null
+++ b/drivers/media/dvb/frontends/itd1000_priv.h
@@ -0,0 +1,88 @@
+/*
+ *  Driver for the Integrant ITD1000 "Zero-IF Tuner IC for Direct Broadcast Satellite"
+ *
+ *  Copyright (c) 2007 Patrick Boettcher <pb@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef ITD1000_PRIV_H
+#define ITD1000_PRIV_H
+
+struct itd1000_state {
+	struct itd1000_config *cfg;
+	struct i2c_adapter    *i2c;
+
+	u32 frequency; /* contains the value resulting from the LO-setting */
+
+	/* ugly workaround for flexcop's incapable i2c-controller
+	 * FIXME, if possible
+	 */
+	u8 shadow[255];
+};
+
+enum itd1000_register {
+	VCO_CHP1 = 0x65,
+	VCO_CHP2,
+	PLLCON1,
+	PLLNH,
+	PLLNL,
+	PLLFH,
+	PLLFM,
+	PLLFL,
+	RESERVED_0X6D,
+	PLLLOCK,
+	VCO_CHP2_I2C,
+	VCO_CHP1_I2C,
+	BW,
+	RESERVED_0X73 = 0x73,
+	RESERVED_0X74,
+	RESERVED_0X75,
+	GVBB,
+	GVRF,
+	GVBB_I2C,
+	EXTGVBBRF,
+	DIVAGCCK,
+	BBTR,
+	RFTR,
+	BBGVMIN,
+	RESERVED_0X7E,
+	RESERVED_0X85 = 0x85,
+	RESERVED_0X86,
+	CON1,
+	RESERVED_0X88,
+	RESERVED_0X89,
+	RFST0,
+	RFST1,
+	RFST2,
+	RFST3,
+	RFST4,
+	RFST5,
+	RFST6,
+	RFST7,
+	RFST8,
+	RFST9,
+	RESERVED_0X94,
+	RESERVED_0X95,
+	RESERVED_0X96,
+	RESERVED_0X97,
+	RESERVED_0X98,
+	RESERVED_0X99,
+	RESERVED_0X9A,
+	RESERVED_0X9B,
+};
+
+#endif
diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c
index 443d904..e1e70e9 100644
--- a/drivers/media/dvb/frontends/l64781.c
+++ b/drivers/media/dvb/frontends/l64781.c
@@ -57,7 +57,7 @@
 
 	if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1)
 		dprintk ("%s: write_reg error (reg == %02x) = %02x!\n",
-			 __FUNCTION__, reg, ret);
+			 __func__, reg, ret);
 
 	return (ret != 1) ? -1 : 0;
 }
diff --git a/drivers/media/dvb/frontends/l64781.h b/drivers/media/dvb/frontends/l64781.h
index cd15f76..1305a9e 100644
--- a/drivers/media/dvb/frontends/l64781.h
+++ b/drivers/media/dvb/frontends/l64781.h
@@ -38,7 +38,7 @@
 static inline struct dvb_frontend* l64781_attach(const struct l64781_config* config,
 					  struct i2c_adapter* i2c)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_L64781
diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c
index bdc9fa8..f0195c8 100644
--- a/drivers/media/dvb/frontends/lgdt330x.c
+++ b/drivers/media/dvb/frontends/lgdt330x.c
@@ -49,7 +49,7 @@
 /* Use Equalizer Mean Squared Error instead of Phaser Tracker MSE */
 /* #define USE_EQMSE */
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug,"Turn on/off lgdt330x frontend debugging (default:off).");
 #define dprintk(args...) \
@@ -88,7 +88,7 @@
 
 	for (i=0; i<len-1; i+=2){
 		if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
-			printk(KERN_WARNING "lgdt330x: %s error (addr %02x <- %02x, err = %i)\n", __FUNCTION__, msg.buf[0], msg.buf[1], err);
+			printk(KERN_WARNING "lgdt330x: %s error (addr %02x <- %02x, err = %i)\n", __func__, msg.buf[0], msg.buf[1], err);
 			if (err < 0)
 				return err;
 			else
@@ -117,7 +117,7 @@
 	int ret;
 	ret = i2c_transfer(state->i2c, msg, 2);
 	if (ret != 2) {
-		printk(KERN_WARNING "lgdt330x: %s: addr 0x%02x select 0x%02x error (ret == %i)\n", __FUNCTION__, state->config->demod_address, reg, ret);
+		printk(KERN_WARNING "lgdt330x: %s: addr 0x%02x select 0x%02x error (ret == %i)\n", __func__, state->config->demod_address, reg, ret);
 	} else {
 		ret = 0;
 	}
@@ -256,7 +256,7 @@
 		printk (KERN_WARNING "Only LGDT3302 and LGDT3303 are supported chips.\n");
 		err = -ENODEV;
 	}
-	dprintk("%s entered as %s\n", __FUNCTION__, chip_name);
+	dprintk("%s entered as %s\n", __func__, chip_name);
 	if (err < 0)
 		return err;
 	return lgdt330x_SwReset(state);
@@ -334,7 +334,7 @@
 	if (state->current_modulation != param->u.vsb.modulation) {
 		switch(param->u.vsb.modulation) {
 		case VSB_8:
-			dprintk("%s: VSB_8 MODE\n", __FUNCTION__);
+			dprintk("%s: VSB_8 MODE\n", __func__);
 
 			/* Select VSB mode */
 			top_ctrl_cfg[1] = 0x03;
@@ -350,7 +350,7 @@
 			break;
 
 		case QAM_64:
-			dprintk("%s: QAM_64 MODE\n", __FUNCTION__);
+			dprintk("%s: QAM_64 MODE\n", __func__);
 
 			/* Select QAM_64 mode */
 			top_ctrl_cfg[1] = 0x00;
@@ -366,7 +366,7 @@
 			break;
 
 		case QAM_256:
-			dprintk("%s: QAM_256 MODE\n", __FUNCTION__);
+			dprintk("%s: QAM_256 MODE\n", __func__);
 
 			/* Select QAM_256 mode */
 			top_ctrl_cfg[1] = 0x01;
@@ -381,7 +381,7 @@
 			}
 			break;
 		default:
-			printk(KERN_WARNING "lgdt330x: %s: Modulation type(%d) UNSUPPORTED\n", __FUNCTION__, param->u.vsb.modulation);
+			printk(KERN_WARNING "lgdt330x: %s: Modulation type(%d) UNSUPPORTED\n", __func__, param->u.vsb.modulation);
 			return -1;
 		}
 		/*
@@ -431,7 +431,7 @@
 
 	/* AGC status register */
 	i2c_read_demod_bytes(state, AGC_STATUS, buf, 1);
-	dprintk("%s: AGC_STATUS = 0x%02x\n", __FUNCTION__, buf[0]);
+	dprintk("%s: AGC_STATUS = 0x%02x\n", __func__, buf[0]);
 	if ((buf[0] & 0x0c) == 0x8){
 		/* Test signal does not exist flag */
 		/* as well as the AGC lock flag.   */
@@ -445,7 +445,7 @@
 	 */
 	/* signal status */
 	i2c_read_demod_bytes(state, TOP_CONTROL, buf, sizeof(buf));
-	dprintk("%s: TOP_CONTROL = 0x%02x, IRO_MASK = 0x%02x, IRQ_STATUS = 0x%02x\n", __FUNCTION__, buf[0], buf[1], buf[2]);
+	dprintk("%s: TOP_CONTROL = 0x%02x, IRO_MASK = 0x%02x, IRQ_STATUS = 0x%02x\n", __func__, buf[0], buf[1], buf[2]);
 
 
 	/* sync status */
@@ -461,7 +461,7 @@
 
 	/* Carrier Recovery Lock Status Register */
 	i2c_read_demod_bytes(state, CARRIER_LOCK, buf, 1);
-	dprintk("%s: CARRIER_LOCK = 0x%02x\n", __FUNCTION__, buf[0]);
+	dprintk("%s: CARRIER_LOCK = 0x%02x\n", __func__, buf[0]);
 	switch (state->current_modulation) {
 	case QAM_256:
 	case QAM_64:
@@ -474,7 +474,7 @@
 			*status |= FE_HAS_CARRIER;
 		break;
 	default:
-		printk(KERN_WARNING "lgdt330x: %s: Modulation set to unsupported value\n", __FUNCTION__);
+		printk(KERN_WARNING "lgdt330x: %s: Modulation set to unsupported value\n", __func__);
 	}
 
 	return 0;
@@ -493,7 +493,7 @@
 	if (err < 0)
 		return err;
 
-	dprintk("%s: AGC_STATUS = 0x%02x\n", __FUNCTION__, buf[0]);
+	dprintk("%s: AGC_STATUS = 0x%02x\n", __func__, buf[0]);
 	if ((buf[0] & 0x21) == 0x01){
 		/* Test input signal does not exist flag */
 		/* as well as the AGC lock flag.   */
@@ -502,7 +502,7 @@
 
 	/* Carrier Recovery Lock Status Register */
 	i2c_read_demod_bytes(state, CARRIER_LOCK, buf, 1);
-	dprintk("%s: CARRIER_LOCK = 0x%02x\n", __FUNCTION__, buf[0]);
+	dprintk("%s: CARRIER_LOCK = 0x%02x\n", __func__, buf[0]);
 	switch (state->current_modulation) {
 	case QAM_256:
 	case QAM_64:
@@ -533,7 +533,7 @@
 		}
 		break;
 	default:
-		printk(KERN_WARNING "lgdt330x: %s: Modulation set to unsupported value\n", __FUNCTION__);
+		printk(KERN_WARNING "lgdt330x: %s: Modulation set to unsupported value\n", __func__);
 	}
 	return 0;
 }
@@ -607,14 +607,14 @@
 		break;
 	default:
 		printk(KERN_ERR "lgdt330x: %s: Modulation set to unsupported value\n",
-		       __FUNCTION__);
+		       __func__);
 		return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */
 	}
 
 	state->snr = calculate_snr(noise, c);
 	*snr = (state->snr) >> 16; /* Convert from 8.24 fixed-point to 8.8 */
 
-	dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __FUNCTION__, noise,
+	dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __func__, noise,
 		state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16);
 
 	return 0;
@@ -651,14 +651,14 @@
 		break;
 	default:
 		printk(KERN_ERR "lgdt330x: %s: Modulation set to unsupported value\n",
-		       __FUNCTION__);
+		       __func__);
 		return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */
 	}
 
 	state->snr = calculate_snr(noise, c);
 	*snr = (state->snr) >> 16; /* Convert from 8.24 fixed-point to 8.8 */
 
-	dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __FUNCTION__, noise,
+	dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __func__, noise,
 		state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16);
 
 	return 0;
@@ -743,7 +743,7 @@
 
 error:
 	kfree(state);
-	dprintk("%s: ERROR\n",__FUNCTION__);
+	dprintk("%s: ERROR\n",__func__);
 	return NULL;
 }
 
diff --git a/drivers/media/dvb/frontends/lgdt330x.h b/drivers/media/dvb/frontends/lgdt330x.h
index 9950590..9012504 100644
--- a/drivers/media/dvb/frontends/lgdt330x.h
+++ b/drivers/media/dvb/frontends/lgdt330x.h
@@ -59,7 +59,7 @@
 static inline struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config,
 					    struct i2c_adapter* i2c)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_LGDT330X
diff --git a/drivers/media/dvb/frontends/lnbp21.h b/drivers/media/dvb/frontends/lnbp21.h
index 68906ac..8fe094b 100644
--- a/drivers/media/dvb/frontends/lnbp21.h
+++ b/drivers/media/dvb/frontends/lnbp21.h
@@ -45,7 +45,7 @@
 #else
 static inline struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_LNBP21
diff --git a/drivers/media/dvb/frontends/mt2060.h b/drivers/media/dvb/frontends/mt2060.h
index 0a86eab..acba005 100644
--- a/drivers/media/dvb/frontends/mt2060.h
+++ b/drivers/media/dvb/frontends/mt2060.h
@@ -35,7 +35,7 @@
 #else
 static inline struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_TUNER_MT2060
diff --git a/drivers/media/dvb/frontends/mt2131.c b/drivers/media/dvb/frontends/mt2131.c
index 13cf166..e254bcf 100644
--- a/drivers/media/dvb/frontends/mt2131.c
+++ b/drivers/media/dvb/frontends/mt2131.c
@@ -110,7 +110,7 @@
 		priv->bandwidth = 0;
 
 	freq = params->frequency / 1000;  // Hz -> kHz
-	dprintk(1, "%s() freq=%d\n", __FUNCTION__, freq);
+	dprintk(1, "%s() freq=%d\n", __func__, freq);
 
 	f_lo1 = freq + MT2131_IF1 * 1000;
 	f_lo1 = (f_lo1 / 250) * 250;
@@ -187,7 +187,7 @@
 static int mt2131_get_frequency(struct dvb_frontend *fe, u32 *frequency)
 {
 	struct mt2131_priv *priv = fe->tuner_priv;
-	dprintk(1, "%s()\n", __FUNCTION__);
+	dprintk(1, "%s()\n", __func__);
 	*frequency = priv->frequency;
 	return 0;
 }
@@ -195,7 +195,7 @@
 static int mt2131_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
 {
 	struct mt2131_priv *priv = fe->tuner_priv;
-	dprintk(1, "%s()\n", __FUNCTION__);
+	dprintk(1, "%s()\n", __func__);
 	*bandwidth = priv->bandwidth;
 	return 0;
 }
@@ -214,7 +214,7 @@
 
 	mt2131_readreg(priv, 0x09, &afc_status);
 	dprintk(1, "%s() - LO Status = 0x%x, AFC Status = 0x%x\n",
-		__FUNCTION__, lock_status, afc_status);
+		__func__, lock_status, afc_status);
 
 	return 0;
 }
@@ -223,7 +223,7 @@
 {
 	struct mt2131_priv *priv = fe->tuner_priv;
 	int ret;
-	dprintk(1, "%s()\n", __FUNCTION__);
+	dprintk(1, "%s()\n", __func__);
 
 	if ((ret = mt2131_writeregs(priv, mt2131_config1,
 				    sizeof(mt2131_config1))) < 0)
@@ -243,7 +243,7 @@
 
 static int mt2131_release(struct dvb_frontend *fe)
 {
-	dprintk(1, "%s()\n", __FUNCTION__);
+	dprintk(1, "%s()\n", __func__);
 	kfree(fe->tuner_priv);
 	fe->tuner_priv = NULL;
 	return 0;
@@ -273,7 +273,7 @@
 	struct mt2131_priv *priv = NULL;
 	u8 id = 0;
 
-	dprintk(1, "%s()\n", __FUNCTION__);
+	dprintk(1, "%s()\n", __func__);
 
 	priv = kzalloc(sizeof(struct mt2131_priv), GFP_KERNEL);
 	if (priv == NULL)
diff --git a/drivers/media/dvb/frontends/mt2131.h b/drivers/media/dvb/frontends/mt2131.h
index 1e4ffe7..606d857 100644
--- a/drivers/media/dvb/frontends/mt2131.h
+++ b/drivers/media/dvb/frontends/mt2131.h
@@ -41,7 +41,7 @@
 						 struct mt2131_config *cfg,
 						 u16 if1)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif /* CONFIG_DVB_TUNER_MT2131 */
diff --git a/drivers/media/dvb/frontends/mt2266.h b/drivers/media/dvb/frontends/mt2266.h
index f31dd61..c5113ef 100644
--- a/drivers/media/dvb/frontends/mt2266.h
+++ b/drivers/media/dvb/frontends/mt2266.h
@@ -29,7 +29,7 @@
 #else
 static inline struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_TUNER_MT2266
diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c
index 1638301..081ca33 100644
--- a/drivers/media/dvb/frontends/mt312.c
+++ b/drivers/media/dvb/frontends/mt312.c
@@ -1,7 +1,8 @@
 /*
-    Driver for Zarlink VP310/MT312 Satellite Channel Decoder
+    Driver for Zarlink VP310/MT312/ZL10313 Satellite Channel Decoder
 
     Copyright (C) 2003 Andreas Oberritter <obi@linuxtv.org>
+    Copyright (C) 2008 Matthias Schwarzott <zzam@gentoo.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
@@ -43,7 +44,8 @@
 	struct dvb_frontend frontend;
 
 	u8 id;
-	u8 frequency;
+	unsigned long xtal;
+	u8 freq_mult;
 };
 
 static int debug;
@@ -53,12 +55,11 @@
 			printk(KERN_DEBUG "mt312: " args); \
 	} while (0)
 
-#define MT312_SYS_CLK		90000000UL	/* 90 MHz */
-#define MT312_LPOWER_SYS_CLK	60000000UL	/* 60 MHz */
 #define MT312_PLL_CLK		10000000UL	/* 10 MHz */
+#define MT312_PLL_CLK_10_111	10111000UL	/* 10.111 MHz */
 
 static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg,
-		      void *buf, const size_t count)
+		      u8 *buf, const size_t count)
 {
 	int ret;
 	struct i2c_msg msg[2];
@@ -76,7 +77,7 @@
 	ret = i2c_transfer(state->i2c, msg, 2);
 
 	if (ret != 2) {
-		printk(KERN_ERR "%s: ret == %d\n", __FUNCTION__, ret);
+		printk(KERN_ERR "%s: ret == %d\n", __func__, ret);
 		return -EREMOTEIO;
 	}
 
@@ -84,7 +85,7 @@
 		int i;
 		dprintk("R(%d):", reg & 0x7f);
 		for (i = 0; i < count; i++)
-			printk(" %02x", ((const u8 *) buf)[i]);
+			printk(" %02x", buf[i]);
 		printk("\n");
 	}
 
@@ -92,7 +93,7 @@
 }
 
 static int mt312_write(struct mt312_state *state, const enum mt312_reg_addr reg,
-		       const void *src, const size_t count)
+		       const u8 *src, const size_t count)
 {
 	int ret;
 	u8 buf[count + 1];
@@ -102,7 +103,7 @@
 		int i;
 		dprintk("W(%d):", reg & 0x7f);
 		for (i = 0; i < count; i++)
-			printk(" %02x", ((const u8 *) src)[i]);
+			printk(" %02x", src[i]);
 		printk("\n");
 	}
 
@@ -117,7 +118,7 @@
 	ret = i2c_transfer(state->i2c, &msg, 1);
 
 	if (ret != 1) {
-		dprintk("%s: ret == %d\n", __FUNCTION__, ret);
+		dprintk("%s: ret == %d\n", __func__, ret);
 		return -EREMOTEIO;
 	}
 
@@ -209,7 +210,7 @@
 		dprintk("sym_rat_op=%d dec_ratio=%d\n",
 		       sym_rat_op, dec_ratio);
 		dprintk("*sr(manual) = %lu\n",
-		       (((MT312_PLL_CLK * 8192) / (sym_rat_op + 8192)) *
+		       (((state->xtal * 8192) / (sym_rat_op + 8192)) *
 			2) - dec_ratio);
 	}
 
@@ -242,7 +243,7 @@
 
 	/* wake up */
 	ret = mt312_writereg(state, CONFIG,
-			(state->frequency == 60 ? 0x88 : 0x8c));
+			(state->freq_mult == 6 ? 0x88 : 0x8c));
 	if (ret < 0)
 		return ret;
 
@@ -265,12 +266,37 @@
 			return ret;
 	}
 
+	switch (state->id) {
+	case ID_ZL10313:
+		/* enable ADC */
+		ret = mt312_writereg(state, GPP_CTRL, 0x80);
+		if (ret < 0)
+			return ret;
+
+		/* configure ZL10313 for optimal ADC performance */
+		buf[0] = 0x80;
+		buf[1] = 0xB0;
+		ret = mt312_write(state, HW_CTRL, buf, 2);
+		if (ret < 0)
+			return ret;
+
+		/* enable MPEG output and ADCs */
+		ret = mt312_writereg(state, HW_CTRL, 0x00);
+		if (ret < 0)
+			return ret;
+
+		ret = mt312_writereg(state, MPEG_CTRL, 0x00);
+		if (ret < 0)
+			return ret;
+
+		break;
+	}
+
 	/* SYS_CLK */
-	buf[0] = mt312_div((state->frequency == 60 ? MT312_LPOWER_SYS_CLK :
-				MT312_SYS_CLK) * 2, 1000000);
+	buf[0] = mt312_div(state->xtal * state->freq_mult * 2, 1000000);
 
 	/* DISEQC_RATIO */
-	buf[1] = mt312_div(MT312_PLL_CLK, 15000 * 4);
+	buf[1] = mt312_div(state->xtal, 22000 * 4);
 
 	ret = mt312_write(state, SYS_CLK, buf, sizeof(buf));
 	if (ret < 0)
@@ -280,7 +306,17 @@
 	if (ret < 0)
 		return ret;
 
-	ret = mt312_writereg(state, OP_CTRL, 0x53);
+	/* different MOCLK polarity */
+	switch (state->id) {
+	case ID_ZL10313:
+		buf[0] = 0x33;
+		break;
+	default:
+		buf[0] = 0x53;
+		break;
+	}
+
+	ret = mt312_writereg(state, OP_CTRL, buf[0]);
 	if (ret < 0)
 		return ret;
 
@@ -323,6 +359,9 @@
 	if (ret < 0)
 		return ret;
 
+	/* is there a better way to wait for message to be transmitted */
+	msleep(100);
+
 	/* set DISEQC_MODE[2:0] to zero if a return message is expected */
 	if (c->msg[0] & 0x02) {
 		ret = mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40));
@@ -383,11 +422,16 @@
 {
 	struct mt312_state *state = fe->demodulator_priv;
 	const u8 volt_tab[3] = { 0x00, 0x40, 0x00 };
+	u8 val;
 
 	if (v > SEC_VOLTAGE_OFF)
 		return -EINVAL;
 
-	return mt312_writereg(state, DISEQC_MODE, volt_tab[v]);
+	val = volt_tab[v];
+	if (state->config->voltage_inverted)
+		val ^= 0x40;
+
+	return mt312_writereg(state, DISEQC_MODE, val);
 }
 
 static int mt312_read_status(struct dvb_frontend *fe, fe_status_t *s)
@@ -463,7 +507,7 @@
 	int ret;
 	u8 buf[2];
 
-	ret = mt312_read(state, M_SNR_H, &buf, sizeof(buf));
+	ret = mt312_read(state, M_SNR_H, buf, sizeof(buf));
 	if (ret < 0)
 		return ret;
 
@@ -478,7 +522,7 @@
 	int ret;
 	u8 buf[2];
 
-	ret = mt312_read(state, RS_UBC_H, &buf, sizeof(buf));
+	ret = mt312_read(state, RS_UBC_H, buf, sizeof(buf));
 	if (ret < 0)
 		return ret;
 
@@ -499,7 +543,7 @@
 	    { 0x00, 0x01, 0x02, 0x04, 0x3f, 0x08, 0x10, 0x20, 0x3f, 0x3f };
 	const u8 inv_tab[3] = { 0x00, 0x40, 0x80 };
 
-	dprintk("%s: Freq %d\n", __FUNCTION__, p->frequency);
+	dprintk("%s: Freq %d\n", __func__, p->frequency);
 
 	if ((p->frequency < fe->ops.info.frequency_min)
 	    || (p->frequency > fe->ops.info.frequency_max))
@@ -532,17 +576,17 @@
 			return ret;
 		if (p->u.qpsk.symbol_rate >= 30000000) {
 			/* Note that 30MS/s should use 90MHz */
-			if ((config_val & 0x0c) == 0x08) {
+			if (state->freq_mult == 6) {
 				/* We are running 60MHz */
-				state->frequency = 90;
+				state->freq_mult = 9;
 				ret = mt312_initfe(fe);
 				if (ret < 0)
 					return ret;
 			}
 		} else {
-			if ((config_val & 0x0c) == 0x0C) {
+			if (state->freq_mult == 9) {
 				/* We are running 90MHz */
-				state->frequency = 60;
+				state->freq_mult = 6;
 				ret = mt312_initfe(fe);
 				if (ret < 0)
 					return ret;
@@ -551,6 +595,7 @@
 		break;
 
 	case ID_MT312:
+	case ID_ZL10313:
 		break;
 
 	default:
@@ -616,11 +661,29 @@
 {
 	struct mt312_state *state = fe->demodulator_priv;
 
-	if (enable) {
-		return mt312_writereg(state, GPP_CTRL, 0x40);
-	} else {
-		return mt312_writereg(state, GPP_CTRL, 0x00);
+	u8 val = 0x00;
+	int ret;
+
+	switch (state->id) {
+	case ID_ZL10313:
+		ret = mt312_readreg(state, GPP_CTRL, &val);
+		if (ret < 0)
+			goto error;
+
+		/* preserve this bit to not accidently shutdown ADC */
+		val &= 0x80;
+		break;
 	}
+
+	if (enable)
+		val |= 0x40;
+	else
+		val &= ~0x40;
+
+	ret = mt312_writereg(state, GPP_CTRL, val);
+
+error:
+	return ret;
 }
 
 static int mt312_sleep(struct dvb_frontend *fe)
@@ -634,6 +697,18 @@
 	if (ret < 0)
 		return ret;
 
+	if (state->id == ID_ZL10313) {
+		/* reset ADC */
+		ret = mt312_writereg(state, GPP_CTRL, 0x00);
+		if (ret < 0)
+			return ret;
+
+		/* full shutdown of ADCs, mpeg bus tristated */
+		ret = mt312_writereg(state, HW_CTRL, 0x0d);
+		if (ret < 0)
+			return ret;
+	}
+
 	ret = mt312_readreg(state, CONFIG, &config);
 	if (ret < 0)
 		return ret;
@@ -661,6 +736,7 @@
 	kfree(state);
 }
 
+#define MT312_SYS_CLK		90000000UL	/* 90 MHz */
 static struct dvb_frontend_ops vp310_mt312_ops = {
 
 	.info = {
@@ -668,8 +744,8 @@
 		.type = FE_QPSK,
 		.frequency_min = 950000,
 		.frequency_max = 2150000,
-		.frequency_stepsize = (MT312_PLL_CLK / 1000) / 128,
-		.symbol_rate_min = MT312_SYS_CLK / 128,
+		.frequency_stepsize = (MT312_PLL_CLK / 1000) / 128, /* FIXME: adjust freq to real used xtal */
+		.symbol_rate_min = MT312_SYS_CLK / 128, /* FIXME as above */
 		.symbol_rate_max = MT312_SYS_CLK / 2,
 		.caps =
 		    FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
@@ -726,14 +802,21 @@
 	switch (state->id) {
 	case ID_VP310:
 		strcpy(state->frontend.ops.info.name, "Zarlink VP310 DVB-S");
-		state->frequency = 90;
+		state->xtal = MT312_PLL_CLK;
+		state->freq_mult = 9;
 		break;
 	case ID_MT312:
 		strcpy(state->frontend.ops.info.name, "Zarlink MT312 DVB-S");
-		state->frequency = 60;
+		state->xtal = MT312_PLL_CLK;
+		state->freq_mult = 6;
+		break;
+	case ID_ZL10313:
+		strcpy(state->frontend.ops.info.name, "Zarlink ZL10313 DVB-S");
+		state->xtal = MT312_PLL_CLK_10_111;
+		state->freq_mult = 9;
 		break;
 	default:
-		printk(KERN_WARNING "Only Zarlink VP310/MT312"
+		printk(KERN_WARNING "Only Zarlink VP310/MT312/ZL10313"
 			" are supported chips.\n");
 		goto error;
 	}
@@ -749,7 +832,7 @@
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
 
-MODULE_DESCRIPTION("Zarlink VP310/MT312 DVB-S Demodulator driver");
+MODULE_DESCRIPTION("Zarlink VP310/MT312/ZL10313 DVB-S Demodulator driver");
 MODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>");
 MODULE_LICENSE("GPL");
 
diff --git a/drivers/media/dvb/frontends/mt312.h b/drivers/media/dvb/frontends/mt312.h
index f17cb93..96338f0 100644
--- a/drivers/media/dvb/frontends/mt312.h
+++ b/drivers/media/dvb/frontends/mt312.h
@@ -31,6 +31,9 @@
 struct mt312_config {
 	/* the demodulator's i2c address */
 	u8 demod_address;
+
+	/* inverted voltage setting */
+	int voltage_inverted:1;
 };
 
 #if defined(CONFIG_DVB_MT312) || (defined(CONFIG_DVB_MT312_MODULE) && defined(MODULE))
@@ -40,7 +43,7 @@
 static inline struct dvb_frontend *vp310_mt312_attach(
 	const struct mt312_config *config, struct i2c_adapter *i2c)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif /* CONFIG_DVB_MT312 */
diff --git a/drivers/media/dvb/frontends/mt312_priv.h b/drivers/media/dvb/frontends/mt312_priv.h
index 5e0b95b..a3959f9 100644
--- a/drivers/media/dvb/frontends/mt312_priv.h
+++ b/drivers/media/dvb/frontends/mt312_priv.h
@@ -110,6 +110,8 @@
 	VIT_ERRPER_H = 83,
 	VIT_ERRPER_M = 84,
 	VIT_ERRPER_L = 85,
+	HW_CTRL = 84,	/* ZL10313 only */
+	MPEG_CTRL = 85,	/* ZL10313 only */
 	VIT_SETUP = 86,
 	VIT_REF0 = 87,
 	VIT_REF1 = 88,
@@ -156,7 +158,8 @@
 
 enum mt312_model_id {
 	ID_VP310 = 1,
-	ID_MT312 = 3
+	ID_MT312 = 3,
+	ID_ZL10313 = 5,
 };
 
 #endif				/* DVB_FRONTENDS_MT312_PRIV */
diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c
index 7cd190b..beba5aa 100644
--- a/drivers/media/dvb/frontends/mt352.c
+++ b/drivers/media/dvb/frontends/mt352.c
@@ -95,7 +95,7 @@
 
 	if (ret != 2) {
 		printk("%s: readreg error (reg=%d, ret==%i)\n",
-		       __FUNCTION__, reg, ret);
+		       __func__, reg, ret);
 		return ret;
 	}
 
@@ -135,7 +135,7 @@
 	value = 64 * bw * (1<<16) / (7 * 8);
 	value = value * 1000 / adc_clock;
 	dprintk("%s: bw %d, adc_clock %d => 0x%x\n",
-		__FUNCTION__, bw, adc_clock, value);
+		__func__, bw, adc_clock, value);
 	buf[0] = msb(value);
 	buf[1] = lsb(value);
 }
@@ -161,7 +161,7 @@
 	}
 	value = -16374 * ife / adc_clock;
 	dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n",
-		__FUNCTION__, if2, ife, adc_clock, value, value & 0x3fff);
+		__func__, if2, ife, adc_clock, value, value & 0x3fff);
 	buf[0] = msb(value);
 	buf[1] = lsb(value);
 }
@@ -521,7 +521,7 @@
 
 	static u8 mt352_reset_attach [] = { RESET, 0xC0 };
 
-	dprintk("%s: hello\n",__FUNCTION__);
+	dprintk("%s: hello\n",__func__);
 
 	if ((mt352_read_register(state, CLOCK_CTL) & 0x10) == 0 ||
 	    (mt352_read_register(state, CONFIG) & 0x20) == 0) {
diff --git a/drivers/media/dvb/frontends/mt352.h b/drivers/media/dvb/frontends/mt352.h
index e996408..595092f 100644
--- a/drivers/media/dvb/frontends/mt352.h
+++ b/drivers/media/dvb/frontends/mt352.h
@@ -58,7 +58,7 @@
 static inline struct dvb_frontend* mt352_attach(const struct mt352_config* config,
 					 struct i2c_adapter* i2c)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_MT352
diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c
index fcf964f..23d0228 100644
--- a/drivers/media/dvb/frontends/nxt200x.c
+++ b/drivers/media/dvb/frontends/nxt200x.c
@@ -74,7 +74,7 @@
 
 	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
 		printk (KERN_WARNING "nxt200x: %s: i2c write error (addr 0x%02x, err == %i)\n",
-			__FUNCTION__, addr, err);
+			__func__, addr, err);
 		return -EREMOTEIO;
 	}
 	return 0;
@@ -87,7 +87,7 @@
 
 	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
 		printk (KERN_WARNING "nxt200x: %s: i2c read error (addr 0x%02x, err == %i)\n",
-			__FUNCTION__, addr, err);
+			__func__, addr, err);
 		return -EREMOTEIO;
 	}
 	return 0;
@@ -104,7 +104,7 @@
 
 	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
 		printk (KERN_WARNING "nxt200x: %s: i2c write error (addr 0x%02x, err == %i)\n",
-			__FUNCTION__, state->config->demod_address, err);
+			__func__, state->config->demod_address, err);
 		return -EREMOTEIO;
 	}
 	return 0;
@@ -121,7 +121,7 @@
 
 	if ((err = i2c_transfer (state->i2c, msg, 2)) != 2) {
 		printk (KERN_WARNING "nxt200x: %s: i2c read error (addr 0x%02x, err == %i)\n",
-			__FUNCTION__, state->config->demod_address, err);
+			__func__, state->config->demod_address, err);
 		return -EREMOTEIO;
 	}
 	return 0;
@@ -146,7 +146,7 @@
 static int nxt200x_writereg_multibyte (struct nxt200x_state* state, u8 reg, u8* data, u8 len)
 {
 	u8 attr, len2, buf;
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	/* set mutli register register */
 	nxt200x_writebytes(state, 0x35, &reg, 1);
@@ -207,7 +207,7 @@
 {
 	int i;
 	u8 buf, len2, attr;
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	/* set mutli register register */
 	nxt200x_writebytes(state, 0x35, &reg, 1);
@@ -254,7 +254,7 @@
 static void nxt200x_microcontroller_stop (struct nxt200x_state* state)
 {
 	u8 buf, stopval, counter = 0;
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	/* set correct stop value */
 	switch (state->demod_chip) {
@@ -287,7 +287,7 @@
 static void nxt200x_microcontroller_start (struct nxt200x_state* state)
 {
 	u8 buf;
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	buf = 0x00;
 	nxt200x_writebytes(state, 0x22, &buf, 1);
@@ -297,7 +297,7 @@
 {
 	u8 buf[9];
 	u8 counter = 0;
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	buf[0] = 0x00;
 	nxt200x_writebytes(state, 0x2b, buf, 1);
@@ -328,7 +328,7 @@
 {
 	u8 buf, count = 0;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	dprintk("Tuner Bytes: %02X %02X %02X %02X\n", data[1], data[2], data[3], data[4]);
 
@@ -387,7 +387,7 @@
 static void nxt200x_agc_reset(struct nxt200x_state* state)
 {
 	u8 buf;
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	switch (state->demod_chip) {
 		case NXT2002:
@@ -416,7 +416,7 @@
 	u8 buf[3], written = 0, chunkpos = 0;
 	u16 rambase, position, crc = 0;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 	dprintk("Firmware is %zu bytes\n", fw->size);
 
 	/* Get the RAM base for this nxt2002 */
@@ -483,7 +483,7 @@
 	u8 buf[3];
 	u16 rambase, position, crc=0;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 	dprintk("Firmware is %zu bytes\n", fw->size);
 
 	/* set rambase */
diff --git a/drivers/media/dvb/frontends/nxt200x.h b/drivers/media/dvb/frontends/nxt200x.h
index bb0ef58..f3c8458 100644
--- a/drivers/media/dvb/frontends/nxt200x.h
+++ b/drivers/media/dvb/frontends/nxt200x.h
@@ -49,7 +49,7 @@
 static inline struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
 					   struct i2c_adapter* i2c)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_NXT200X
diff --git a/drivers/media/dvb/frontends/nxt6000.c b/drivers/media/dvb/frontends/nxt6000.c
index d313d7d..0eef22d 100644
--- a/drivers/media/dvb/frontends/nxt6000.c
+++ b/drivers/media/dvb/frontends/nxt6000.c
@@ -38,7 +38,7 @@
 	struct dvb_frontend frontend;
 };
 
-static int debug = 0;
+static int debug;
 #define dprintk if (debug) printk
 
 static int nxt6000_writereg(struct nxt6000_state* state, u8 reg, u8 data)
diff --git a/drivers/media/dvb/frontends/nxt6000.h b/drivers/media/dvb/frontends/nxt6000.h
index 13d2251..878eb38 100644
--- a/drivers/media/dvb/frontends/nxt6000.h
+++ b/drivers/media/dvb/frontends/nxt6000.h
@@ -40,7 +40,7 @@
 static inline struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
 					   struct i2c_adapter* i2c)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_NXT6000
diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c
index 8ffb8da..c7b5785 100644
--- a/drivers/media/dvb/frontends/or51132.c
+++ b/drivers/media/dvb/frontends/or51132.c
@@ -419,7 +419,7 @@
 		*status = 0;
 		return -EREMOTEIO;
 	}
-	dprintk("%s: read_status %04x\n", __FUNCTION__, reg);
+	dprintk("%s: read_status %04x\n", __func__, reg);
 
 	if (reg & 0x0100) /* Receiver Lock */
 		*status = FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI|
@@ -504,14 +504,14 @@
 		if (retry--) goto start;
 		return -EREMOTEIO;
 	}
-	dprintk("%s: modulation %02x, NTSC rej O%s\n", __FUNCTION__,
+	dprintk("%s: modulation %02x, NTSC rej O%s\n", __func__,
 		reg&0xff, reg&0x1000?"n":"ff");
 
 	/* Calculate SNR using noise, c, and NTSC rejection correction */
 	state->snr = calculate_snr(noise, c) - usK;
 	*snr = (state->snr) >> 16;
 
-	dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __FUNCTION__, noise,
+	dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __func__, noise,
 		state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16);
 
 	return 0;
diff --git a/drivers/media/dvb/frontends/or51132.h b/drivers/media/dvb/frontends/or51132.h
index add24f0..1b8e04d 100644
--- a/drivers/media/dvb/frontends/or51132.h
+++ b/drivers/media/dvb/frontends/or51132.h
@@ -41,7 +41,7 @@
 static inline struct dvb_frontend* or51132_attach(const struct or51132_config* config,
 					   struct i2c_adapter* i2c)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_OR51132
diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c
index 6a6b0d7..7eaa476 100644
--- a/drivers/media/dvb/frontends/or51211.c
+++ b/drivers/media/dvb/frontends/or51211.c
@@ -307,19 +307,19 @@
 
 	if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) {
 		printk(KERN_WARNING "%s: error writing snr reg\n",
-		       __FUNCTION__);
+		       __func__);
 		return -1;
 	}
 	if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
 		printk(KERN_WARNING "%s: read_status read error\n",
-		       __FUNCTION__);
+		       __func__);
 		return -1;
 	}
 
 	state->snr = calculate_snr(rec_buf[0], 89599047);
 	*snr = (state->snr) >> 16;
 
-	dprintk("%s: noise = 0x%02x, snr = %d.%02d dB\n", __FUNCTION__, rec_buf[0],
+	dprintk("%s: noise = 0x%02x, snr = %d.%02d dB\n", __func__, rec_buf[0],
 		state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16);
 
 	return 0;
diff --git a/drivers/media/dvb/frontends/or51211.h b/drivers/media/dvb/frontends/or51211.h
index 8aad840..3ce0508 100644
--- a/drivers/media/dvb/frontends/or51211.h
+++ b/drivers/media/dvb/frontends/or51211.h
@@ -44,7 +44,7 @@
 static inline struct dvb_frontend* or51211_attach(const struct or51211_config* config,
 					   struct i2c_adapter* i2c)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_OR51211
diff --git a/drivers/media/dvb/frontends/qt1010.h b/drivers/media/dvb/frontends/qt1010.h
index 3ab4aa0..cff6a7c 100644
--- a/drivers/media/dvb/frontends/qt1010.h
+++ b/drivers/media/dvb/frontends/qt1010.h
@@ -45,7 +45,7 @@
 						 struct i2c_adapter *i2c,
 						 struct qt1010_config *cfg)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_TUNER_QT1010
diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c
index 1a4d831..b999ec4 100644
--- a/drivers/media/dvb/frontends/s5h1409.c
+++ b/drivers/media/dvb/frontends/s5h1409.c
@@ -48,7 +48,7 @@
 	u32 qam_state;
 };
 
-static int debug = 0;
+static int debug;
 #define dprintk	if (debug) printk
 
 /* Register values to initialise the demod, this will set VSB by default */
@@ -312,7 +312,7 @@
 
 	if (ret != 1)
 		printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, "
-		       "ret == %i)\n", __FUNCTION__, reg, data, ret);
+		       "ret == %i)\n", __func__, reg, data, ret);
 
 	return (ret != 1) ? -1 : 0;
 }
@@ -332,7 +332,7 @@
 	ret = i2c_transfer(state->i2c, msg, 2);
 
 	if (ret != 2)
-		printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
+		printk("%s: readreg error (ret == %i)\n", __func__, ret);
 	return (b1[0] << 8) | b1[1];
 }
 
@@ -340,7 +340,7 @@
 {
 	struct s5h1409_state* state = fe->demodulator_priv;
 
-	dprintk("%s()\n", __FUNCTION__);
+	dprintk("%s()\n", __func__);
 
 	s5h1409_writereg(state, 0xf5, 0);
 	s5h1409_writereg(state, 0xf5, 1);
@@ -356,7 +356,7 @@
 {
 	struct s5h1409_state* state = fe->demodulator_priv;
 
-	dprintk("%s(%d KHz)\n", __FUNCTION__, KHz);
+	dprintk("%s(%d KHz)\n", __func__, KHz);
 
 	switch (KHz) {
 	case 4000:
@@ -381,7 +381,7 @@
 {
 	struct s5h1409_state* state = fe->demodulator_priv;
 
-	dprintk("%s(%d)\n", __FUNCTION__, inverted);
+	dprintk("%s(%d)\n", __func__, inverted);
 
 	if(inverted == 1)
 		return s5h1409_writereg(state, 0x1b, 0x1101); /* Inverted */
@@ -394,25 +394,25 @@
 {
 	struct s5h1409_state* state = fe->demodulator_priv;
 
-	dprintk("%s(0x%08x)\n", __FUNCTION__, m);
+	dprintk("%s(0x%08x)\n", __func__, m);
 
 	switch(m) {
 	case VSB_8:
-		dprintk("%s() VSB_8\n", __FUNCTION__);
+		dprintk("%s() VSB_8\n", __func__);
 		if (state->if_freq != S5H1409_VSB_IF_FREQ)
 			s5h1409_set_if_freq(fe, S5H1409_VSB_IF_FREQ);
 		s5h1409_writereg(state, 0xf4, 0);
 		break;
 	case QAM_64:
 	case QAM_256:
-		dprintk("%s() QAM_AUTO (64/256)\n", __FUNCTION__);
+		dprintk("%s() QAM_AUTO (64/256)\n", __func__);
 		if (state->if_freq != S5H1409_QAM_IF_FREQ)
 			s5h1409_set_if_freq(fe, S5H1409_QAM_IF_FREQ);
 		s5h1409_writereg(state, 0xf4, 1);
 		s5h1409_writereg(state, 0x85, 0x110);
 		break;
 	default:
-		dprintk("%s() Invalid modulation\n", __FUNCTION__);
+		dprintk("%s() Invalid modulation\n", __func__);
 		return -EINVAL;
 	}
 
@@ -426,7 +426,7 @@
 {
 	struct s5h1409_state* state = fe->demodulator_priv;
 
-	dprintk("%s(%d)\n", __FUNCTION__, enable);
+	dprintk("%s(%d)\n", __func__, enable);
 
 	if (enable)
 		return s5h1409_writereg(state, 0xf3, 1);
@@ -438,7 +438,7 @@
 {
 	struct s5h1409_state* state = fe->demodulator_priv;
 
-	dprintk("%s(%d)\n", __FUNCTION__, enable);
+	dprintk("%s(%d)\n", __func__, enable);
 
 	if (enable)
 		return s5h1409_writereg(state, 0xe3,
@@ -452,7 +452,7 @@
 {
 	struct s5h1409_state* state = fe->demodulator_priv;
 
-	dprintk("%s(%d)\n", __FUNCTION__, enable);
+	dprintk("%s(%d)\n", __func__, enable);
 
 	return s5h1409_writereg(state, 0xf2, enable);
 }
@@ -461,7 +461,7 @@
 {
 	struct s5h1409_state* state = fe->demodulator_priv;
 
-	dprintk("%s()\n", __FUNCTION__);
+	dprintk("%s()\n", __func__);
 
 	return s5h1409_writereg(state, 0xfa, 0);
 }
@@ -534,7 +534,7 @@
 {
 	struct s5h1409_state* state = fe->demodulator_priv;
 
-	dprintk("%s(frequency=%d)\n", __FUNCTION__, p->frequency);
+	dprintk("%s(frequency=%d)\n", __func__, p->frequency);
 
 	s5h1409_softreset(fe);
 
@@ -565,7 +565,7 @@
 	struct s5h1409_state *state = fe->demodulator_priv;
 	u16 val;
 
-	dprintk("%s(%d)\n", __FUNCTION__, mode);
+	dprintk("%s(%d)\n", __func__, mode);
 
 	val = s5h1409_readreg(state, 0xac) & 0xcfff;
 	switch (mode) {
@@ -573,7 +573,7 @@
 		val |= 0x0000;
 		break;
 	case S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK:
-		dprintk("%s(%d) Mode1 or Defaulting\n", __FUNCTION__, mode);
+		dprintk("%s(%d) Mode1 or Defaulting\n", __func__, mode);
 		val |= 0x1000;
 		break;
 	case S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK:
@@ -597,7 +597,7 @@
 	int i;
 
 	struct s5h1409_state* state = fe->demodulator_priv;
-	dprintk("%s()\n", __FUNCTION__);
+	dprintk("%s()\n", __func__);
 
 	s5h1409_sleep(fe, 0);
 	s5h1409_register_reset(fe);
@@ -663,7 +663,7 @@
 		break;
 	}
 
-	dprintk("%s() status 0x%08x\n", __FUNCTION__, *status);
+	dprintk("%s() status 0x%08x\n", __func__, *status);
 
 	return 0;
 }
@@ -671,7 +671,7 @@
 static int s5h1409_qam256_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
 {
 	int i, ret = -EINVAL;
-	dprintk("%s()\n", __FUNCTION__);
+	dprintk("%s()\n", __func__);
 
 	for (i=0; i < ARRAY_SIZE(qam256_snr_tab); i++) {
 		if (v < qam256_snr_tab[i].val) {
@@ -686,7 +686,7 @@
 static int s5h1409_qam64_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
 {
 	int i, ret = -EINVAL;
-	dprintk("%s()\n", __FUNCTION__);
+	dprintk("%s()\n", __func__);
 
 	for (i=0; i < ARRAY_SIZE(qam64_snr_tab); i++) {
 		if (v < qam64_snr_tab[i].val) {
@@ -701,7 +701,7 @@
 static int s5h1409_vsb_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
 {
 	int i, ret = -EINVAL;
-	dprintk("%s()\n", __FUNCTION__);
+	dprintk("%s()\n", __func__);
 
 	for (i=0; i < ARRAY_SIZE(vsb_snr_tab); i++) {
 		if (v > vsb_snr_tab[i].val) {
@@ -710,7 +710,7 @@
 			break;
 		}
 	}
-	dprintk("%s() snr=%d\n", __FUNCTION__, *snr);
+	dprintk("%s() snr=%d\n", __func__, *snr);
 	return ret;
 }
 
@@ -718,7 +718,7 @@
 {
 	struct s5h1409_state* state = fe->demodulator_priv;
 	u16 reg;
-	dprintk("%s()\n", __FUNCTION__);
+	dprintk("%s()\n", __func__);
 
 	switch(state->current_modulation) {
 	case QAM_64:
@@ -812,7 +812,7 @@
 
 	if (s5h1409_init(&state->frontend) != 0) {
 		printk(KERN_ERR "%s: Failed to initialize correctly\n",
-			__FUNCTION__);
+			__func__);
 		goto error;
 	}
 
diff --git a/drivers/media/dvb/frontends/s5h1409.h b/drivers/media/dvb/frontends/s5h1409.h
index f0bb13f..59f4335 100644
--- a/drivers/media/dvb/frontends/s5h1409.h
+++ b/drivers/media/dvb/frontends/s5h1409.h
@@ -67,7 +67,7 @@
 static inline struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
 						  struct i2c_adapter* i2c)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif /* CONFIG_DVB_S5H1409 */
diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c
index 2c2c344..281e1cb 100644
--- a/drivers/media/dvb/frontends/s5h1420.c
+++ b/drivers/media/dvb/frontends/s5h1420.c
@@ -1,24 +1,26 @@
 /*
-Driver for Samsung S5H1420 QPSK Demodulator
-
-Copyright (C) 2005 Andrew de Quincey <adq_dvb@lidskialf.net>
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
+ * Driver for
+ *    Samsung S5H1420 and
+ *    PnpNetwork PN1010 QPSK Demodulator
+ *
+ * Copyright (C) 2005 Andrew de Quincey <adq_dvb@lidskialf.net>
+ * Copyright (C) 2005-8 Patrick Boettcher <pb@linuxtv.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/kernel.h>
 #include <linux/module.h>
@@ -29,23 +31,35 @@
 #include <linux/jiffies.h>
 #include <asm/div64.h>
 
+#include <linux/i2c.h>
+
+
 #include "dvb_frontend.h"
 #include "s5h1420.h"
-
-
+#include "s5h1420_priv.h"
 
 #define TONE_FREQ 22000
 
 struct s5h1420_state {
 	struct i2c_adapter* i2c;
 	const struct s5h1420_config* config;
+
 	struct dvb_frontend frontend;
+	struct i2c_adapter tuner_i2c_adapter;
+
+	u8 CON_1_val;
 
 	u8 postlocked:1;
 	u32 fclk;
 	u32 tunedfreq;
 	fe_code_rate_t fec_inner;
 	u32 symbol_rate;
+
+	/* FIXME: ugly workaround for flexcop's incapable i2c-controller
+	 * it does not support repeated-start, workaround: write addr-1
+	 * and then read
+	 */
+	u8 shadow[255];
 };
 
 static u32 s5h1420_getsymbolrate(struct s5h1420_state* state);
@@ -53,44 +67,66 @@
 				     struct dvb_frontend_tune_settings* fesettings);
 
 
-static int debug = 0;
-#define dprintk if (debug) printk
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debugging");
+
+#define dprintk(x...) do { \
+	if (debug) \
+		printk(KERN_DEBUG "S5H1420: " x); \
+} while (0)
+
+static u8 s5h1420_readreg(struct s5h1420_state *state, u8 reg)
+{
+	int ret;
+	u8 b[2];
+	struct i2c_msg msg[] = {
+		{ .addr = state->config->demod_address, .flags = 0, .buf = b, .len = 2 },
+		{ .addr = state->config->demod_address, .flags = 0, .buf = &reg, .len = 1 },
+		{ .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = 1 },
+	};
+
+	b[0] = (reg - 1) & 0xff;
+	b[1] = state->shadow[(reg - 1) & 0xff];
+
+	if (state->config->repeated_start_workaround) {
+		ret = i2c_transfer(state->i2c, msg, 3);
+		if (ret != 3)
+			return ret;
+	} else {
+		ret = i2c_transfer(state->i2c, &msg[1], 2);
+		if (ret != 2)
+			return ret;
+	}
+
+	/* dprintk("rd(%02x): %02x %02x\n", state->config->demod_address, reg, b[0]); */
+
+	return b[0];
+}
 
 static int s5h1420_writereg (struct s5h1420_state* state, u8 reg, u8 data)
 {
-	u8 buf [] = { reg, data };
+	u8 buf[] = { reg, data };
 	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
 	int err;
 
-	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
-		dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __FUNCTION__, err, reg, data);
+	/* dprintk("wr(%02x): %02x %02x\n", state->config->demod_address, reg, data); */
+	err = i2c_transfer(state->i2c, &msg, 1);
+	if (err != 1) {
+		dprintk("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __func__, err, reg, data);
 		return -EREMOTEIO;
 	}
+	state->shadow[reg] = data;
 
 	return 0;
 }
 
-static u8 s5h1420_readreg (struct s5h1420_state* state, u8 reg)
-{
-	int ret;
-	u8 b0 [] = { reg };
-	u8 b1 [] = { 0 };
-	struct i2c_msg msg1 = { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 };
-	struct i2c_msg msg2 = { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 };
-
-	if ((ret = i2c_transfer (state->i2c, &msg1, 1)) != 1)
-		return ret;
-
-	if ((ret = i2c_transfer (state->i2c, &msg2, 1)) != 1)
-		return ret;
-
-	return b1[0];
-}
-
 static int s5h1420_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
 {
 	struct s5h1420_state* state = fe->demodulator_priv;
 
+	dprintk("enter %s\n", __func__);
+
 	switch(voltage) {
 	case SEC_VOLTAGE_13:
 		s5h1420_writereg(state, 0x3c,
@@ -106,6 +142,7 @@
 		break;
 	}
 
+	dprintk("leave %s\n", __func__);
 	return 0;
 }
 
@@ -113,6 +150,7 @@
 {
 	struct s5h1420_state* state = fe->demodulator_priv;
 
+	dprintk("enter %s\n", __func__);
 	switch(tone) {
 	case SEC_TONE_ON:
 		s5h1420_writereg(state, 0x3b,
@@ -124,6 +162,7 @@
 				 (s5h1420_readreg(state, 0x3b) & 0x74) | 0x01);
 		break;
 	}
+	dprintk("leave %s\n", __func__);
 
 	return 0;
 }
@@ -137,6 +176,7 @@
 	unsigned long timeout;
 	int result = 0;
 
+	dprintk("enter %s\n", __func__);
 	if (cmd->msg_len > 8)
 		return -EINVAL;
 
@@ -168,6 +208,7 @@
 	/* restore original settings */
 	s5h1420_writereg(state, 0x3b, val);
 	msleep(15);
+	dprintk("leave %s\n", __func__);
 	return result;
 }
 
@@ -289,6 +330,8 @@
 	struct s5h1420_state* state = fe->demodulator_priv;
 	u8 val;
 
+	dprintk("enter %s\n", __func__);
+
 	if (status == NULL)
 		return -EINVAL;
 
@@ -297,13 +340,13 @@
 
 	/* fix for FEC 5/6 inversion issue - if it doesn't quite lock, invert
 	the inversion, wait a bit and check again */
-	if (*status == (FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI)) {
-		val = s5h1420_readreg(state, 0x32);
+	if (*status == (FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI)) {
+		val = s5h1420_readreg(state, Vit10);
 		if ((val & 0x07) == 0x03) {
 			if (val & 0x08)
-				s5h1420_writereg(state, 0x31, 0x13);
+				s5h1420_writereg(state, Vit09, 0x13);
 			else
-				s5h1420_writereg(state, 0x31, 0x1b);
+				s5h1420_writereg(state, Vit09, 0x1b);
 
 			/* wait a bit then update lock status */
 			mdelay(200);
@@ -312,68 +355,73 @@
 	}
 
 	/* perform post lock setup */
-	if ((*status & FE_HAS_LOCK) && (!state->postlocked)) {
+	if ((*status & FE_HAS_LOCK) && !state->postlocked) {
 
 		/* calculate the data rate */
 		u32 tmp = s5h1420_getsymbolrate(state);
-		switch(s5h1420_readreg(state, 0x32) & 0x07) {
-		case 0:
-			tmp = (tmp * 2 * 1) / 2;
-			break;
-
-		case 1:
-			tmp = (tmp * 2 * 2) / 3;
-			break;
-
-		case 2:
-			tmp = (tmp * 2 * 3) / 4;
-			break;
-
-		case 3:
-			tmp = (tmp * 2 * 5) / 6;
-			break;
-
-		case 4:
-			tmp = (tmp * 2 * 6) / 7;
-			break;
-
-		case 5:
-			tmp = (tmp * 2 * 7) / 8;
-			break;
+		switch (s5h1420_readreg(state, Vit10) & 0x07) {
+		case 0: tmp = (tmp * 2 * 1) / 2; break;
+		case 1: tmp = (tmp * 2 * 2) / 3; break;
+		case 2: tmp = (tmp * 2 * 3) / 4; break;
+		case 3: tmp = (tmp * 2 * 5) / 6; break;
+		case 4: tmp = (tmp * 2 * 6) / 7; break;
+		case 5: tmp = (tmp * 2 * 7) / 8; break;
 		}
+
 		if (tmp == 0) {
-			printk("s5h1420: avoided division by 0\n");
+			printk(KERN_ERR "s5h1420: avoided division by 0\n");
 			tmp = 1;
 		}
 		tmp = state->fclk / tmp;
 
+
 		/* set the MPEG_CLK_INTL for the calculated data rate */
-		if (tmp < 4)
+		if (tmp < 2)
 			val = 0x00;
-		else if (tmp < 8)
+		else if (tmp < 5)
 			val = 0x01;
-		else if (tmp < 12)
+		else if (tmp < 9)
 			val = 0x02;
-		else if (tmp < 16)
+		else if (tmp < 13)
 			val = 0x03;
-		else if (tmp < 24)
+		else if (tmp < 17)
 			val = 0x04;
-		else if (tmp < 32)
+		else if (tmp < 25)
 			val = 0x05;
-		else
+		else if (tmp < 33)
 			val = 0x06;
-		s5h1420_writereg(state, 0x22, val);
+		else
+			val = 0x07;
+		dprintk("for MPEG_CLK_INTL %d %x\n", tmp, val);
 
-		/* DC freeze */
-		s5h1420_writereg(state, 0x1f, s5h1420_readreg(state, 0x1f) | 0x01);
+		s5h1420_writereg(state, FEC01, 0x18);
+		s5h1420_writereg(state, FEC01, 0x10);
+		s5h1420_writereg(state, FEC01, val);
 
-		/* kicker disable + remove DC offset */
-		s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) & 0x6f);
+		/* Enable "MPEG_Out" */
+		val = s5h1420_readreg(state, Mpeg02);
+		s5h1420_writereg(state, Mpeg02, val | (1 << 6));
+
+		/* kicker disable */
+		val = s5h1420_readreg(state, QPSK01) & 0x7f;
+		s5h1420_writereg(state, QPSK01, val);
+
+		/* DC freeze TODO it was never activated by default or it can stay activated */
+
+		if (s5h1420_getsymbolrate(state) >= 20000000) {
+			s5h1420_writereg(state, Loop04, 0x8a);
+			s5h1420_writereg(state, Loop05, 0x6a);
+		} else {
+			s5h1420_writereg(state, Loop04, 0x58);
+			s5h1420_writereg(state, Loop05, 0x27);
+		}
 
 		/* post-lock processing has been done! */
 		state->postlocked = 1;
 	}
 
+	dprintk("leave %s\n", __func__);
+
 	return 0;
 }
 
@@ -414,6 +462,7 @@
 
 static void s5h1420_reset(struct s5h1420_state* state)
 {
+	dprintk("%s\n", __func__);
 	s5h1420_writereg (state, 0x01, 0x08);
 	s5h1420_writereg (state, 0x01, 0x00);
 	udelay(10);
@@ -422,54 +471,52 @@
 static void s5h1420_setsymbolrate(struct s5h1420_state* state,
 				  struct dvb_frontend_parameters *p)
 {
+	u8 v;
 	u64 val;
 
+	dprintk("enter %s\n", __func__);
+
 	val = ((u64) p->u.qpsk.symbol_rate / 1000ULL) * (1ULL<<24);
-	if (p->u.qpsk.symbol_rate <= 21000000) {
+	if (p->u.qpsk.symbol_rate < 29000000)
 		val *= 2;
-	}
 	do_div(val, (state->fclk / 1000));
 
-	s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) & 0x7f);
-	s5h1420_writereg(state, 0x11, val >> 16);
-	s5h1420_writereg(state, 0x12, val >> 8);
-	s5h1420_writereg(state, 0x13, val & 0xff);
-	s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) | 0x80);
+	dprintk("symbol rate register: %06llx\n", val);
+
+	v = s5h1420_readreg(state, Loop01);
+	s5h1420_writereg(state, Loop01, v & 0x7f);
+	s5h1420_writereg(state, Tnco01, val >> 16);
+	s5h1420_writereg(state, Tnco02, val >> 8);
+	s5h1420_writereg(state, Tnco03, val & 0xff);
+	s5h1420_writereg(state, Loop01,  v | 0x80);
+	dprintk("leave %s\n", __func__);
 }
 
 static u32 s5h1420_getsymbolrate(struct s5h1420_state* state)
 {
-	u64 val = 0;
-	int sampling = 2;
-
-	if (s5h1420_readreg(state, 0x05) & 0x2)
-		sampling = 1;
-
-	s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) | 0x08);
-	val  = s5h1420_readreg(state, 0x11) << 16;
-	val |= s5h1420_readreg(state, 0x12) << 8;
-	val |= s5h1420_readreg(state, 0x13);
-	s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) & 0xf7);
-
-	val *= (state->fclk / 1000ULL);
-	do_div(val, ((1<<24) * sampling));
-
-	return (u32) (val * 1000ULL);
+	return state->symbol_rate;
 }
 
 static void s5h1420_setfreqoffset(struct s5h1420_state* state, int freqoffset)
 {
 	int val;
+	u8 v;
+
+	dprintk("enter %s\n", __func__);
 
 	/* remember freqoffset is in kHz, but the chip wants the offset in Hz, so
 	 * divide fclk by 1000000 to get the correct value. */
 	val = -(int) ((freqoffset * (1<<24)) / (state->fclk / 1000000));
 
-	s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) & 0xbf);
-	s5h1420_writereg(state, 0x0e, val >> 16);
-	s5h1420_writereg(state, 0x0f, val >> 8);
-	s5h1420_writereg(state, 0x10, val & 0xff);
-	s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) | 0x40);
+	dprintk("phase rotator/freqoffset: %d %06x\n", freqoffset, val);
+
+	v = s5h1420_readreg(state, Loop01);
+	s5h1420_writereg(state, Loop01, v & 0xbf);
+	s5h1420_writereg(state, Pnco01, val >> 16);
+	s5h1420_writereg(state, Pnco02, val >> 8);
+	s5h1420_writereg(state, Pnco03, val & 0xff);
+	s5h1420_writereg(state, Loop01, v | 0x40);
+	dprintk("leave %s\n", __func__);
 }
 
 static int s5h1420_getfreqoffset(struct s5h1420_state* state)
@@ -496,52 +543,53 @@
 				     struct dvb_frontend_parameters *p)
 {
 	u8 inversion = 0;
+	u8 vit08, vit09;
 
-	if (p->inversion == INVERSION_OFF) {
+	dprintk("enter %s\n", __func__);
+
+	if (p->inversion == INVERSION_OFF)
 		inversion = state->config->invert ? 0x08 : 0;
-	} else if (p->inversion == INVERSION_ON) {
+	else if (p->inversion == INVERSION_ON)
 		inversion = state->config->invert ? 0 : 0x08;
-	}
 
 	if ((p->u.qpsk.fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) {
-		s5h1420_writereg(state, 0x30, 0x3f);
-		s5h1420_writereg(state, 0x31, 0x00 | inversion);
+		vit08 = 0x3f;
+		vit09 = 0;
 	} else {
 		switch(p->u.qpsk.fec_inner) {
 		case FEC_1_2:
-			s5h1420_writereg(state, 0x30, 0x01);
-			s5h1420_writereg(state, 0x31, 0x10 | inversion);
+			vit08 = 0x01; vit09 = 0x10;
 			break;
 
 		case FEC_2_3:
-			s5h1420_writereg(state, 0x30, 0x02);
-			s5h1420_writereg(state, 0x31, 0x11 | inversion);
+			vit08 = 0x02; vit09 = 0x11;
 			break;
 
 		case FEC_3_4:
-			s5h1420_writereg(state, 0x30, 0x04);
-			s5h1420_writereg(state, 0x31, 0x12 | inversion);
+			vit08 = 0x04; vit09 = 0x12;
 			break;
 
 		case FEC_5_6:
-			s5h1420_writereg(state, 0x30, 0x08);
-			s5h1420_writereg(state, 0x31, 0x13 | inversion);
+			vit08 = 0x08; vit09 = 0x13;
 			break;
 
 		case FEC_6_7:
-			s5h1420_writereg(state, 0x30, 0x10);
-			s5h1420_writereg(state, 0x31, 0x14 | inversion);
+			vit08 = 0x10; vit09 = 0x14;
 			break;
 
 		case FEC_7_8:
-			s5h1420_writereg(state, 0x30, 0x20);
-			s5h1420_writereg(state, 0x31, 0x15 | inversion);
+			vit08 = 0x20; vit09 = 0x15;
 			break;
 
 		default:
 			return;
 		}
 	}
+	vit09 |= inversion;
+	dprintk("fec: %02x %02x\n", vit08, vit09);
+	s5h1420_writereg(state, Vit08, vit08);
+	s5h1420_writereg(state, Vit09, vit09);
+	dprintk("leave %s\n", __func__);
 }
 
 static fe_code_rate_t s5h1420_getfec(struct s5h1420_state* state)
@@ -583,16 +631,19 @@
 	struct s5h1420_state* state = fe->demodulator_priv;
 	int frequency_delta;
 	struct dvb_frontend_tune_settings fesettings;
+	uint8_t clock_settting;
+
+	dprintk("enter %s\n", __func__);
 
 	/* check if we should do a fast-tune */
 	memcpy(&fesettings.parameters, p, sizeof(struct dvb_frontend_parameters));
 	s5h1420_get_tune_settings(fe, &fesettings);
 	frequency_delta = p->frequency - state->tunedfreq;
 	if ((frequency_delta > -fesettings.max_drift) &&
-	    (frequency_delta < fesettings.max_drift) &&
-	    (frequency_delta != 0) &&
-	    (state->fec_inner == p->u.qpsk.fec_inner) &&
-	    (state->symbol_rate == p->u.qpsk.symbol_rate)) {
+			(frequency_delta < fesettings.max_drift) &&
+			(frequency_delta != 0) &&
+			(state->fec_inner == p->u.qpsk.fec_inner) &&
+			(state->symbol_rate == p->u.qpsk.symbol_rate)) {
 
 		if (fe->ops.tuner_ops.set_params) {
 			fe->ops.tuner_ops.set_params(fe, p);
@@ -606,54 +657,93 @@
 		} else {
 			s5h1420_setfreqoffset(state, 0);
 		}
+		dprintk("simple tune\n");
 		return 0;
 	}
+	dprintk("tuning demod\n");
 
 	/* first of all, software reset */
 	s5h1420_reset(state);
 
 	/* set s5h1420 fclk PLL according to desired symbol rate */
-	if (p->u.qpsk.symbol_rate > 28000000) {
-		state->fclk = 88000000;
-		s5h1420_writereg(state, 0x03, 0x50);
-		s5h1420_writereg(state, 0x04, 0x40);
-		s5h1420_writereg(state, 0x05, 0xae);
-	} else if (p->u.qpsk.symbol_rate > 21000000) {
+	if (p->u.qpsk.symbol_rate > 33000000)
+		state->fclk = 80000000;
+	else if (p->u.qpsk.symbol_rate > 28500000)
 		state->fclk = 59000000;
-		s5h1420_writereg(state, 0x03, 0x33);
-		s5h1420_writereg(state, 0x04, 0x40);
-		s5h1420_writereg(state, 0x05, 0xae);
-	} else {
+	else if (p->u.qpsk.symbol_rate > 25000000)
+		state->fclk = 86000000;
+	else if (p->u.qpsk.symbol_rate > 1900000)
 		state->fclk = 88000000;
-		s5h1420_writereg(state, 0x03, 0x50);
-		s5h1420_writereg(state, 0x04, 0x40);
-		s5h1420_writereg(state, 0x05, 0xac);
+	else
+		state->fclk = 44000000;
+
+	/* Clock */
+	switch (state->fclk) {
+	default:
+	case 88000000:
+		clock_settting = 80;
+		break;
+	case 86000000:
+		clock_settting = 78;
+		break;
+	case 80000000:
+		clock_settting = 72;
+		break;
+	case 59000000:
+		clock_settting = 51;
+		break;
+	case 44000000:
+		clock_settting = 36;
+		break;
 	}
+	dprintk("pll01: %d, ToneFreq: %d\n", state->fclk/1000000 - 8, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32));
+	s5h1420_writereg(state, PLL01, state->fclk/1000000 - 8);
+	s5h1420_writereg(state, PLL02, 0x40);
+	s5h1420_writereg(state, DiS01, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32));
+
+	/* TODO DC offset removal, config parameter ? */
+	if (p->u.qpsk.symbol_rate > 29000000)
+		s5h1420_writereg(state, QPSK01, 0xae | 0x10);
+	else
+		s5h1420_writereg(state, QPSK01, 0xac | 0x10);
 
 	/* set misc registers */
-	s5h1420_writereg(state, 0x02, 0x00);
-	s5h1420_writereg(state, 0x06, 0x00);
-	s5h1420_writereg(state, 0x07, 0xb0);
-	s5h1420_writereg(state, 0x0a, 0xe7);
-	s5h1420_writereg(state, 0x0b, 0x78);
-	s5h1420_writereg(state, 0x0c, 0x48);
-	s5h1420_writereg(state, 0x0d, 0x6b);
-	s5h1420_writereg(state, 0x2e, 0x8e);
-	s5h1420_writereg(state, 0x35, 0x33);
-	s5h1420_writereg(state, 0x38, 0x01);
-	s5h1420_writereg(state, 0x39, 0x7d);
-	s5h1420_writereg(state, 0x3a, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32));
-	s5h1420_writereg(state, 0x3c, 0x00);
-	s5h1420_writereg(state, 0x45, 0x61);
-	s5h1420_writereg(state, 0x46, 0x1d);
+	s5h1420_writereg(state, CON_1, 0x00);
+	s5h1420_writereg(state, QPSK02, 0x00);
+	s5h1420_writereg(state, Pre01, 0xb0);
 
-	/* start QPSK */
-	s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) | 1);
+	s5h1420_writereg(state, Loop01, 0xF0);
+	s5h1420_writereg(state, Loop02, 0x2a); /* e7 for s5h1420 */
+	s5h1420_writereg(state, Loop03, 0x79); /* 78 for s5h1420 */
+	if (p->u.qpsk.symbol_rate > 20000000)
+		s5h1420_writereg(state, Loop04, 0x79);
+	else
+		s5h1420_writereg(state, Loop04, 0x58);
+	s5h1420_writereg(state, Loop05, 0x6b);
+
+	if (p->u.qpsk.symbol_rate >= 8000000)
+		s5h1420_writereg(state, Post01, (0 << 6) | 0x10);
+	else if (p->u.qpsk.symbol_rate >= 4000000)
+		s5h1420_writereg(state, Post01, (1 << 6) | 0x10);
+	else
+		s5h1420_writereg(state, Post01, (3 << 6) | 0x10);
+
+	s5h1420_writereg(state, Monitor12, 0x00); /* unfreeze DC compensation */
+
+	s5h1420_writereg(state, Sync01, 0x33);
+	s5h1420_writereg(state, Mpeg01, state->config->cdclk_polarity);
+	s5h1420_writereg(state, Mpeg02, 0x3d); /* Parallel output more, disabled -> enabled later */
+	s5h1420_writereg(state, Err01, 0x03); /* 0x1d for s5h1420 */
+
+	s5h1420_writereg(state, Vit06, 0x6e); /* 0x8e for s5h1420 */
+	s5h1420_writereg(state, DiS03, 0x00);
+	s5h1420_writereg(state, Rf01, 0x61); /* Tuner i2c address - for the gate controller */
 
 	/* set tuner PLL */
 	if (fe->ops.tuner_ops.set_params) {
 		fe->ops.tuner_ops.set_params(fe, p);
-		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
 		s5h1420_setfreqoffset(state, 0);
 	}
 
@@ -661,10 +751,15 @@
 	s5h1420_setsymbolrate(state, p);
 	s5h1420_setfec_inversion(state, p);
 
+	/* start QPSK */
+	s5h1420_writereg(state, QPSK01, s5h1420_readreg(state, QPSK01) | 1);
+
 	state->fec_inner = p->u.qpsk.fec_inner;
 	state->symbol_rate = p->u.qpsk.symbol_rate;
 	state->postlocked = 0;
 	state->tunedfreq = p->frequency;
+
+	dprintk("leave %s\n", __func__);
 	return 0;
 }
 
@@ -717,11 +812,10 @@
 {
 	struct s5h1420_state* state = fe->demodulator_priv;
 
-	if (enable) {
-		return s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
-	} else {
-		return s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe);
-	}
+	if (enable)
+		return s5h1420_writereg(state, 0x02, state->CON_1_val | 1);
+	else
+		return s5h1420_writereg(state, 0x02, state->CON_1_val & 0xfe);
 }
 
 static int s5h1420_init (struct dvb_frontend* fe)
@@ -729,7 +823,8 @@
 	struct s5h1420_state* state = fe->demodulator_priv;
 
 	/* disable power down and do reset */
-	s5h1420_writereg(state, 0x02, 0x10);
+	state->CON_1_val = 0x10;
+	s5h1420_writereg(state, 0x02, state->CON_1_val);
 	msleep(10);
 	s5h1420_reset(state);
 
@@ -739,26 +834,60 @@
 static int s5h1420_sleep(struct dvb_frontend* fe)
 {
 	struct s5h1420_state* state = fe->demodulator_priv;
-
-	return s5h1420_writereg(state, 0x02, 0x12);
+	state->CON_1_val = 0x12;
+	return s5h1420_writereg(state, 0x02, state->CON_1_val);
 }
 
 static void s5h1420_release(struct dvb_frontend* fe)
 {
 	struct s5h1420_state* state = fe->demodulator_priv;
+	i2c_del_adapter(&state->tuner_i2c_adapter);
 	kfree(state);
 }
 
+static u32 s5h1420_tuner_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static int s5h1420_tuner_i2c_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
+{
+	struct s5h1420_state *state = i2c_get_adapdata(i2c_adap);
+	struct i2c_msg m[1 + num];
+	u8 tx_open[2] = { CON_1, state->CON_1_val | 1 }; /* repeater stops once there was a stop condition */
+
+	memset(m, 0, sizeof(struct i2c_msg) * (1 + num));
+
+	m[0].addr = state->config->demod_address;
+	m[0].buf  = tx_open;
+	m[0].len  = 2;
+
+	memcpy(&m[1], msg, sizeof(struct i2c_msg) * num);
+
+	return i2c_transfer(state->i2c, m, 1+num) == 1 + num ? num : -EIO;
+}
+
+static struct i2c_algorithm s5h1420_tuner_i2c_algo = {
+	.master_xfer   = s5h1420_tuner_i2c_tuner_xfer,
+	.functionality = s5h1420_tuner_i2c_func,
+};
+
+struct i2c_adapter *s5h1420_get_tuner_i2c_adapter(struct dvb_frontend *fe)
+{
+	struct s5h1420_state *state = fe->demodulator_priv;
+	return &state->tuner_i2c_adapter;
+}
+EXPORT_SYMBOL(s5h1420_get_tuner_i2c_adapter);
+
 static struct dvb_frontend_ops s5h1420_ops;
 
-struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
-				    struct i2c_adapter* i2c)
+struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config,
+				    struct i2c_adapter *i2c)
 {
-	struct s5h1420_state* state = NULL;
-	u8 identity;
-
 	/* allocate memory for the internal state */
-	state = kmalloc(sizeof(struct s5h1420_state), GFP_KERNEL);
+	struct s5h1420_state *state = kzalloc(sizeof(struct s5h1420_state), GFP_KERNEL);
+	u8 i;
+
 	if (state == NULL)
 		goto error;
 
@@ -772,24 +901,42 @@
 	state->symbol_rate = 0;
 
 	/* check if the demod is there + identify it */
-	identity = s5h1420_readreg(state, 0x00);
-	if (identity != 0x03)
+	i = s5h1420_readreg(state, ID01);
+	if (i != 0x03)
 		goto error;
 
+	memset(state->shadow, 0xff, sizeof(state->shadow));
+
+	for (i = 0; i < 0x50; i++)
+		state->shadow[i] = s5h1420_readreg(state, i);
+
 	/* create dvb_frontend */
 	memcpy(&state->frontend.ops, &s5h1420_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
+
+	/* create tuner i2c adapter */
+	strncpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus", I2C_NAME_SIZE);
+	state->tuner_i2c_adapter.class     = I2C_CLASS_TV_DIGITAL,
+	state->tuner_i2c_adapter.algo      = &s5h1420_tuner_i2c_algo;
+	state->tuner_i2c_adapter.algo_data = NULL;
+	i2c_set_adapdata(&state->tuner_i2c_adapter, state);
+	if (i2c_add_adapter(&state->tuner_i2c_adapter) < 0) {
+		printk(KERN_ERR "S5H1420/PN1010: tuner i2c bus could not be initialized\n");
+		goto error;
+	}
+
 	return &state->frontend;
 
 error:
 	kfree(state);
 	return NULL;
 }
+EXPORT_SYMBOL(s5h1420_attach);
 
 static struct dvb_frontend_ops s5h1420_ops = {
 
 	.info = {
-		.name     = "Samsung S5H1420 DVB-S",
+		.name     = "Samsung S5H1420/PnpNetwork PN1010 DVB-S",
 		.type     = FE_QPSK,
 		.frequency_min    = 950000,
 		.frequency_max    = 2150000,
@@ -826,10 +973,6 @@
 	.set_voltage = s5h1420_set_voltage,
 };
 
-module_param(debug, int, 0644);
-
-MODULE_DESCRIPTION("Samsung S5H1420 DVB-S Demodulator driver");
-MODULE_AUTHOR("Andrew de Quincey");
+MODULE_DESCRIPTION("Samsung S5H1420/PnpNetwork PN1010 DVB-S Demodulator driver");
+MODULE_AUTHOR("Andrew de Quincey, Patrick Boettcher");
 MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(s5h1420_attach);
diff --git a/drivers/media/dvb/frontends/s5h1420.h b/drivers/media/dvb/frontends/s5h1420.h
index 1555870..4c913f1 100644
--- a/drivers/media/dvb/frontends/s5h1420.h
+++ b/drivers/media/dvb/frontends/s5h1420.h
@@ -1,25 +1,26 @@
 /*
-    Driver for S5H1420 QPSK Demodulators
-
-    Copyright (C) 2005 Andrew de Quincey <adq_dvb@lidskialf.net>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
+ * Driver for
+ *    Samsung S5H1420 and
+ *    PnpNetwork PN1010 QPSK Demodulator
+ *
+ * Copyright (C) 2005 Andrew de Quincey <adq_dvb@lidskialf.net>
+ * Copyright (C) 2005-8 Patrick Boettcher <pb@linuxtv.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
 #ifndef S5H1420_H
 #define S5H1420_H
 
@@ -31,17 +32,26 @@
 	u8 demod_address;
 
 	/* does the inversion require inversion? */
-	u8 invert:1;
+	u8 invert : 1;
+
+	u8 repeated_start_workaround : 1;
+	u8 cdclk_polarity : 1; /* 1 == falling edge, 0 == raising edge */
 };
 
 #if defined(CONFIG_DVB_S5H1420) || (defined(CONFIG_DVB_S5H1420_MODULE) && defined(MODULE))
-extern struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
-	     struct i2c_adapter* i2c);
+extern struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config,
+	     struct i2c_adapter *i2c);
+extern struct i2c_adapter *s5h1420_get_tuner_i2c_adapter(struct dvb_frontend *fe);
 #else
-static inline struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
-					   struct i2c_adapter* i2c)
+static inline struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config,
+					   struct i2c_adapter *i2c)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+static inline struct i2c_adapter *s5h1420_get_tuner_i2c_adapter(struct dvb_frontend *fe)
+{
 	return NULL;
 }
 #endif // CONFIG_DVB_S5H1420
diff --git a/drivers/media/dvb/frontends/s5h1420_priv.h b/drivers/media/dvb/frontends/s5h1420_priv.h
new file mode 100644
index 0000000..d9c58d2
--- /dev/null
+++ b/drivers/media/dvb/frontends/s5h1420_priv.h
@@ -0,0 +1,102 @@
+/*
+ * Driver for
+ *    Samsung S5H1420 and
+ *    PnpNetwork PN1010 QPSK Demodulator
+ *
+ * Copyright (C) 2005 Andrew de Quincey <adq_dvb@lidskialf.net>
+ * Copyright (C) 2005 Patrick Boettcher <pb@linuxtv.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+ * Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef S5H1420_PRIV
+#define S5H1420_PRIV
+
+#include <asm/types.h>
+
+enum s5h1420_register {
+	ID01      = 0x00,
+	CON_0     = 0x01,
+	CON_1     = 0x02,
+	PLL01     = 0x03,
+	PLL02     = 0x04,
+	QPSK01    = 0x05,
+	QPSK02    = 0x06,
+	Pre01     = 0x07,
+	Post01    = 0x08,
+	Loop01    = 0x09,
+	Loop02    = 0x0a,
+	Loop03    = 0x0b,
+	Loop04    = 0x0c,
+	Loop05    = 0x0d,
+	Pnco01    = 0x0e,
+	Pnco02    = 0x0f,
+	Pnco03    = 0x10,
+	Tnco01    = 0x11,
+	Tnco02    = 0x12,
+	Tnco03    = 0x13,
+	Monitor01 = 0x14,
+	Monitor02 = 0x15,
+	Monitor03 = 0x16,
+	Monitor04 = 0x17,
+	Monitor05 = 0x18,
+	Monitor06 = 0x19,
+	Monitor07 = 0x1a,
+	Monitor12 = 0x1f,
+
+	FEC01     = 0x22,
+	Soft01    = 0x23,
+	Soft02    = 0x24,
+	Soft03    = 0x25,
+	Soft04    = 0x26,
+	Soft05    = 0x27,
+	Soft06    = 0x28,
+	Vit01     = 0x29,
+	Vit02     = 0x2a,
+	Vit03     = 0x2b,
+	Vit04     = 0x2c,
+	Vit05     = 0x2d,
+	Vit06     = 0x2e,
+	Vit07     = 0x2f,
+	Vit08     = 0x30,
+	Vit09     = 0x31,
+	Vit10     = 0x32,
+	Vit11     = 0x33,
+	Vit12     = 0x34,
+	Sync01    = 0x35,
+	Sync02    = 0x36,
+	Rs01      = 0x37,
+	Mpeg01    = 0x38,
+	Mpeg02    = 0x39,
+	DiS01     = 0x3a,
+	DiS02     = 0x3b,
+	DiS03     = 0x3c,
+	DiS04     = 0x3d,
+	DiS05     = 0x3e,
+	DiS06     = 0x3f,
+	DiS07     = 0x40,
+	DiS08     = 0x41,
+	DiS09     = 0x42,
+	DiS10     = 0x43,
+	DiS11     = 0x44,
+	Rf01      = 0x45,
+	Err01     = 0x46,
+	Err02     = 0x47,
+	Err03     = 0x48,
+	Err04     = 0x49,
+};
+
+
+#endif
diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c
index da876f7..aa78aa1 100644
--- a/drivers/media/dvb/frontends/sp8870.c
+++ b/drivers/media/dvb/frontends/sp8870.c
@@ -70,7 +70,7 @@
 	int err;
 
 	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
-		dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __FUNCTION__, err, reg, data);
+		dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __func__, err, reg, data);
 		return -EREMOTEIO;
 	}
 
@@ -88,7 +88,7 @@
 	ret = i2c_transfer (state->i2c, msg, 2);
 
 	if (ret != 2) {
-		dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
+		dprintk("%s: readreg error (ret == %i)\n", __func__, ret);
 		return -1;
 	}
 
@@ -104,7 +104,7 @@
 	int tx_len;
 	int err = 0;
 
-	dprintk ("%s: ...\n", __FUNCTION__);
+	dprintk ("%s: ...\n", __func__);
 
 	if (fw->size < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET)
 		return -EINVAL;
@@ -131,14 +131,14 @@
 		msg.buf = tx_buf;
 		msg.len = tx_len + 2;
 		if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
-			printk("%s: firmware upload failed!\n", __FUNCTION__);
-			printk ("%s: i2c error (err == %i)\n", __FUNCTION__, err);
+			printk("%s: firmware upload failed!\n", __func__);
+			printk ("%s: i2c error (err == %i)\n", __func__, err);
 			return err;
 		}
 		fw_pos += tx_len;
 	}
 
-	dprintk ("%s: done!\n", __FUNCTION__);
+	dprintk ("%s: done!\n", __func__);
 	return 0;
 };
 
@@ -310,7 +310,7 @@
 	if (state->initialised) return 0;
 	state->initialised = 1;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 
 	/* request the firmware, this will block until someone uploads it */
@@ -449,15 +449,15 @@
 	return 0;
 }
 
-// number of trials to recover from lockup
+/* number of trials to recover from lockup */
 #define MAXTRIALS 5
-// maximum checks for data valid signal
+/* maximum checks for data valid signal */
 #define MAXCHECKS 100
 
-// only for debugging: counter for detected lockups
-static int lockups = 0;
-// only for debugging: counter for channel switches
-static int switches = 0;
+/* only for debugging: counter for detected lockups */
+static int lockups;
+/* only for debugging: counter for channel switches */
+static int switches;
 
 static int sp8870_set_frontend (struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
 {
@@ -475,7 +475,7 @@
 	int trials = 0;
 	int check_count = 0;
 
-	dprintk("%s: frequency = %i\n", __FUNCTION__, p->frequency);
+	dprintk("%s: frequency = %i\n", __func__, p->frequency);
 
 	for (trials = 1; trials <= MAXTRIALS; trials++) {
 
@@ -487,7 +487,7 @@
 			valid = sp8870_read_data_valid_signal(state);
 			if (valid) {
 				dprintk("%s: delay = %i usec\n",
-					__FUNCTION__, check_count * 10);
+					__func__, check_count * 10);
 				break;
 			}
 			udelay(10);
@@ -497,20 +497,20 @@
 	}
 
 	if (!valid) {
-		printk("%s: firmware crash!!!!!!\n", __FUNCTION__);
+		printk("%s: firmware crash!!!!!!\n", __func__);
 		return -EIO;
 	}
 
 	if (debug) {
 		if (valid) {
 			if (trials > 1) {
-				printk("%s: firmware lockup!!!\n", __FUNCTION__);
-				printk("%s: recovered after %i trial(s))\n",  __FUNCTION__, trials - 1);
+				printk("%s: firmware lockup!!!\n", __func__);
+				printk("%s: recovered after %i trial(s))\n",  __func__, trials - 1);
 				lockups++;
 			}
 		}
 		switches++;
-		printk("%s: switches = %i lockups = %i\n", __FUNCTION__, switches, lockups);
+		printk("%s: switches = %i lockups = %i\n", __func__, switches, lockups);
 	}
 
 	return 0;
diff --git a/drivers/media/dvb/frontends/sp8870.h b/drivers/media/dvb/frontends/sp8870.h
index 909cefe..a764a79 100644
--- a/drivers/media/dvb/frontends/sp8870.h
+++ b/drivers/media/dvb/frontends/sp8870.h
@@ -42,7 +42,7 @@
 static inline struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
 					  struct i2c_adapter* i2c)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_SP8870
diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c
index 1aa2539f..49f5587 100644
--- a/drivers/media/dvb/frontends/sp887x.c
+++ b/drivers/media/dvb/frontends/sp887x.c
@@ -43,7 +43,7 @@
 
 	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
 		printk ("%s: i2c write error (addr %02x, err == %i)\n",
-			__FUNCTION__, state->config->demod_address, err);
+			__func__, state->config->demod_address, err);
 		return -EREMOTEIO;
 	}
 
@@ -65,7 +65,7 @@
 		{
 			printk("%s: writereg error "
 			       "(reg %03x, data %03x, ret == %i)\n",
-			       __FUNCTION__, reg & 0xffff, data & 0xffff, ret);
+			       __func__, reg & 0xffff, data & 0xffff, ret);
 			return ret;
 		}
 	}
@@ -82,7 +82,7 @@
 			 { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 2 }};
 
 	if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) {
-		printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
+		printk("%s: readreg error (ret == %i)\n", __func__, ret);
 		return -1;
 	}
 
@@ -91,7 +91,7 @@
 
 static void sp887x_microcontroller_stop (struct sp887x_state* state)
 {
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 	sp887x_writereg(state, 0xf08, 0x000);
 	sp887x_writereg(state, 0xf09, 0x000);
 
@@ -101,7 +101,7 @@
 
 static void sp887x_microcontroller_start (struct sp887x_state* state)
 {
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 	sp887x_writereg(state, 0xf08, 0x000);
 	sp887x_writereg(state, 0xf09, 0x000);
 
@@ -112,7 +112,7 @@
 static void sp887x_setup_agc (struct sp887x_state* state)
 {
 	/* setup AGC parameters */
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 	sp887x_writereg(state, 0x33c, 0x054);
 	sp887x_writereg(state, 0x33b, 0x04c);
 	sp887x_writereg(state, 0x328, 0x000);
@@ -142,7 +142,7 @@
 	int fw_size = fw->size;
 	unsigned char *mem = fw->data;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	/* ignore the first 10 bytes, then we expect 0x4000 bytes of firmware */
 	if (fw_size < FW_SIZE+10)
@@ -155,7 +155,7 @@
 
 	sp887x_microcontroller_stop (state);
 
-	printk ("%s: firmware upload... ", __FUNCTION__);
+	printk ("%s: firmware upload... ", __func__);
 
 	/* setup write pointer to -1 (end of memory) */
 	/* bit 0x8000 in address is set to enable 13bit mode */
@@ -181,7 +181,7 @@
 
 		if ((err = i2c_writebytes (state, buf, c+2)) < 0) {
 			printk ("failed.\n");
-			printk ("%s: i2c error (err == %i)\n", __FUNCTION__, err);
+			printk ("%s: i2c error (err == %i)\n", __func__, err);
 			return err;
 		}
 	}
diff --git a/drivers/media/dvb/frontends/sp887x.h b/drivers/media/dvb/frontends/sp887x.h
index 7ee78d7..04eff6e 100644
--- a/drivers/media/dvb/frontends/sp887x.h
+++ b/drivers/media/dvb/frontends/sp887x.h
@@ -24,7 +24,7 @@
 static inline struct dvb_frontend* sp887x_attach(const struct sp887x_config* config,
 					  struct i2c_adapter* i2c)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_SP887X
diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c
index 7c23775..62caf80 100644
--- a/drivers/media/dvb/frontends/stv0297.c
+++ b/drivers/media/dvb/frontends/stv0297.c
@@ -58,7 +58,7 @@
 
 	if (ret != 1)
 		dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
-			"ret == %i)\n", __FUNCTION__, reg, data, ret);
+			"ret == %i)\n", __func__, reg, data, ret);
 
 	return (ret != 1) ? -1 : 0;
 }
@@ -75,16 +75,16 @@
 	// this device needs a STOP between the register and data
 	if (state->config->stop_during_read) {
 		if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
-			dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
+			dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg, ret);
 			return -1;
 		}
 		if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
-			dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
+			dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg, ret);
 			return -1;
 		}
 	} else {
 		if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) {
-			dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
+			dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg, ret);
 			return -1;
 		}
 	}
@@ -115,16 +115,16 @@
 	// this device needs a STOP between the register and data
 	if (state->config->stop_during_read) {
 		if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
-			dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
+			dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg1, ret);
 			return -1;
 		}
 		if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
-			dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
+			dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg1, ret);
 			return -1;
 		}
 	} else {
 		if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) {
-			dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
+			dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg1, ret);
 			return -1;
 		}
 	}
diff --git a/drivers/media/dvb/frontends/stv0297.h b/drivers/media/dvb/frontends/stv0297.h
index 69f4515..3f8f946 100644
--- a/drivers/media/dvb/frontends/stv0297.h
+++ b/drivers/media/dvb/frontends/stv0297.h
@@ -49,7 +49,7 @@
 static inline struct dvb_frontend* stv0297_attach(const struct stv0297_config* config,
 					   struct i2c_adapter* i2c)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_STV0297
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c
index 035dd7b..1755618 100644
--- a/drivers/media/dvb/frontends/stv0299.c
+++ b/drivers/media/dvb/frontends/stv0299.c
@@ -86,7 +86,7 @@
 
 	if (ret != 1)
 		dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
-			"ret == %i)\n", __FUNCTION__, reg, data, ret);
+			"ret == %i)\n", __func__, reg, data, ret);
 
 	return (ret != 1) ? -EREMOTEIO : 0;
 }
@@ -113,7 +113,7 @@
 
 	if (ret != 2)
 		dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n",
-				__FUNCTION__, reg, ret);
+				__func__, reg, ret);
 
 	return b1[0];
 }
@@ -127,14 +127,14 @@
 	ret = i2c_transfer (state->i2c, msg, 2);
 
 	if (ret != 2)
-		dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
+		dprintk("%s: readreg error (ret == %i)\n", __func__, ret);
 
 	return ret == 2 ? 0 : ret;
 }
 
 static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec)
 {
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	switch (fec) {
 	case FEC_AUTO:
@@ -174,7 +174,7 @@
 					     FEC_7_8, FEC_1_2 };
 	u8 index;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	index = stv0299_readreg (state, 0x1b);
 	index &= 0x7;
@@ -189,11 +189,11 @@
 {
 	unsigned long start = jiffies;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	while (stv0299_readreg(state, 0x0a) & 1) {
 		if (jiffies - start > timeout) {
-			dprintk ("%s: timeout!!\n", __FUNCTION__);
+			dprintk ("%s: timeout!!\n", __func__);
 			return -ETIMEDOUT;
 		}
 		msleep(10);
@@ -206,11 +206,11 @@
 {
 	unsigned long start = jiffies;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	while ((stv0299_readreg(state, 0x0a) & 3) != 2 ) {
 		if (jiffies - start > timeout) {
-			dprintk ("%s: timeout!!\n", __FUNCTION__);
+			dprintk ("%s: timeout!!\n", __func__);
 			return -ETIMEDOUT;
 		}
 		msleep(10);
@@ -245,7 +245,7 @@
 	u8 sfr[3];
 	s8 rtf;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	stv0299_readregs (state, 0x1f, sfr, 3);
 	stv0299_readregs (state, 0x1a, (u8 *)&rtf, 1);
@@ -257,8 +257,8 @@
 	offset = (s32) rtf * (srate / 4096L);
 	offset /= 128;
 
-	dprintk ("%s : srate = %i\n", __FUNCTION__, srate);
-	dprintk ("%s : ofset = %i\n", __FUNCTION__, offset);
+	dprintk ("%s : srate = %i\n", __func__, srate);
+	dprintk ("%s : ofset = %i\n", __func__, offset);
 
 	srate += offset;
 
@@ -276,7 +276,7 @@
 	u8 val;
 	int i;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	if (stv0299_wait_diseqc_idle (state, 100) < 0)
 		return -ETIMEDOUT;
@@ -305,7 +305,7 @@
 	struct stv0299_state* state = fe->demodulator_priv;
 	u8 val;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	if (stv0299_wait_diseqc_idle (state, 100) < 0)
 		return -ETIMEDOUT;
@@ -355,7 +355,7 @@
 	u8 reg0x08;
 	u8 reg0x0c;
 
-	dprintk("%s: %s\n", __FUNCTION__,
+	dprintk("%s: %s\n", __func__,
 		voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
 		voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
 
@@ -366,26 +366,32 @@
 	 *  H/V switching over OP0, OP1 and OP2 are LNB power enable bits
 	 */
 	reg0x0c &= 0x0f;
-
-	if (voltage == SEC_VOLTAGE_OFF) {
-		stv0299_writeregI (state, 0x0c, 0x00); /*	LNB power off! */
-		return stv0299_writeregI (state, 0x08, 0x00); /*	LNB power off! */
-	}
-
-	stv0299_writeregI (state, 0x08, (reg0x08 & 0x3f) | (state->config->lock_output << 6));
+	reg0x08 = (reg0x08 & 0x3f) | (state->config->lock_output << 6);
 
 	switch (voltage) {
 	case SEC_VOLTAGE_13:
-		if (state->config->volt13_op0_op1 == STV0299_VOLT13_OP0) reg0x0c |= 0x10;
-		else reg0x0c |= 0x40;
-
-		return stv0299_writeregI(state, 0x0c, reg0x0c);
-
+		if (state->config->volt13_op0_op1 == STV0299_VOLT13_OP0)
+			reg0x0c |= 0x10; /* OP1 off, OP0 on */
+		else
+			reg0x0c |= 0x40; /* OP1 on, OP0 off */
+		break;
 	case SEC_VOLTAGE_18:
-		return stv0299_writeregI(state, 0x0c, reg0x0c | 0x50);
+		reg0x0c |= 0x50; /* OP1 on, OP0 on */
+		break;
+	case SEC_VOLTAGE_OFF:
+		/* LNB power off! */
+		reg0x08 = 0x00;
+		reg0x0c = 0x00;
+		break;
 	default:
 		return -EINVAL;
 	};
+
+	if (state->config->op0_off)
+		reg0x0c &= ~0x10;
+
+	stv0299_writeregI(state, 0x08, reg0x08);
+	return stv0299_writeregI(state, 0x0c, reg0x0c);
 }
 
 static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long cmd)
@@ -408,7 +414,7 @@
 
 	cmd = cmd << 1;
 	if (debug_legacy_dish_switch)
-		printk ("%s switch command: 0x%04lx\n",__FUNCTION__, cmd);
+		printk ("%s switch command: 0x%04lx\n",__func__, cmd);
 
 	do_gettimeofday (&nexttime);
 	if (debug_legacy_dish_switch)
@@ -433,7 +439,7 @@
 	}
 	if (debug_legacy_dish_switch) {
 		printk ("%s(%d): switch delay (should be 32k followed by all 8k\n",
-			__FUNCTION__, fe->dvb->num);
+			__func__, fe->dvb->num);
 		for (i = 1; i < 10; i++)
 			printk ("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i]));
 	}
@@ -445,11 +451,20 @@
 {
 	struct stv0299_state* state = fe->demodulator_priv;
 	int i;
+	u8 reg;
+	u8 val;
 
 	dprintk("stv0299: init chip\n");
 
-	for (i=0; !(state->config->inittab[i] == 0xff && state->config->inittab[i+1] == 0xff); i+=2)
-		stv0299_writeregI(state, state->config->inittab[i], state->config->inittab[i+1]);
+	for (i = 0; ; i += 2)  {
+		reg = state->config->inittab[i];
+		val = state->config->inittab[i+1];
+		if (reg == 0xff && val == 0xff)
+			break;
+		if (reg == 0x0c && state->config->op0_off)
+			val &= ~0x10;
+		stv0299_writeregI(state, reg, val);
+	}
 
 	return 0;
 }
@@ -461,7 +476,7 @@
 	u8 signal = 0xff - stv0299_readreg (state, 0x18);
 	u8 sync = stv0299_readreg (state, 0x1b);
 
-	dprintk ("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __FUNCTION__, sync);
+	dprintk ("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, sync);
 	*status = 0;
 
 	if (signal > 10)
@@ -499,7 +514,7 @@
 	s32 signal =  0xffff - ((stv0299_readreg (state, 0x18) << 8)
 			       | stv0299_readreg (state, 0x19));
 
-	dprintk ("%s : FE_READ_SIGNAL_STRENGTH : AGC2I: 0x%02x%02x, signal=0x%04x\n", __FUNCTION__,
+	dprintk ("%s : FE_READ_SIGNAL_STRENGTH : AGC2I: 0x%02x%02x, signal=0x%04x\n", __func__,
 		 stv0299_readreg (state, 0x18),
 		 stv0299_readreg (state, 0x19), (int) signal);
 
@@ -536,7 +551,7 @@
 	struct stv0299_state* state = fe->demodulator_priv;
 	int invval = 0;
 
-	dprintk ("%s : FE_SET_FRONTEND\n", __FUNCTION__);
+	dprintk ("%s : FE_SET_FRONTEND\n", __func__);
 
 	// set the inversion
 	if (p->inversion == INVERSION_OFF) invval = 0;
diff --git a/drivers/media/dvb/frontends/stv0299.h b/drivers/media/dvb/frontends/stv0299.h
index 33df949..3282f43 100644
--- a/drivers/media/dvb/frontends/stv0299.h
+++ b/drivers/media/dvb/frontends/stv0299.h
@@ -48,10 +48,10 @@
 #include <linux/dvb/frontend.h>
 #include "dvb_frontend.h"
 
-#define STV0229_LOCKOUTPUT_0  0
-#define STV0229_LOCKOUTPUT_1  1
-#define STV0229_LOCKOUTPUT_CF 2
-#define STV0229_LOCKOUTPUT_LK 3
+#define STV0299_LOCKOUTPUT_0  0
+#define STV0299_LOCKOUTPUT_1  1
+#define STV0299_LOCKOUTPUT_CF 2
+#define STV0299_LOCKOUTPUT_LK 3
 
 #define STV0299_VOLT13_OP0 0
 #define STV0299_VOLT13_OP1 1
@@ -82,6 +82,9 @@
 	/* Is 13v controlled by OP0 or OP1? */
 	u8 volt13_op0_op1:1;
 
+	/* Turn-off OP0? */
+	u8 op0_off:1;
+
 	/* minimum delay before retuning */
 	int min_delay_ms;
 
@@ -96,7 +99,7 @@
 static inline struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
 					   struct i2c_adapter* i2c)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_STV0299
diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c
index 45137d2..f648fdb 100644
--- a/drivers/media/dvb/frontends/tda10021.c
+++ b/drivers/media/dvb/frontends/tda10021.c
@@ -79,7 +79,7 @@
 	if (ret != 1)
 		printk("DVB: TDA10021(%d): %s, writereg error "
 			"(reg == 0x%02x, val == 0x%02x, ret == %i)\n",
-			state->frontend.dvb->num, __FUNCTION__, reg, data, ret);
+			state->frontend.dvb->num, __func__, reg, data, ret);
 
 	msleep(10);
 	return (ret != 1) ? -EREMOTEIO : 0;
@@ -97,7 +97,7 @@
 	// Don't print an error message if the id is read.
 	if (ret != 2 && reg != 0x1a)
 		printk("DVB: TDA10021: %s: readreg error (ret == %i)\n",
-				__FUNCTION__, ret);
+				__func__, ret);
 	return b1[0];
 }
 
diff --git a/drivers/media/dvb/frontends/tda10023.c b/drivers/media/dvb/frontends/tda10023.c
index 364bc01..0727b80 100644
--- a/drivers/media/dvb/frontends/tda10023.c
+++ b/drivers/media/dvb/frontends/tda10023.c
@@ -118,7 +118,7 @@
 	ret = i2c_transfer (state->i2c, msg, 2);
 	if (ret != 2)
 		printk("DVB: TDA10023: %s: readreg error (ret == %i)\n",
-				 __FUNCTION__, ret);
+				 __func__, ret);
 	return b1[0];
 }
 
@@ -132,7 +132,7 @@
 	if (ret != 1)
 		printk("DVB: TDA10023(%d): %s, writereg error "
 			"(reg == 0x%02x, val == 0x%02x, ret == %i)\n",
-			state->frontend.dvb->num, __FUNCTION__, reg, data, ret);
+			state->frontend.dvb->num, __func__, reg, data, ret);
 
 	return (ret != 1) ? -EREMOTEIO : 0;
 }
diff --git a/drivers/media/dvb/frontends/tda1002x.h b/drivers/media/dvb/frontends/tda1002x.h
index e9094d8..1bcc0d4 100644
--- a/drivers/media/dvb/frontends/tda1002x.h
+++ b/drivers/media/dvb/frontends/tda1002x.h
@@ -40,7 +40,7 @@
 static inline struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
 					    struct i2c_adapter* i2c, u8 pwm)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_TDA10021
@@ -52,7 +52,7 @@
 static inline struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
 					    struct i2c_adapter* i2c, u8 pwm)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_TDA10023
diff --git a/drivers/media/dvb/frontends/tda10048.c b/drivers/media/dvb/frontends/tda10048.c
new file mode 100644
index 0000000..090fb7d
--- /dev/null
+++ b/drivers/media/dvb/frontends/tda10048.c
@@ -0,0 +1,841 @@
+/*
+    NXP TDA10048HN DVB OFDM demodulator driver
+
+    Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include "dvb_frontend.h"
+#include "dvb_math.h"
+#include "tda10048.h"
+
+#define TDA10048_DEFAULT_FIRMWARE "dvb-fe-tda10048-1.0.fw"
+#define TDA10048_DEFAULT_FIRMWARE_SIZE 24878
+
+/* Register name definitions */
+#define TDA10048_IDENTITY          0x00
+#define TDA10048_VERSION           0x01
+#define TDA10048_DSP_CODE_CPT      0x0C
+#define TDA10048_DSP_CODE_IN       0x0E
+#define TDA10048_IN_CONF1          0x10
+#define TDA10048_IN_CONF2          0x11
+#define TDA10048_IN_CONF3          0x12
+#define TDA10048_OUT_CONF1         0x14
+#define TDA10048_OUT_CONF2         0x15
+#define TDA10048_OUT_CONF3         0x16
+#define TDA10048_AUTO              0x18
+#define TDA10048_SYNC_STATUS       0x1A
+#define TDA10048_CONF_C4_1         0x1E
+#define TDA10048_CONF_C4_2         0x1F
+#define TDA10048_CODE_IN_RAM       0x20
+#define TDA10048_CHANNEL_INFO_1_R  0x22
+#define TDA10048_CHANNEL_INFO_2_R  0x23
+#define TDA10048_CHANNEL_INFO1     0x24
+#define TDA10048_CHANNEL_INFO2     0x25
+#define TDA10048_TIME_ERROR_R      0x26
+#define TDA10048_TIME_ERROR        0x27
+#define TDA10048_FREQ_ERROR_LSB_R  0x28
+#define TDA10048_FREQ_ERROR_MSB_R  0x29
+#define TDA10048_FREQ_ERROR_LSB    0x2A
+#define TDA10048_FREQ_ERROR_MSB    0x2B
+#define TDA10048_IT_SEL            0x30
+#define TDA10048_IT_STAT           0x32
+#define TDA10048_DSP_AD_LSB        0x3C
+#define TDA10048_DSP_AD_MSB        0x3D
+#define TDA10048_DSP_REF_LSB       0x3E
+#define TDA10048_DSP_REF_MSB       0x3F
+#define TDA10048_CONF_TRISTATE1    0x44
+#define TDA10048_CONF_TRISTATE2    0x45
+#define TDA10048_CONF_POLARITY     0x46
+#define TDA10048_GPIO_SP_DS0       0x48
+#define TDA10048_GPIO_SP_DS1       0x49
+#define TDA10048_GPIO_SP_DS2       0x4A
+#define TDA10048_GPIO_SP_DS3       0x4B
+#define TDA10048_GPIO_OUT_SEL      0x4C
+#define TDA10048_GPIO_SELECT       0x4D
+#define TDA10048_IC_MODE           0x4E
+#define TDA10048_CONF_XO           0x50
+#define TDA10048_CONF_PLL1         0x51
+#define TDA10048_CONF_PLL2         0x52
+#define TDA10048_CONF_PLL3         0x53
+#define TDA10048_CONF_ADC          0x54
+#define TDA10048_CONF_ADC_2        0x55
+#define TDA10048_CONF_C1_1         0x60
+#define TDA10048_CONF_C1_3         0x62
+#define TDA10048_AGC_CONF          0x70
+#define TDA10048_AGC_THRESHOLD_LSB 0x72
+#define TDA10048_AGC_THRESHOLD_MSB 0x73
+#define TDA10048_AGC_RENORM        0x74
+#define TDA10048_AGC_GAINS         0x76
+#define TDA10048_AGC_TUN_MIN       0x78
+#define TDA10048_AGC_TUN_MAX       0x79
+#define TDA10048_AGC_IF_MIN        0x7A
+#define TDA10048_AGC_IF_MAX        0x7B
+#define TDA10048_AGC_TUN_LEVEL     0x7E
+#define TDA10048_AGC_IF_LEVEL      0x7F
+#define TDA10048_DIG_AGC_LEVEL     0x81
+#define TDA10048_FREQ_PHY2_LSB     0x86
+#define TDA10048_FREQ_PHY2_MSB     0x87
+#define TDA10048_TIME_INVWREF_LSB  0x88
+#define TDA10048_TIME_INVWREF_MSB  0x89
+#define TDA10048_TIME_WREF_LSB     0x8A
+#define TDA10048_TIME_WREF_MID1    0x8B
+#define TDA10048_TIME_WREF_MID2    0x8C
+#define TDA10048_TIME_WREF_MSB     0x8D
+#define TDA10048_NP_OUT            0xA2
+#define TDA10048_CELL_ID_LSB       0xA4
+#define TDA10048_CELL_ID_MSB       0xA5
+#define TDA10048_EXTTPS_ODD        0xAA
+#define TDA10048_EXTTPS_EVEN       0xAB
+#define TDA10048_TPS_LENGTH        0xAC
+#define TDA10048_FREE_REG_1        0xB2
+#define TDA10048_FREE_REG_2        0xB3
+#define TDA10048_CONF_C3_1         0xC0
+#define TDA10048_CYBER_CTRL        0xC2
+#define TDA10048_CBER_NMAX_LSB     0xC4
+#define TDA10048_CBER_NMAX_MSB     0xC5
+#define TDA10048_CBER_LSB          0xC6
+#define TDA10048_CBER_MSB          0xC7
+#define TDA10048_VBER_LSB          0xC8
+#define TDA10048_VBER_MID          0xC9
+#define TDA10048_VBER_MSB          0xCA
+#define TDA10048_CYBER_LUT         0xCC
+#define TDA10048_UNCOR_CTRL        0xCD
+#define TDA10048_UNCOR_CPT_LSB     0xCE
+#define TDA10048_UNCOR_CPT_MSB     0xCF
+#define TDA10048_SOFT_IT_C3        0xD6
+#define TDA10048_CONF_TS2          0xE0
+#define TDA10048_CONF_TS1          0xE1
+
+static unsigned int debug;
+
+#define dprintk(level, fmt, arg...)\
+	do { if (debug >= level)\
+		printk(KERN_DEBUG "tda10048: " fmt, ## arg);\
+	} while (0)
+
+struct tda10048_state {
+
+	struct i2c_adapter *i2c;
+
+	/* configuration settings */
+	const struct tda10048_config *config;
+	struct dvb_frontend frontend;
+
+	int fwloaded;
+};
+
+static struct init_tab {
+	u8	reg;
+	u16	data;
+} init_tab[] = {
+	{ TDA10048_CONF_PLL1, 0x08 },
+	{ TDA10048_CONF_ADC_2, 0x00 },
+	{ TDA10048_CONF_C4_1, 0x00 },
+	{ TDA10048_CONF_PLL1, 0x0f },
+	{ TDA10048_CONF_PLL2, 0x0a },
+	{ TDA10048_CONF_PLL3, 0x43 },
+	{ TDA10048_FREQ_PHY2_LSB, 0x02 },
+	{ TDA10048_FREQ_PHY2_MSB, 0x0a },
+	{ TDA10048_TIME_WREF_LSB, 0xbd },
+	{ TDA10048_TIME_WREF_MID1, 0xe4 },
+	{ TDA10048_TIME_WREF_MID2, 0xa8 },
+	{ TDA10048_TIME_WREF_MSB, 0x02 },
+	{ TDA10048_TIME_INVWREF_LSB, 0x04 },
+	{ TDA10048_TIME_INVWREF_MSB, 0x06 },
+	{ TDA10048_CONF_C4_1, 0x00 },
+	{ TDA10048_CONF_C1_1, 0xa8 },
+	{ TDA10048_AGC_CONF, 0x16 },
+	{ TDA10048_CONF_C1_3, 0x0b },
+	{ TDA10048_AGC_TUN_MIN, 0x00 },
+	{ TDA10048_AGC_TUN_MAX, 0xff },
+	{ TDA10048_AGC_IF_MIN, 0x00 },
+	{ TDA10048_AGC_IF_MAX, 0xff },
+	{ TDA10048_AGC_THRESHOLD_MSB, 0x00 },
+	{ TDA10048_AGC_THRESHOLD_LSB, 0x70 },
+	{ TDA10048_CYBER_CTRL, 0x38 },
+	{ TDA10048_AGC_GAINS, 0x12 },
+	{ TDA10048_CONF_XO, 0x00 },
+	{ TDA10048_CONF_TS1, 0x07 },
+	{ TDA10048_IC_MODE, 0x00 },
+	{ TDA10048_CONF_TS2, 0xc0 },
+	{ TDA10048_CONF_TRISTATE1, 0x21 },
+	{ TDA10048_CONF_TRISTATE2, 0x00 },
+	{ TDA10048_CONF_POLARITY, 0x00 },
+	{ TDA10048_CONF_C4_2, 0x04 },
+	{ TDA10048_CONF_ADC, 0x60 },
+	{ TDA10048_CONF_ADC_2, 0x10 },
+	{ TDA10048_CONF_ADC, 0x60 },
+	{ TDA10048_CONF_ADC_2, 0x00 },
+	{ TDA10048_CONF_C1_1, 0xa8 },
+	{ TDA10048_UNCOR_CTRL, 0x00 },
+	{ TDA10048_CONF_C4_2, 0x04 },
+};
+
+static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data)
+{
+	int ret;
+	u8 buf [] = { reg, data };
+	struct i2c_msg msg = {
+		.addr = state->config->demod_address,
+		.flags = 0, .buf = buf, .len = 2 };
+
+	dprintk(2, "%s(reg = 0x%02x, data = 0x%02x)\n", __func__, reg, data);
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+
+	if (ret != 1)
+		printk("%s: writereg error (ret == %i)\n", __func__, ret);
+
+	return (ret != 1) ? -1 : 0;
+}
+
+static u8 tda10048_readreg(struct tda10048_state *state, u8 reg)
+{
+	int ret;
+	u8 b0 [] = { reg };
+	u8 b1 [] = { 0 };
+	struct i2c_msg msg [] = {
+		{ .addr = state->config->demod_address,
+			.flags = 0, .buf = b0, .len = 1 },
+		{ .addr = state->config->demod_address,
+			.flags = I2C_M_RD, .buf = b1, .len = 1 } };
+
+	dprintk(2, "%s(reg = 0x%02x)\n", __func__, reg);
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2)
+		printk(KERN_ERR "%s: readreg error (ret == %i)\n",
+			__func__, ret);
+
+	return b1[0];
+}
+
+static int tda10048_writeregbulk(struct tda10048_state *state, u8 reg,
+	u8 *data, u16 len)
+{
+	int ret = -EREMOTEIO;
+	struct i2c_msg msg;
+	u8 *buf;
+
+	dprintk(2, "%s(%d, ?, len = %d)\n", __func__, reg, len);
+
+	buf = kmalloc(len + 1, GFP_KERNEL);
+	if (buf == NULL) {
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	*buf = reg;
+	memcpy(buf + 1, data, len);
+
+	msg.addr = state->config->demod_address;
+	msg.flags = 0;
+	msg.buf = buf;
+	msg.len = len + 1;
+
+	dprintk(2, "%s():  write len = %d\n",
+		__func__, msg.len);
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+	if (ret != 1) {
+		printk(KERN_ERR "%s(): writereg error err %i\n",
+			 __func__, ret);
+		ret = -EREMOTEIO;
+	}
+
+error:
+	kfree(buf);
+
+	return ret;
+}
+
+static int tda10048_firmware_upload(struct dvb_frontend *fe)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+	const struct firmware *fw;
+	int ret;
+	int pos = 0;
+	int cnt;
+	u8 wlen = state->config->fwbulkwritelen;
+
+	if ((wlen != TDA10048_BULKWRITE_200) && (wlen != TDA10048_BULKWRITE_50))
+		wlen = TDA10048_BULKWRITE_200;
+
+	/* request the firmware, this will block and timeout */
+	printk(KERN_INFO "%s: waiting for firmware upload (%s)...\n",
+		__func__,
+		TDA10048_DEFAULT_FIRMWARE);
+
+	ret = request_firmware(&fw, TDA10048_DEFAULT_FIRMWARE,
+		&state->i2c->dev);
+	if (ret) {
+		printk(KERN_ERR "%s: Upload failed. (file not found?)\n",
+			__func__);
+		return -EIO;
+	} else {
+		printk(KERN_INFO "%s: firmware read %Zu bytes.\n",
+			__func__,
+			fw->size);
+		ret = 0;
+	}
+
+	if (fw->size != TDA10048_DEFAULT_FIRMWARE_SIZE) {
+		printk(KERN_ERR "%s: firmware incorrect size\n", __func__);
+		return -EIO;
+	} else {
+		printk(KERN_INFO "%s: firmware uploading\n", __func__);
+
+		/* Soft reset */
+		tda10048_writereg(state, TDA10048_CONF_TRISTATE1,
+			tda10048_readreg(state, TDA10048_CONF_TRISTATE1)
+				& 0xfe);
+		tda10048_writereg(state, TDA10048_CONF_TRISTATE1,
+			tda10048_readreg(state, TDA10048_CONF_TRISTATE1)
+				| 0x01);
+
+		/* Put the demod into host download mode */
+		tda10048_writereg(state, TDA10048_CONF_C4_1,
+			tda10048_readreg(state, TDA10048_CONF_C4_1) & 0xf9);
+
+		/* Boot the DSP */
+		tda10048_writereg(state, TDA10048_CONF_C4_1,
+			tda10048_readreg(state, TDA10048_CONF_C4_1) | 0x08);
+
+		/* Prepare for download */
+		tda10048_writereg(state, TDA10048_DSP_CODE_CPT, 0);
+
+		/* Download the firmware payload */
+		while (pos < fw->size) {
+
+			if ((fw->size - pos) > wlen)
+				cnt = wlen;
+			else
+				cnt = fw->size - pos;
+
+			tda10048_writeregbulk(state, TDA10048_DSP_CODE_IN,
+				&fw->data[pos], cnt);
+
+			pos += cnt;
+		}
+
+		ret = -EIO;
+		/* Wait up to 250ms for the DSP to boot */
+		for (cnt = 0; cnt < 250 ; cnt += 10) {
+
+			msleep(10);
+
+			if (tda10048_readreg(state, TDA10048_SYNC_STATUS)
+				& 0x40) {
+				ret = 0;
+				break;
+			}
+		}
+	}
+
+	release_firmware(fw);
+
+	if (ret == 0) {
+		printk(KERN_INFO "%s: firmware uploaded\n", __func__);
+		state->fwloaded = 1;
+	} else
+		printk(KERN_ERR "%s: firmware upload failed\n", __func__);
+
+	return ret;
+}
+
+static int tda10048_set_inversion(struct dvb_frontend *fe, int inversion)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+
+	dprintk(1, "%s(%d)\n", __func__, inversion);
+
+	if (inversion == TDA10048_INVERSION_ON)
+		tda10048_writereg(state, TDA10048_CONF_C1_1,
+			tda10048_readreg(state, TDA10048_CONF_C1_1) | 0x20);
+	else
+		tda10048_writereg(state, TDA10048_CONF_C1_1,
+			tda10048_readreg(state, TDA10048_CONF_C1_1) & 0xdf);
+
+	return 0;
+}
+
+/* Retrieve the demod settings */
+static int tda10048_get_tps(struct tda10048_state *state,
+	struct dvb_ofdm_parameters *p)
+{
+	u8 val;
+
+	/* Make sure the TPS regs are valid */
+	if (!(tda10048_readreg(state, TDA10048_AUTO) & 0x01))
+		return -EAGAIN;
+
+	val = tda10048_readreg(state, TDA10048_OUT_CONF2);
+	switch ((val & 0x60) >> 5) {
+	case 0: p->constellation =   QPSK; break;
+	case 1: p->constellation = QAM_16; break;
+	case 2: p->constellation = QAM_64; break;
+	}
+	switch ((val & 0x18) >> 3) {
+	case 0: p->hierarchy_information = HIERARCHY_NONE; break;
+	case 1: p->hierarchy_information =    HIERARCHY_1; break;
+	case 2: p->hierarchy_information =    HIERARCHY_2; break;
+	case 3: p->hierarchy_information =    HIERARCHY_4; break;
+	}
+	switch (val & 0x07) {
+	case 0: p->code_rate_HP = FEC_1_2; break;
+	case 1: p->code_rate_HP = FEC_2_3; break;
+	case 2: p->code_rate_HP = FEC_3_4; break;
+	case 3: p->code_rate_HP = FEC_5_6; break;
+	case 4: p->code_rate_HP = FEC_7_8; break;
+	}
+
+	val = tda10048_readreg(state, TDA10048_OUT_CONF3);
+	switch (val & 0x07) {
+	case 0: p->code_rate_LP = FEC_1_2; break;
+	case 1: p->code_rate_LP = FEC_2_3; break;
+	case 2: p->code_rate_LP = FEC_3_4; break;
+	case 3: p->code_rate_LP = FEC_5_6; break;
+	case 4: p->code_rate_LP = FEC_7_8; break;
+	}
+
+	val = tda10048_readreg(state, TDA10048_OUT_CONF1);
+	switch ((val & 0x0c) >> 2) {
+	case 0: p->guard_interval = GUARD_INTERVAL_1_32; break;
+	case 1: p->guard_interval = GUARD_INTERVAL_1_16; break;
+	case 2: p->guard_interval =  GUARD_INTERVAL_1_8; break;
+	case 3: p->guard_interval =  GUARD_INTERVAL_1_4; break;
+	}
+	switch (val & 0x02) {
+	case 0: p->transmission_mode = TRANSMISSION_MODE_2K; break;
+	case 1: p->transmission_mode = TRANSMISSION_MODE_8K; break;
+	}
+
+	return 0;
+}
+
+static int tda10048_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+	dprintk(1, "%s(%d)\n", __func__, enable);
+
+	if (enable)
+		return tda10048_writereg(state, TDA10048_CONF_C4_1,
+			tda10048_readreg(state, TDA10048_CONF_C4_1) | 0x02);
+	else
+		return tda10048_writereg(state, TDA10048_CONF_C4_1,
+			tda10048_readreg(state, TDA10048_CONF_C4_1) & 0xfd);
+}
+
+static int tda10048_output_mode(struct dvb_frontend *fe, int serial)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+	dprintk(1, "%s(%d)\n", __func__, serial);
+
+	/* Ensure pins are out of tri-state */
+	tda10048_writereg(state, TDA10048_CONF_TRISTATE1, 0x21);
+	tda10048_writereg(state, TDA10048_CONF_TRISTATE2, 0x00);
+
+	if (serial) {
+		tda10048_writereg(state, TDA10048_IC_MODE, 0x80 | 0x20);
+		tda10048_writereg(state, TDA10048_CONF_TS2, 0xc0);
+	} else {
+		tda10048_writereg(state, TDA10048_IC_MODE, 0x00);
+		tda10048_writereg(state, TDA10048_CONF_TS2, 0x01);
+	}
+
+	return 0;
+}
+
+/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
+/* TODO: Support manual tuning with specific params */
+static int tda10048_set_frontend(struct dvb_frontend *fe,
+	struct dvb_frontend_parameters *p)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+
+	dprintk(1, "%s(frequency=%d)\n", __func__, p->frequency);
+
+	if (fe->ops.tuner_ops.set_params) {
+
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+
+		fe->ops.tuner_ops.set_params(fe, p);
+
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	/* Enable demod TPS auto detection and begin acquisition */
+	tda10048_writereg(state, TDA10048_AUTO, 0x57);
+
+	return 0;
+}
+
+/* Establish sane defaults and load firmware. */
+static int tda10048_init(struct dvb_frontend *fe)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+	int ret = 0, i;
+
+	dprintk(1, "%s()\n", __func__);
+
+	/* Apply register defaults */
+	for (i = 0; i < ARRAY_SIZE(init_tab); i++)
+		tda10048_writereg(state, init_tab[i].reg, init_tab[i].data);
+
+	if (state->fwloaded == 0)
+		ret = tda10048_firmware_upload(fe);
+
+	/* Set either serial or parallel */
+	tda10048_output_mode(fe, state->config->output_mode);
+
+	/* set inversion */
+	tda10048_set_inversion(fe, state->config->inversion);
+
+	/* Ensure we leave the gate closed */
+	tda10048_i2c_gate_ctrl(fe, 0);
+
+	return ret;
+}
+
+static int tda10048_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+	u8 reg;
+
+	*status = 0;
+
+	reg = tda10048_readreg(state, TDA10048_SYNC_STATUS);
+
+	dprintk(1, "%s() status =0x%02x\n", __func__, reg);
+
+	if (reg & 0x02)
+		*status |= FE_HAS_CARRIER;
+
+	if (reg & 0x04)
+		*status |= FE_HAS_SIGNAL;
+
+	if (reg & 0x08) {
+		*status |= FE_HAS_LOCK;
+		*status |= FE_HAS_VITERBI;
+		*status |= FE_HAS_SYNC;
+	}
+
+	return 0;
+}
+
+static int tda10048_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+
+	dprintk(1, "%s()\n", __func__);
+
+	/* TODO: A reset may be required here */
+	*ber = tda10048_readreg(state, TDA10048_CBER_MSB) << 8 |
+		tda10048_readreg(state, TDA10048_CBER_LSB);
+
+	return 0;
+}
+
+static int tda10048_read_signal_strength(struct dvb_frontend *fe,
+	u16 *signal_strength)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+	u8 v;
+
+	dprintk(1, "%s()\n", __func__);
+
+	*signal_strength = 65535;
+
+	v = tda10048_readreg(state, TDA10048_NP_OUT);
+	if (v > 0)
+		*signal_strength -= (v << 8) | v;
+
+	return 0;
+}
+
+/* SNR lookup table */
+static struct snr_tab {
+	u8 val;
+	u8 data;
+} snr_tab[] = {
+	{   0,   0 },
+	{   1, 246 },
+	{   2, 215 },
+	{   3, 198 },
+	{   4, 185 },
+	{   5, 176 },
+	{   6, 168 },
+	{   7, 161 },
+	{   8, 155 },
+	{   9, 150 },
+	{  10, 146 },
+	{  11, 141 },
+	{  12, 138 },
+	{  13, 134 },
+	{  14, 131 },
+	{  15, 128 },
+	{  16, 125 },
+	{  17, 122 },
+	{  18, 120 },
+	{  19, 118 },
+	{  20, 115 },
+	{  21, 113 },
+	{  22, 111 },
+	{  23, 109 },
+	{  24, 107 },
+	{  25, 106 },
+	{  26, 104 },
+	{  27, 102 },
+	{  28, 101 },
+	{  29,  99 },
+	{  30,  98 },
+	{  31,  96 },
+	{  32,  95 },
+	{  33,  94 },
+	{  34,  92 },
+	{  35,  91 },
+	{  36,  90 },
+	{  37,  89 },
+	{  38,  88 },
+	{  39,  86 },
+	{  40,  85 },
+	{  41,  84 },
+	{  42,  83 },
+	{  43,  82 },
+	{  44,  81 },
+	{  45,  80 },
+	{  46,  79 },
+	{  47,  78 },
+	{  48,  77 },
+	{  49,  76 },
+	{  50,  76 },
+	{  51,  75 },
+	{  52,  74 },
+	{  53,  73 },
+	{  54,  72 },
+	{  56,  71 },
+	{  57,  70 },
+	{  58,  69 },
+	{  60,  68 },
+	{  61,  67 },
+	{  63,  66 },
+	{  64,  65 },
+	{  66,  64 },
+	{  67,  63 },
+	{  68,  62 },
+	{  69,  62 },
+	{  70,  61 },
+	{  72,  60 },
+	{  74,  59 },
+	{  75,  58 },
+	{  77,  57 },
+	{  79,  56 },
+	{  81,  55 },
+	{  83,  54 },
+	{  85,  53 },
+	{  87,  52 },
+	{  89,  51 },
+	{  91,  50 },
+	{  93,  49 },
+	{  95,  48 },
+	{  97,  47 },
+	{ 100,  46 },
+	{ 102,  45 },
+	{ 104,  44 },
+	{ 107,  43 },
+	{ 109,  42 },
+	{ 112,  41 },
+	{ 114,  40 },
+	{ 117,  39 },
+	{ 120,  38 },
+	{ 123,  37 },
+	{ 125,  36 },
+	{ 128,  35 },
+	{ 131,  34 },
+	{ 134,  33 },
+	{ 138,  32 },
+	{ 141,  31 },
+	{ 144,  30 },
+	{ 147,  29 },
+	{ 151,  28 },
+	{ 154,  27 },
+	{ 158,  26 },
+	{ 162,  25 },
+	{ 165,  24 },
+	{ 169,  23 },
+	{ 173,  22 },
+	{ 177,  21 },
+	{ 181,  20 },
+	{ 186,  19 },
+	{ 190,  18 },
+	{ 194,  17 },
+	{ 199,  16 },
+	{ 204,  15 },
+	{ 208,  14 },
+	{ 213,  13 },
+	{ 218,  12 },
+	{ 223,  11 },
+	{ 229,  10 },
+	{ 234,   9 },
+	{ 239,   8 },
+	{ 245,   7 },
+	{ 251,   6 },
+	{ 255,   5 },
+};
+
+static int tda10048_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+	u8 v;
+	int i, ret = -EINVAL;
+
+	dprintk(1, "%s()\n", __func__);
+
+	v = tda10048_readreg(state, TDA10048_NP_OUT);
+	for (i = 0; i < ARRAY_SIZE(snr_tab); i++) {
+		if (v <= snr_tab[i].val) {
+			*snr = snr_tab[i].data;
+			ret = 0;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int tda10048_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+
+	dprintk(1, "%s()\n", __func__);
+
+	*ucblocks = tda10048_readreg(state, TDA10048_UNCOR_CPT_MSB) << 8 |
+		tda10048_readreg(state, TDA10048_UNCOR_CPT_LSB);
+
+	return 0;
+}
+
+static int tda10048_get_frontend(struct dvb_frontend *fe,
+	struct dvb_frontend_parameters *p)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+
+	dprintk(1, "%s()\n", __func__);
+
+	p->inversion = tda10048_readreg(state, TDA10048_CONF_C1_1)
+		& 0x20 ? INVERSION_ON : INVERSION_OFF;
+
+	return tda10048_get_tps(state, &p->u.ofdm);
+}
+
+static int tda10048_get_tune_settings(struct dvb_frontend *fe,
+	struct dvb_frontend_tune_settings *tune)
+{
+	tune->min_delay_ms = 1000;
+	return 0;
+}
+
+static void tda10048_release(struct dvb_frontend *fe)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+	dprintk(1, "%s()\n", __func__);
+	kfree(state);
+}
+
+static struct dvb_frontend_ops tda10048_ops;
+
+struct dvb_frontend *tda10048_attach(const struct tda10048_config *config,
+	struct i2c_adapter *i2c)
+{
+	struct tda10048_state *state = NULL;
+
+	dprintk(1, "%s()\n", __func__);
+
+	/* allocate memory for the internal state */
+	state = kmalloc(sizeof(struct tda10048_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	state->fwloaded = 0;
+
+	/* check if the demod is present */
+	if (tda10048_readreg(state, TDA10048_IDENTITY) != 0x048)
+		goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &tda10048_ops,
+		sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+
+	/* Leave the gate closed */
+	tda10048_i2c_gate_ctrl(&state->frontend, 0);
+
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(tda10048_attach);
+
+static struct dvb_frontend_ops tda10048_ops = {
+
+	.info = {
+		.name			= "NXP TDA10048HN DVB-T",
+		.type			= FE_OFDM,
+		.frequency_min		= 177000000,
+		.frequency_max		= 858000000,
+		.frequency_stepsize	= 166666,
+		.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_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+		FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER
+	},
+
+	.release = tda10048_release,
+	.init = tda10048_init,
+	.i2c_gate_ctrl = tda10048_i2c_gate_ctrl,
+	.set_frontend = tda10048_set_frontend,
+	.get_frontend = tda10048_get_frontend,
+	.get_tune_settings = tda10048_get_tune_settings,
+	.read_status = tda10048_read_status,
+	.read_ber = tda10048_read_ber,
+	.read_signal_strength = tda10048_read_signal_strength,
+	.read_snr = tda10048_read_snr,
+	.read_ucblocks = tda10048_read_ucblocks,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+
+MODULE_DESCRIPTION("NXP TDA10048HN DVB-T Demodulator driver");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/tda10048.h b/drivers/media/dvb/frontends/tda10048.h
new file mode 100644
index 0000000..2b5c78e
--- /dev/null
+++ b/drivers/media/dvb/frontends/tda10048.h
@@ -0,0 +1,63 @@
+/*
+    NXP TDA10048HN DVB OFDM demodulator driver
+
+    Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef TDA10048_H
+#define TDA10048_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/firmware.h>
+
+struct tda10048_config {
+
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* serial/parallel output */
+#define TDA10048_PARALLEL_OUTPUT 0
+#define TDA10048_SERIAL_OUTPUT   1
+	u8 output_mode;
+
+#define TDA10048_BULKWRITE_200	200
+#define TDA10048_BULKWRITE_50	50
+	u8 fwbulkwritelen;
+
+	/* Spectral Inversion */
+#define TDA10048_INVERSION_OFF 0
+#define TDA10048_INVERSION_ON  1
+	u8 inversion;
+};
+
+#if defined(CONFIG_DVB_TDA10048) || \
+	(defined(CONFIG_DVB_TDA10048_MODULE) && defined(MODULE))
+extern struct dvb_frontend *tda10048_attach(
+	const struct tda10048_config *config,
+	struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *tda10048_attach(
+	const struct tda10048_config *config,
+	struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_TDA10048 */
+
+#endif /* TDA10048_H */
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
index 8415a8a..4997384 100644
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb/frontends/tda1004x.c
@@ -131,16 +131,16 @@
 	u8 buf[] = { reg, data };
 	struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 };
 
-	dprintk("%s: reg=0x%x, data=0x%x\n", __FUNCTION__, reg, data);
+	dprintk("%s: reg=0x%x, data=0x%x\n", __func__, reg, data);
 
 	msg.addr = state->config->demod_address;
 	ret = i2c_transfer(state->i2c, &msg, 1);
 
 	if (ret != 1)
 		dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
-			__FUNCTION__, reg, data, ret);
+			__func__, reg, data, ret);
 
-	dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __FUNCTION__,
+	dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __func__,
 		reg, data, ret);
 	return (ret != 1) ? -1 : 0;
 }
@@ -153,19 +153,19 @@
 	struct i2c_msg msg[] = {{ .flags = 0, .buf = b0, .len = 1 },
 				{ .flags = I2C_M_RD, .buf = b1, .len = 1 }};
 
-	dprintk("%s: reg=0x%x\n", __FUNCTION__, reg);
+	dprintk("%s: reg=0x%x\n", __func__, reg);
 
 	msg[0].addr = state->config->demod_address;
 	msg[1].addr = state->config->demod_address;
 	ret = i2c_transfer(state->i2c, msg, 2);
 
 	if (ret != 2) {
-		dprintk("%s: error reg=0x%x, ret=%i\n", __FUNCTION__, reg,
+		dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg,
 			ret);
 		return -1;
 	}
 
-	dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __FUNCTION__,
+	dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __func__,
 		reg, b1[0], ret);
 	return b1[0];
 }
@@ -173,7 +173,7 @@
 static int tda1004x_write_mask(struct tda1004x_state *state, int reg, int mask, int data)
 {
 	int val;
-	dprintk("%s: reg=0x%x, mask=0x%x, data=0x%x\n", __FUNCTION__, reg,
+	dprintk("%s: reg=0x%x, mask=0x%x, data=0x%x\n", __func__, reg,
 		mask, data);
 
 	// read a byte and check
@@ -194,7 +194,7 @@
 	int i;
 	int result;
 
-	dprintk("%s: reg=0x%x, len=0x%x\n", __FUNCTION__, reg, len);
+	dprintk("%s: reg=0x%x, len=0x%x\n", __func__, reg, len);
 
 	result = 0;
 	for (i = 0; i < len; i++) {
@@ -209,7 +209,7 @@
 static int tda1004x_enable_tuner_i2c(struct tda1004x_state *state)
 {
 	int result;
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	result = tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 2);
 	msleep(20);
@@ -218,7 +218,7 @@
 
 static int tda1004x_disable_tuner_i2c(struct tda1004x_state *state)
 {
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	return tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 0);
 }
@@ -345,7 +345,7 @@
 		}
 		pos += tx_size;
 
-		dprintk("%s: fw_pos=0x%x\n", __FUNCTION__, pos);
+		dprintk("%s: fw_pos=0x%x\n", __func__, pos);
 	}
 	// give the DSP a chance to settle 03/10/05 Hac
 	msleep(100);
@@ -444,10 +444,10 @@
 		tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x03); // PLL M = 3
 	}
 	if (state->config->xtal_freq == TDA10046_XTAL_4M ) {
-		dprintk("%s: setting up PLLs for a 4 MHz Xtal\n", __FUNCTION__);
+		dprintk("%s: setting up PLLs for a 4 MHz Xtal\n", __func__);
 		tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0
 	} else {
-		dprintk("%s: setting up PLLs for a 16 MHz Xtal\n", __FUNCTION__);
+		dprintk("%s: setting up PLLs for a 16 MHz Xtal\n", __func__);
 		tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 3); // PLL P = 0, N = 3
 	}
 	if(tda10046_clk53m)
@@ -488,7 +488,7 @@
 	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__);
+		dprintk("%s: 16MHz Xtal, reducing I2C speed\n", __func__);
 		tda1004x_write_byteI(state, TDA1004X_CONFC4, 0x80);
 	}
 	tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0);
@@ -594,7 +594,7 @@
 {
 	struct tda1004x_state* state = fe->demodulator_priv;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	if (tda10045_fwupload(fe)) {
 		printk("tda1004x: firmware upload failed\n");
@@ -624,7 +624,7 @@
 static int tda10046_init(struct dvb_frontend* fe)
 {
 	struct tda1004x_state* state = fe->demodulator_priv;
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	if (tda10046_fwupload(fe)) {
 		printk("tda1004x: firmware upload failed\n");
@@ -686,7 +686,7 @@
 	int tmp;
 	int inversion;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	if (state->demod_type == TDA1004X_DEMOD_TDA10046) {
 		// setup auto offset
@@ -881,7 +881,7 @@
 {
 	struct tda1004x_state* state = fe->demodulator_priv;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	// inversion status
 	fe_params->inversion = INVERSION_OFF;
@@ -989,7 +989,7 @@
 	int cber;
 	int vber;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	// read status
 	status = tda1004x_read_byte(state, TDA1004X_STATUS_CD);
@@ -1048,7 +1048,7 @@
 	}
 
 	// success
-	dprintk("%s: fe_status=0x%x\n", __FUNCTION__, *fe_status);
+	dprintk("%s: fe_status=0x%x\n", __func__, *fe_status);
 	return 0;
 }
 
@@ -1058,7 +1058,7 @@
 	int tmp;
 	int reg = 0;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	// determine the register to use
 	switch (state->demod_type) {
@@ -1077,7 +1077,7 @@
 		return -EIO;
 
 	*signal = (tmp << 8) | tmp;
-	dprintk("%s: signal=0x%x\n", __FUNCTION__, *signal);
+	dprintk("%s: signal=0x%x\n", __func__, *signal);
 	return 0;
 }
 
@@ -1086,7 +1086,7 @@
 	struct tda1004x_state* state = fe->demodulator_priv;
 	int tmp;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	// read it
 	tmp = tda1004x_read_byte(state, TDA1004X_SNR);
@@ -1095,7 +1095,7 @@
 	tmp = 255 - tmp;
 
 	*snr = ((tmp << 8) | tmp);
-	dprintk("%s: snr=0x%x\n", __FUNCTION__, *snr);
+	dprintk("%s: snr=0x%x\n", __func__, *snr);
 	return 0;
 }
 
@@ -1106,7 +1106,7 @@
 	int tmp2;
 	int counter;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	// read the UCBLOCKS and reset
 	counter = 0;
@@ -1132,7 +1132,7 @@
 	else
 		*ucblocks = 0xffffffff;
 
-	dprintk("%s: ucblocks=0x%x\n", __FUNCTION__, *ucblocks);
+	dprintk("%s: ucblocks=0x%x\n", __func__, *ucblocks);
 	return 0;
 }
 
@@ -1141,7 +1141,7 @@
 	struct tda1004x_state* state = fe->demodulator_priv;
 	int tmp;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	// read it in
 	tmp = tda1004x_read_byte(state, TDA1004X_CBER_LSB);
@@ -1155,7 +1155,7 @@
 	// 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);
+	dprintk("%s: ber=0x%x\n", __func__, *ber);
 	return 0;
 }
 
diff --git a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h
index abae843..4e27ffb 100644
--- a/drivers/media/dvb/frontends/tda1004x.h
+++ b/drivers/media/dvb/frontends/tda1004x.h
@@ -94,7 +94,6 @@
 
 	/* slave address and configuration of the tuner */
 	u8 tuner_address;
-	u8 tuner_config;
 	u8 antenna_switch;
 
 	/* if the board uses another I2c Bridge (tda8290), its address */
@@ -128,13 +127,13 @@
 static inline struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
 					    struct i2c_adapter* i2c)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 static inline struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
 					    struct i2c_adapter* i2c)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_TDA1004X
diff --git a/drivers/media/dvb/frontends/tda10086.c b/drivers/media/dvb/frontends/tda10086.c
index 0d2b69a..a17ce3c 100644
--- a/drivers/media/dvb/frontends/tda10086.c
+++ b/drivers/media/dvb/frontends/tda10086.c
@@ -43,7 +43,7 @@
 	bool has_lock;
 };
 
-static int debug = 0;
+static int debug;
 #define dprintk(args...) \
 	do { \
 		if (debug) printk(KERN_DEBUG "tda10086: " args); \
@@ -60,7 +60,7 @@
 
 	if (ret != 1)
 		dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
-			__FUNCTION__, reg, data, ret);
+			__func__, reg, data, ret);
 
 	return (ret != 1) ? ret : 0;
 }
@@ -78,7 +78,7 @@
 	ret = i2c_transfer(state->i2c, msg, 2);
 
 	if (ret != 2) {
-		dprintk("%s: error reg=0x%x, ret=%i\n", __FUNCTION__, reg,
+		dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg,
 			ret);
 		return ret;
 	}
@@ -90,16 +90,16 @@
 {
 	int val;
 
-	// read a byte and check
+	/* read a byte and check */
 	val = tda10086_read_byte(state, reg);
 	if (val < 0)
 		return val;
 
-	// mask if off
+	/* mask if off */
 	val = val & ~mask;
 	val |= data & 0xff;
 
-	// write it out again
+	/* write it out again */
 	return tda10086_write_byte(state, reg, val);
 }
 
@@ -108,62 +108,67 @@
 	struct tda10086_state* state = fe->demodulator_priv;
 	u8 t22k_off = 0x80;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	if (state->config->diseqc_tone)
 		t22k_off = 0;
-	// reset
+	/* reset */
 	tda10086_write_byte(state, 0x00, 0x00);
 	msleep(10);
 
-	// misc setup
+	/* misc setup */
 	tda10086_write_byte(state, 0x01, 0x94);
-	tda10086_write_byte(state, 0x02, 0x35); // NOTE: TT drivers appear to disable CSWP
+	tda10086_write_byte(state, 0x02, 0x35); /* NOTE: TT drivers appear to disable CSWP */
 	tda10086_write_byte(state, 0x03, 0xe4);
 	tda10086_write_byte(state, 0x04, 0x43);
 	tda10086_write_byte(state, 0x0c, 0x0c);
-	tda10086_write_byte(state, 0x1b, 0xb0); // noise threshold
-	tda10086_write_byte(state, 0x20, 0x89); // misc
-	tda10086_write_byte(state, 0x30, 0x04); // acquisition period length
-	tda10086_write_byte(state, 0x32, 0x00); // irq off
-	tda10086_write_byte(state, 0x31, 0x56); // setup AFC
+	tda10086_write_byte(state, 0x1b, 0xb0); /* noise threshold */
+	tda10086_write_byte(state, 0x20, 0x89); /* misc */
+	tda10086_write_byte(state, 0x30, 0x04); /* acquisition period length */
+	tda10086_write_byte(state, 0x32, 0x00); /* irq off */
+	tda10086_write_byte(state, 0x31, 0x56); /* setup AFC */
 
-	// setup PLL (assumes 16Mhz XIN)
-	tda10086_write_byte(state, 0x55, 0x2c); // misc PLL setup
-	tda10086_write_byte(state, 0x3a, 0x0b); // M=12
-	tda10086_write_byte(state, 0x3b, 0x01); // P=2
-	tda10086_write_mask(state, 0x55, 0x20, 0x00); // powerup PLL
+	/* setup PLL (this assumes SACLK = 96MHz) */
+	tda10086_write_byte(state, 0x55, 0x2c); /* misc PLL setup */
+	if (state->config->xtal_freq == TDA10086_XTAL_16M) {
+		tda10086_write_byte(state, 0x3a, 0x0b); /* M=12 */
+		tda10086_write_byte(state, 0x3b, 0x01); /* P=2 */
+	} else {
+		tda10086_write_byte(state, 0x3a, 0x17); /* M=24 */
+		tda10086_write_byte(state, 0x3b, 0x00); /* P=1 */
+	}
+	tda10086_write_mask(state, 0x55, 0x20, 0x00); /* powerup PLL */
 
-	// setup TS interface
+	/* setup TS interface */
 	tda10086_write_byte(state, 0x11, 0x81);
 	tda10086_write_byte(state, 0x12, 0x81);
-	tda10086_write_byte(state, 0x19, 0x40); // parallel mode A + MSBFIRST
-	tda10086_write_byte(state, 0x56, 0x80); // powerdown WPLL - unused in the mode we use
-	tda10086_write_byte(state, 0x57, 0x08); // bypass WPLL - unused in the mode we use
+	tda10086_write_byte(state, 0x19, 0x40); /* parallel mode A + MSBFIRST */
+	tda10086_write_byte(state, 0x56, 0x80); /* powerdown WPLL - unused in the mode we use */
+	tda10086_write_byte(state, 0x57, 0x08); /* bypass WPLL - unused in the mode we use */
 	tda10086_write_byte(state, 0x10, 0x2a);
 
-	// setup ADC
-	tda10086_write_byte(state, 0x58, 0x61); // ADC setup
-	tda10086_write_mask(state, 0x58, 0x01, 0x00); // powerup ADC
+	/* setup ADC */
+	tda10086_write_byte(state, 0x58, 0x61); /* ADC setup */
+	tda10086_write_mask(state, 0x58, 0x01, 0x00); /* powerup ADC */
 
-	// setup AGC
+	/* setup AGC */
 	tda10086_write_byte(state, 0x05, 0x0B);
 	tda10086_write_byte(state, 0x37, 0x63);
-	tda10086_write_byte(state, 0x3f, 0x0a); // NOTE: flydvb varies it
+	tda10086_write_byte(state, 0x3f, 0x0a); /* NOTE: flydvb varies it */
 	tda10086_write_byte(state, 0x40, 0x64);
 	tda10086_write_byte(state, 0x41, 0x4f);
 	tda10086_write_byte(state, 0x42, 0x43);
 
-	// setup viterbi
-	tda10086_write_byte(state, 0x1a, 0x11); // VBER 10^6, DVB, QPSK
+	/* setup viterbi */
+	tda10086_write_byte(state, 0x1a, 0x11); /* VBER 10^6, DVB, QPSK */
 
-	// setup carrier recovery
+	/* setup carrier recovery */
 	tda10086_write_byte(state, 0x3d, 0x80);
 
-	// setup SEC
-	tda10086_write_byte(state, 0x36, t22k_off); // all SEC off, 22k tone
-	tda10086_write_byte(state, 0x34, (((1<<19) * (22000/1000)) / (SACLK/1000)));      // } tone frequency
-	tda10086_write_byte(state, 0x35, (((1<<19) * (22000/1000)) / (SACLK/1000)) >> 8); // }
+	/* setup SEC */
+	tda10086_write_byte(state, 0x36, t22k_off); /* all SEC off, 22k tone */
+	tda10086_write_byte(state, 0x34, (((1<<19) * (22000/1000)) / (SACLK/1000)));
+	tda10086_write_byte(state, 0x35, (((1<<19) * (22000/1000)) / (SACLK/1000)) >> 8);
 
 	return 0;
 }
@@ -173,7 +178,7 @@
 	unsigned long timeout = jiffies + msecs_to_jiffies(200);
 	while (!(tda10086_read_byte(state, 0x50) & 0x01)) {
 		if(time_after(jiffies, timeout)) {
-			printk("%s: diseqc queue not ready, command may be lost.\n", __FUNCTION__);
+			printk("%s: diseqc queue not ready, command may be lost.\n", __func__);
 			break;
 		}
 		msleep(10);
@@ -185,7 +190,7 @@
 	struct tda10086_state* state = fe->demodulator_priv;
 	u8 t22k_off = 0x80;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	if (state->config->diseqc_tone)
 		t22k_off = 0;
@@ -211,7 +216,7 @@
 	u8 oldval;
 	u8 t22k_off = 0x80;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	if (state->config->diseqc_tone)
 		t22k_off = 0;
@@ -239,7 +244,7 @@
 	u8 oldval = tda10086_read_byte(state, 0x36);
 	u8 t22k_off = 0x80;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	if (state->config->diseqc_tone)
 		t22k_off = 0;
@@ -266,7 +271,7 @@
 {
 	u8 invval = 0x80;
 
-	dprintk ("%s %i %i\n", __FUNCTION__, fe_params->inversion, state->config->invert);
+	dprintk ("%s %i %i\n", __func__, fe_params->inversion, state->config->invert);
 
 	switch(fe_params->inversion) {
 	case INVERSION_OFF:
@@ -300,9 +305,9 @@
 	u32 bdri;
 	u32 symbol_rate = fe_params->u.qpsk.symbol_rate;
 
-	dprintk ("%s %i\n", __FUNCTION__, symbol_rate);
+	dprintk ("%s %i\n", __func__, symbol_rate);
 
-	// setup the decimation and anti-aliasing filters..
+	/* setup the decimation and anti-aliasing filters.. */
 	if (symbol_rate < (u32) (SACLK * 0.0137)) {
 		dfn=4;
 		afs=1;
@@ -339,13 +344,13 @@
 		byp=1;
 	}
 
-	// calculate BDR
+	/* calculate BDR */
 	big = (1ULL<<21) * ((u64) symbol_rate/1000ULL) * (1ULL<<dfn);
 	big += ((SACLK/1000ULL)-1ULL);
 	do_div(big, (SACLK/1000ULL));
 	bdr = big & 0xfffff;
 
-	// calculate BDRI
+	/* calculate BDRI */
 	tmp = (1<<dfn)*(symbol_rate/1000);
 	bdri = ((32 * (SACLK/1000)) + (tmp-1)) / tmp;
 
@@ -366,7 +371,7 @@
 {
 	u8 fecval;
 
-	dprintk ("%s %i\n", __FUNCTION__, fe_params->u.qpsk.fec_inner);
+	dprintk ("%s %i\n", __func__, fe_params->u.qpsk.fec_inner);
 
 	switch(fe_params->u.qpsk.fec_inner) {
 	case FEC_1_2:
@@ -412,13 +417,13 @@
 	u32 freq = 0;
 	int freqoff;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
-	// modify parameters for tuning
+	/* modify parameters for tuning */
 	tda10086_write_byte(state, 0x02, 0x35);
 	state->has_lock = false;
 
-	// set params
+	/* set params */
 	if (fe->ops.tuner_ops.set_params) {
 		fe->ops.tuner_ops.set_params(fe, fe_params);
 		if (fe->ops.i2c_gate_ctrl)
@@ -430,7 +435,7 @@
 			fe->ops.i2c_gate_ctrl(fe, 0);
 	}
 
-	// calcluate the frequency offset (in *Hz* not kHz)
+	/* calcluate the frequency offset (in *Hz* not kHz) */
 	freqoff = fe_params->frequency - freq;
 	freqoff = ((1<<16) * freqoff) / (SACLK/1000);
 	tda10086_write_byte(state, 0x3d, 0x80 | ((freqoff >> 8) & 0x7f));
@@ -443,7 +448,7 @@
 	if ((ret = tda10086_set_fec(state, fe_params)) < 0)
 		return ret;
 
-	// soft reset + disable TS output until lock
+	/* soft reset + disable TS output until lock */
 	tda10086_write_mask(state, 0x10, 0x40, 0x40);
 	tda10086_write_mask(state, 0x00, 0x01, 0x00);
 
@@ -459,13 +464,13 @@
 	int tmp;
 	u64 tmp64;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
-	// check for invalid symbol rate
+	/* check for invalid symbol rate */
 	if (fe_params->u.qpsk.symbol_rate < 500000)
 		return -EINVAL;
 
-	// calculate the updated frequency (note: we convert from Hz->kHz)
+	/* calculate the updated frequency (note: we convert from Hz->kHz) */
 	tmp64 = tda10086_read_byte(state, 0x52);
 	tmp64 |= (tda10086_read_byte(state, 0x51) << 8);
 	if (tmp64 & 0x8000)
@@ -474,7 +479,7 @@
 	do_div(tmp64, (1ULL<<15) * (1ULL<<1));
 	fe_params->frequency = (int) state->frequency + (int) tmp64;
 
-	// the inversion
+	/* the inversion */
 	val = tda10086_read_byte(state, 0x0c);
 	if (val & 0x80) {
 		switch(val & 0x40) {
@@ -505,7 +510,7 @@
 		}
 	}
 
-	// calculate the updated symbol rate
+	/* calculate the updated symbol rate */
 	tmp = tda10086_read_byte(state, 0x1d);
 	if (tmp & 0x80)
 		tmp |= 0xffffff00;
@@ -513,7 +518,7 @@
 	tmp = ((state->symbol_rate/1000) * tmp) / (1000000/1000);
 	fe_params->u.qpsk.symbol_rate = state->symbol_rate + tmp;
 
-	// the FEC
+	/* the FEC */
 	val = (tda10086_read_byte(state, 0x0d) & 0x70) >> 4;
 	switch(val) {
 	case 0x00:
@@ -550,7 +555,7 @@
 	struct tda10086_state* state = fe->demodulator_priv;
 	u8 val;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	val = tda10086_read_byte(state, 0x0e);
 	*fe_status = 0;
@@ -566,7 +571,7 @@
 		*fe_status |= FE_HAS_LOCK;
 		if (!state->has_lock) {
 			state->has_lock = true;
-			// modify parameters for stable reception
+			/* modify parameters for stable reception */
 			tda10086_write_byte(state, 0x02, 0x00);
 		}
 	}
@@ -579,7 +584,7 @@
 	struct tda10086_state* state = fe->demodulator_priv;
 	u8 _str;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	_str = 0xff - tda10086_read_byte(state, 0x43);
 	*signal = (_str << 8) | _str;
@@ -592,7 +597,7 @@
 	struct tda10086_state* state = fe->demodulator_priv;
 	u8 _snr;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	_snr = 0xff - tda10086_read_byte(state, 0x1c);
 	*snr = (_snr << 8) | _snr;
@@ -604,12 +609,12 @@
 {
 	struct tda10086_state* state = fe->demodulator_priv;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
-	// read it
+	/* read it */
 	*ucblocks = tda10086_read_byte(state, 0x18) & 0x7f;
 
-	// reset counter
+	/* reset counter */
 	tda10086_write_byte(state, 0x18, 0x00);
 	tda10086_write_byte(state, 0x18, 0x80);
 
@@ -620,9 +625,9 @@
 {
 	struct tda10086_state* state = fe->demodulator_priv;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
-	// read it
+	/* read it */
 	*ber = 0;
 	*ber |= tda10086_read_byte(state, 0x15);
 	*ber |= tda10086_read_byte(state, 0x16) << 8;
@@ -635,7 +640,7 @@
 {
 	struct tda10086_state* state = fe->demodulator_priv;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	tda10086_write_mask(state, 0x00, 0x08, 0x08);
 
@@ -646,7 +651,7 @@
 {
 	struct tda10086_state* state = fe->demodulator_priv;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	if (enable) {
 		tda10086_write_mask(state, 0x00, 0x10, 0x10);
@@ -737,7 +742,7 @@
 {
 	struct tda10086_state *state;
 
-	dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __func__);
 
 	/* allocate memory for the internal state */
 	state = kmalloc(sizeof(struct tda10086_state), GFP_KERNEL);
diff --git a/drivers/media/dvb/frontends/tda10086.h b/drivers/media/dvb/frontends/tda10086.h
index eeceaee..61148c5 100644
--- a/drivers/media/dvb/frontends/tda10086.h
+++ b/drivers/media/dvb/frontends/tda10086.h
@@ -26,6 +26,11 @@
 #include <linux/dvb/frontend.h>
 #include <linux/firmware.h>
 
+enum tda10086_xtal {
+	TDA10086_XTAL_16M,
+	TDA10086_XTAL_4M
+};
+
 struct tda10086_config
 {
 	/* the demodulator's i2c address */
@@ -36,6 +41,9 @@
 
 	/* do we need the diseqc signal with carrier? */
 	u8 diseqc_tone;
+
+	/* frequency of the reference xtal */
+	enum tda10086_xtal xtal_freq;
 };
 
 #if defined(CONFIG_DVB_TDA10086) || (defined(CONFIG_DVB_TDA10086_MODULE) && defined(MODULE))
@@ -45,9 +53,9 @@
 static inline struct dvb_frontend* tda10086_attach(const struct tda10086_config* config,
 						   struct i2c_adapter* i2c)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
-#endif // CONFIG_DVB_TDA10086
+#endif /* CONFIG_DVB_TDA10086 */
 
-#endif // TDA10086_H
+#endif /* TDA10086_H */
diff --git a/drivers/media/dvb/frontends/tda18271-common.c b/drivers/media/dvb/frontends/tda18271-common.c
index bca5709..e27a762 100644
--- a/drivers/media/dvb/frontends/tda18271-common.c
+++ b/drivers/media/dvb/frontends/tda18271-common.c
@@ -125,16 +125,16 @@
 	unsigned char buf = 0x00;
 	int ret;
 	struct i2c_msg msg[] = {
-		{ .addr = priv->i2c_addr, .flags = 0,
+		{ .addr = priv->i2c_props.addr, .flags = 0,
 		  .buf = &buf, .len = 1 },
-		{ .addr = priv->i2c_addr, .flags = I2C_M_RD,
+		{ .addr = priv->i2c_props.addr, .flags = I2C_M_RD,
 		  .buf = regs, .len = 16 }
 	};
 
 	tda18271_i2c_gate_ctrl(fe, 1);
 
 	/* read all registers */
-	ret = i2c_transfer(priv->i2c_adap, msg, 2);
+	ret = i2c_transfer(priv->i2c_props.adap, msg, 2);
 
 	tda18271_i2c_gate_ctrl(fe, 0);
 
@@ -155,16 +155,16 @@
 	unsigned char buf = 0x00;
 	int ret, i;
 	struct i2c_msg msg[] = {
-		{ .addr = priv->i2c_addr, .flags = 0,
+		{ .addr = priv->i2c_props.addr, .flags = 0,
 		  .buf = &buf, .len = 1 },
-		{ .addr = priv->i2c_addr, .flags = I2C_M_RD,
+		{ .addr = priv->i2c_props.addr, .flags = I2C_M_RD,
 		  .buf = regdump, .len = TDA18271_NUM_REGS }
 	};
 
 	tda18271_i2c_gate_ctrl(fe, 1);
 
 	/* read all registers */
-	ret = i2c_transfer(priv->i2c_adap, msg, 2);
+	ret = i2c_transfer(priv->i2c_props.adap, msg, 2);
 
 	tda18271_i2c_gate_ctrl(fe, 0);
 
@@ -192,7 +192,7 @@
 	struct tda18271_priv *priv = fe->tuner_priv;
 	unsigned char *regs = priv->tda18271_regs;
 	unsigned char buf[TDA18271_NUM_REGS + 1];
-	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
+	struct i2c_msg msg = { .addr = priv->i2c_props.addr, .flags = 0,
 			       .buf = buf, .len = len + 1 };
 	int i, ret;
 
@@ -205,7 +205,7 @@
 	tda18271_i2c_gate_ctrl(fe, 1);
 
 	/* write registers */
-	ret = i2c_transfer(priv->i2c_adap, &msg, 1);
+	ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
 
 	tda18271_i2c_gate_ctrl(fe, 0);
 
@@ -217,13 +217,29 @@
 
 /*---------------------------------------------------------------------*/
 
+int tda18271_charge_pump_source(struct dvb_frontend *fe,
+				enum tda18271_pll pll, int force)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+
+	int r_cp = (pll == TDA18271_CAL_PLL) ? R_EB7 : R_EB4;
+
+	regs[r_cp] &= ~0x20;
+	regs[r_cp] |= ((force & 1) << 5);
+	tda18271_write_regs(fe, r_cp, 1);
+
+	return 0;
+}
+
 int tda18271_init_regs(struct dvb_frontend *fe)
 {
 	struct tda18271_priv *priv = fe->tuner_priv;
 	unsigned char *regs = priv->tda18271_regs;
 
 	tda_dbg("initializing registers for device @ %d-%04x\n",
-		i2c_adapter_id(priv->i2c_adap), priv->i2c_addr);
+		i2c_adapter_id(priv->i2c_props.adap),
+		priv->i2c_props.addr);
 
 	/* initialize registers */
 	switch (priv->id) {
@@ -310,7 +326,12 @@
 	regs[R_EB22] = 0x48;
 	regs[R_EB23] = 0xb0;
 
-	tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS);
+	if (priv->small_i2c) {
+		tda18271_write_regs(fe, 0x00, 0x10);
+		tda18271_write_regs(fe, 0x10, 0x10);
+		tda18271_write_regs(fe, 0x20, 0x07);
+	} else
+		tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS);
 
 	/* setup agc1 gain */
 	regs[R_EB17] = 0x00;
@@ -349,24 +370,15 @@
 	regs[R_MD2] = 0x08;
 	regs[R_MD3] = 0x00;
 
-	switch (priv->id) {
-	case TDA18271HDC1:
-		tda18271_write_regs(fe, R_EP3, 11);
-		break;
-	case TDA18271HDC2:
-		tda18271_write_regs(fe, R_EP3, 12);
-		break;
-	};
+	tda18271_write_regs(fe, R_EP3, 11);
 
 	if ((priv->id) == TDA18271HDC2) {
 		/* main pll cp source on */
-		regs[R_EB4] = 0x61;
-		tda18271_write_regs(fe, R_EB4, 1);
+		tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1);
 		msleep(1);
 
 		/* main pll cp source off */
-		regs[R_EB4] = 0x41;
-		tda18271_write_regs(fe, R_EB4, 1);
+		tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0);
 	}
 
 	msleep(5); /* pll locking */
@@ -398,6 +410,7 @@
 	tda18271_write_regs(fe, R_EP3, 11);
 	msleep(5); /* pll locking */
 
+	/* launch detector */
 	tda18271_write_regs(fe, R_EP1, 1);
 	msleep(5); /* wanted mid measurement */
 
diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c
index dfe72aa..b262100 100644
--- a/drivers/media/dvb/frontends/tda18271-fe.c
+++ b/drivers/media/dvb/frontends/tda18271-fe.c
@@ -31,30 +31,23 @@
 module_param_named(cal, tda18271_cal_on_startup, int, 0644);
 MODULE_PARM_DESC(cal, "perform RF tracking filter calibration on startup");
 
-static LIST_HEAD(tda18271_list);
 static DEFINE_MUTEX(tda18271_list_mutex);
+static LIST_HEAD(hybrid_tuner_instance_list);
 
 /*---------------------------------------------------------------------*/
 
-static int tda18271_ir_cal_init(struct dvb_frontend *fe)
+static inline int charge_pump_source(struct dvb_frontend *fe, int force)
 {
 	struct tda18271_priv *priv = fe->tuner_priv;
-	unsigned char *regs = priv->tda18271_regs;
-
-	tda18271_read_regs(fe);
-
-	/* test IR_CAL_OK to see if we need init */
-	if ((regs[R_EP1] & 0x08) == 0)
-		tda18271_init_regs(fe);
-
-	return 0;
+	return tda18271_charge_pump_source(fe,
+					   (priv->role == TDA18271_SLAVE) ?
+					   TDA18271_CAL_PLL :
+					   TDA18271_MAIN_PLL, force);
 }
 
-/* ------------------------------------------------------------------ */
-
 static int tda18271_channel_configuration(struct dvb_frontend *fe,
-					  u32 ifc, u32 freq, u32 bw, u8 std,
-					  int radio)
+					  struct tda18271_std_map_item *map,
+					  u32 freq, u32 bw)
 {
 	struct tda18271_priv *priv = fe->tuner_priv;
 	unsigned char *regs = priv->tda18271_regs;
@@ -64,38 +57,34 @@
 
 	/* set standard */
 	regs[R_EP3]  &= ~0x1f; /* clear std bits */
-	regs[R_EP3]  |= std;
+	regs[R_EP3]  |= (map->agc_mode << 3) | map->std;
+
+	/* set rfagc to high speed mode */
+	regs[R_EP3] &= ~0x04;
 
 	/* set cal mode to normal */
 	regs[R_EP4]  &= ~0x03;
 
 	/* update IF output level & IF notch frequency */
 	regs[R_EP4]  &= ~0x1c; /* clear if level bits */
+	regs[R_EP4]  |= (map->if_lvl << 2);
 
 	switch (priv->mode) {
 	case TDA18271_ANALOG:
 		regs[R_MPD]  &= ~0x80; /* IF notch = 0 */
 		break;
 	case TDA18271_DIGITAL:
-		regs[R_EP4]  |= 0x04; /* IF level = 1 */
 		regs[R_MPD]  |= 0x80; /* IF notch = 1 */
 		break;
 	}
 
-	if (radio)
-		regs[R_EP4]  |=  0x80;
-	else
-		regs[R_EP4]  &= ~0x80;
+	/* update FM_RFn */
+	regs[R_EP4]  &= ~0x80;
+	regs[R_EP4]  |= map->fm_rfn << 7;
 
-	/* update RF_TOP / IF_TOP */
-	switch (priv->mode) {
-	case TDA18271_ANALOG:
-		regs[R_EB22]  = 0x2c;
-		break;
-	case TDA18271_DIGITAL:
-		regs[R_EB22]  = 0x37;
-		break;
-	}
+	/* update rf top / if top */
+	regs[R_EB22]  = 0x00;
+	regs[R_EB22] |= map->rfagc_top;
 	tda18271_write_regs(fe, R_EB22, 1);
 
 	/* --------------------------------------------------------------- */
@@ -117,8 +106,14 @@
 
 	/* dual tuner and agc1 extra configuration */
 
-	/* main vco when Master, cal vco when slave */
-	regs[R_EB1]  |= 0x04; /* FIXME: assumes master */
+	switch (priv->role) {
+	case TDA18271_MASTER:
+		regs[R_EB1]  |= 0x04; /* main vco */
+		break;
+	case TDA18271_SLAVE:
+		regs[R_EB1]  &= ~0x04; /* cal vco */
+		break;
+	}
 
 	/* agc1 always active */
 	regs[R_EB1]  &= ~0x02;
@@ -130,25 +125,40 @@
 
 	/* --------------------------------------------------------------- */
 
-	N = freq + ifc;
+	N = map->if_freq * 1000 + freq;
 
-	/* FIXME: assumes master */
-	tda18271_calc_main_pll(fe, N);
-	tda18271_write_regs(fe, R_MPD, 4);
+	switch (priv->role) {
+	case TDA18271_MASTER:
+		tda18271_calc_main_pll(fe, N);
+		tda18271_write_regs(fe, R_MPD, 4);
+		break;
+	case TDA18271_SLAVE:
+		tda18271_calc_cal_pll(fe, N);
+		tda18271_write_regs(fe, R_CPD, 4);
+
+		regs[R_MPD] = regs[R_CPD] & 0x7f;
+		tda18271_write_regs(fe, R_MPD, 1);
+		break;
+	}
 
 	tda18271_write_regs(fe, R_TM, 7);
 
-	/* main pll charge pump source */
-	regs[R_EB4] |= 0x20;
-	tda18271_write_regs(fe, R_EB4, 1);
+	/* force charge pump source */
+	charge_pump_source(fe, 1);
 
 	msleep(1);
 
-	/* normal operation for the main pll */
-	regs[R_EB4] &= ~0x20;
-	tda18271_write_regs(fe, R_EB4, 1);
+	/* return pll to normal operation */
+	charge_pump_source(fe, 0);
 
-	msleep(5);
+	msleep(20);
+
+	/* set rfagc to normal speed mode */
+	if (map->fm_rfn)
+		regs[R_EP3] &= ~0x04;
+	else
+		regs[R_EP3] |= 0x04;
+	tda18271_write_regs(fe, R_EP3, 1);
 
 	return 0;
 }
@@ -195,8 +205,10 @@
 	return tm;
 }
 
-static int tda18271_rf_tracking_filters_correction(struct dvb_frontend *fe,
-						   u32 freq)
+/* ------------------------------------------------------------------ */
+
+static int tda18271c2_rf_tracking_filters_correction(struct dvb_frontend *fe,
+						     u32 freq)
 {
 	struct tda18271_priv *priv = fe->tuner_priv;
 	struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
@@ -296,12 +308,10 @@
 	tda18271_write_regs(fe, R_EB13, 1);
 
 	/* main pll charge pump source */
-	regs[R_EB4]  |= 0x20;
-	tda18271_write_regs(fe, R_EB4, 1);
+	tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1);
 
 	/* cal pll charge pump source */
-	regs[R_EB7]  |= 0x20;
-	tda18271_write_regs(fe, R_EB7, 1);
+	tda18271_charge_pump_source(fe, TDA18271_CAL_PLL, 1);
 
 	/* force dcdc converter to 0 V */
 	regs[R_EB14] = 0x00;
@@ -320,8 +330,8 @@
 	/* set the internal calibration signal */
 	N = freq;
 
-	tda18271_calc_main_pll(fe, N);
-	tda18271_write_regs(fe, R_MPD, 4);
+	tda18271_calc_cal_pll(fe, N);
+	tda18271_write_regs(fe, R_CPD, 4);
 
 	/* downconvert internal calibration */
 	N += 1000000;
@@ -339,14 +349,12 @@
 	/* --------------------------------------------------------------- */
 
 	/* normal operation for the main pll */
-	regs[R_EB4] &= ~0x20;
-	tda18271_write_regs(fe, R_EB4, 1);
+	tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0);
 
 	/* normal operation for the cal pll  */
-	regs[R_EB7] &= ~0x20;
-	tda18271_write_regs(fe, R_EB7, 1);
+	tda18271_charge_pump_source(fe, TDA18271_CAL_PLL, 0);
 
-	msleep(5); /* plls locking */
+	msleep(10); /* plls locking */
 
 	/* launch the rf tracking filters calibration */
 	regs[R_EB20]  |= 0x20;
@@ -443,7 +451,7 @@
 
 		count += 200;
 
-		if (count < count_limit)
+		if (count <= count_limit)
 			continue;
 
 		if (sgn <= 0)
@@ -587,7 +595,7 @@
 
 /* ------------------------------------------------------------------ */
 
-static int tda18271_rf_cal_init(struct dvb_frontend *fe)
+static int tda18271c2_rf_cal_init(struct dvb_frontend *fe)
 {
 	struct tda18271_priv *priv = fe->tuner_priv;
 	unsigned char *regs = priv->tda18271_regs;
@@ -610,63 +618,13 @@
 	return 0;
 }
 
-static int tda18271_init(struct dvb_frontend *fe)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-
-	mutex_lock(&priv->lock);
-
-	/* power up */
-	tda18271_set_standby_mode(fe, 0, 0, 0);
-
-	/* initialization */
-	tda18271_ir_cal_init(fe);
-
-	if (priv->id == TDA18271HDC2)
-		tda18271_rf_cal_init(fe);
-
-	mutex_unlock(&priv->lock);
-
-	return 0;
-}
-
-static int tda18271c2_tune(struct dvb_frontend *fe,
-			   u32 ifc, u32 freq, u32 bw, u8 std, int radio)
-{
-	struct tda18271_priv *priv = fe->tuner_priv;
-
-	tda_dbg("freq = %d, ifc = %d\n", freq, ifc);
-
-	tda18271_init(fe);
-
-	mutex_lock(&priv->lock);
-
-	tda18271_rf_tracking_filters_correction(fe, freq);
-
-	tda18271_channel_configuration(fe, ifc, freq, bw, std, radio);
-
-	mutex_unlock(&priv->lock);
-
-	return 0;
-}
-
-/* ------------------------------------------------------------------ */
-
-static int tda18271c1_tune(struct dvb_frontend *fe,
-			   u32 ifc, u32 freq, u32 bw, u8 std, int radio)
+static int tda18271c1_rf_tracking_filter_calibration(struct dvb_frontend *fe,
+						     u32 freq, u32 bw)
 {
 	struct tda18271_priv *priv = fe->tuner_priv;
 	unsigned char *regs = priv->tda18271_regs;
 	u32 N = 0;
 
-	tda18271_init(fe);
-
-	mutex_lock(&priv->lock);
-
-	tda_dbg("freq = %d, ifc = %d\n", freq, ifc);
-
-	/* RF tracking filter calibration */
-
 	/* calculate bp filter */
 	tda18271_calc_bp_filter(fe, &freq);
 	tda18271_write_regs(fe, R_EP1, 1);
@@ -737,7 +695,7 @@
 
 	regs[R_EB7]   = 0x40;
 	tda18271_write_regs(fe, R_EB7, 1);
-	msleep(10);
+	msleep(10); /* pll locking */
 
 	regs[R_EB20]  = 0xec;
 	tda18271_write_regs(fe, R_EB20, 1);
@@ -752,74 +710,70 @@
 	if (0 == tda18271_calc_rf_cal(fe, &freq))
 		tda18271_write_regs(fe, R_EB14, 1);
 
-	/* Channel Configuration */
+	return 0;
+}
 
-	switch (priv->mode) {
-	case TDA18271_ANALOG:
-		regs[R_EB22]  = 0x2c;
-		break;
-	case TDA18271_DIGITAL:
-		regs[R_EB22]  = 0x37;
-		break;
-	}
-	tda18271_write_regs(fe, R_EB22, 1);
+/* ------------------------------------------------------------------ */
 
-	regs[R_EP1]  |= 0x40; /* set dis power level on */
+static int tda18271_ir_cal_init(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
 
-	/* set standard */
-	regs[R_EP3]  &= ~0x1f; /* clear std bits */
+	tda18271_read_regs(fe);
 
-	/* see table 22 */
-	regs[R_EP3]  |= std;
+	/* test IR_CAL_OK to see if we need init */
+	if ((regs[R_EP1] & 0x08) == 0)
+		tda18271_init_regs(fe);
 
-	regs[R_EP4]  &= ~0x03; /* set cal mode to normal */
+	return 0;
+}
 
-	regs[R_EP4]  &= ~0x1c; /* clear if level bits */
-	switch (priv->mode) {
-	case TDA18271_ANALOG:
-		regs[R_MPD]  &= ~0x80; /* IF notch = 0 */
-		break;
-	case TDA18271_DIGITAL:
-		regs[R_EP4]  |= 0x04;
-		regs[R_MPD]  |= 0x80;
-		break;
-	}
+static int tda18271_init(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
 
-	if (radio)
-		regs[R_EP4]  |=  0x80;
-	else
-		regs[R_EP4]  &= ~0x80;
+	mutex_lock(&priv->lock);
 
-	/* image rejection validity */
-	tda18271_calc_ir_measure(fe, &freq);
+	/* power up */
+	tda18271_set_standby_mode(fe, 0, 0, 0);
 
-	/* calculate MAIN PLL */
-	N = freq + ifc;
+	/* initialization */
+	tda18271_ir_cal_init(fe);
 
-	tda18271_calc_main_pll(fe, N);
+	if (priv->id == TDA18271HDC2)
+		tda18271c2_rf_cal_init(fe);
 
-	tda18271_write_regs(fe, R_TM, 15);
-	msleep(5);
 	mutex_unlock(&priv->lock);
 
 	return 0;
 }
 
-static inline int tda18271_tune(struct dvb_frontend *fe,
-				u32 ifc, u32 freq, u32 bw, u8 std, int radio)
+static int tda18271_tune(struct dvb_frontend *fe,
+			 struct tda18271_std_map_item *map, u32 freq, u32 bw)
 {
 	struct tda18271_priv *priv = fe->tuner_priv;
-	int ret = -EINVAL;
+
+	tda_dbg("freq = %d, ifc = %d, bw = %d, agc_mode = %d, std = %d\n",
+		freq, map->if_freq, bw, map->agc_mode, map->std);
+
+	tda18271_init(fe);
+
+	mutex_lock(&priv->lock);
 
 	switch (priv->id) {
 	case TDA18271HDC1:
-		ret = tda18271c1_tune(fe, ifc, freq, bw, std, radio);
+		tda18271c1_rf_tracking_filter_calibration(fe, freq, bw);
 		break;
 	case TDA18271HDC2:
-		ret = tda18271c2_tune(fe, ifc, freq, bw, std, radio);
+		tda18271c2_rf_tracking_filters_correction(fe, freq);
 		break;
 	}
-	return ret;
+	tda18271_channel_configuration(fe, map, freq, bw);
+
+	mutex_unlock(&priv->lock);
+
+	return 0;
 }
 
 /* ------------------------------------------------------------------ */
@@ -829,9 +783,8 @@
 {
 	struct tda18271_priv *priv = fe->tuner_priv;
 	struct tda18271_std_map *std_map = &priv->std;
+	struct tda18271_std_map_item *map;
 	int ret;
-	u8 std;
-	u16 sgIF;
 	u32 bw, freq = params->frequency;
 
 	priv->mode = TDA18271_DIGITAL;
@@ -840,13 +793,11 @@
 		switch (params->u.vsb.modulation) {
 		case VSB_8:
 		case VSB_16:
-			std  = std_map->atsc_6.std_bits;
-			sgIF = std_map->atsc_6.if_freq;
+			map = &std_map->atsc_6;
 			break;
 		case QAM_64:
 		case QAM_256:
-			std  = std_map->qam_6.std_bits;
-			sgIF = std_map->qam_6.if_freq;
+			map = &std_map->qam_6;
 			break;
 		default:
 			tda_warn("modulation not set!\n");
@@ -861,18 +812,15 @@
 		switch (params->u.ofdm.bandwidth) {
 		case BANDWIDTH_6_MHZ:
 			bw = 6000000;
-			std  = std_map->dvbt_6.std_bits;
-			sgIF = std_map->dvbt_6.if_freq;
+			map = &std_map->dvbt_6;
 			break;
 		case BANDWIDTH_7_MHZ:
 			bw = 7000000;
-			std  = std_map->dvbt_7.std_bits;
-			sgIF = std_map->dvbt_7.if_freq;
+			map = &std_map->dvbt_7;
 			break;
 		case BANDWIDTH_8_MHZ:
 			bw = 8000000;
-			std  = std_map->dvbt_8.std_bits;
-			sgIF = std_map->dvbt_8.if_freq;
+			map = &std_map->dvbt_8;
 			break;
 		default:
 			tda_warn("bandwidth not set!\n");
@@ -887,7 +835,7 @@
 	if (fe->ops.analog_ops.standby)
 		fe->ops.analog_ops.standby(fe);
 
-	ret = tda18271_tune(fe, sgIF * 1000, freq, bw, std, 0);
+	ret = tda18271_tune(fe, map, freq, bw);
 
 	if (ret < 0)
 		goto fail;
@@ -904,57 +852,46 @@
 {
 	struct tda18271_priv *priv = fe->tuner_priv;
 	struct tda18271_std_map *std_map = &priv->std;
+	struct tda18271_std_map_item *map;
 	char *mode;
-	int ret, radio = 0;
-	u8 std;
-	u16 sgIF;
+	int ret;
 	u32 freq = params->frequency * 62500;
 
 	priv->mode = TDA18271_ANALOG;
 
 	if (params->mode == V4L2_TUNER_RADIO) {
-		radio = 1;
 		freq = freq / 1000;
-		std  = std_map->fm_radio.std_bits;
-		sgIF = std_map->fm_radio.if_freq;
+		map = &std_map->fm_radio;
 		mode = "fm";
 	} else if (params->std & V4L2_STD_MN) {
-		std  = std_map->atv_mn.std_bits;
-		sgIF = std_map->atv_mn.if_freq;
+		map = &std_map->atv_mn;
 		mode = "MN";
 	} else if (params->std & V4L2_STD_B) {
-		std  = std_map->atv_b.std_bits;
-		sgIF = std_map->atv_b.if_freq;
+		map = &std_map->atv_b;
 		mode = "B";
 	} else if (params->std & V4L2_STD_GH) {
-		std  = std_map->atv_gh.std_bits;
-		sgIF = std_map->atv_gh.if_freq;
+		map = &std_map->atv_gh;
 		mode = "GH";
 	} else if (params->std & V4L2_STD_PAL_I) {
-		std  = std_map->atv_i.std_bits;
-		sgIF = std_map->atv_i.if_freq;
+		map = &std_map->atv_i;
 		mode = "I";
 	} else if (params->std & V4L2_STD_DK) {
-		std  = std_map->atv_dk.std_bits;
-		sgIF = std_map->atv_dk.if_freq;
+		map = &std_map->atv_dk;
 		mode = "DK";
 	} else if (params->std & V4L2_STD_SECAM_L) {
-		std  = std_map->atv_l.std_bits;
-		sgIF = std_map->atv_l.if_freq;
+		map = &std_map->atv_l;
 		mode = "L";
 	} else if (params->std & V4L2_STD_SECAM_LC) {
-		std  = std_map->atv_lc.std_bits;
-		sgIF = std_map->atv_lc.if_freq;
+		map = &std_map->atv_lc;
 		mode = "L'";
 	} else {
-		std  = std_map->atv_i.std_bits;
-		sgIF = std_map->atv_i.if_freq;
+		map = &std_map->atv_i;
 		mode = "xx";
 	}
 
 	tda_dbg("setting tda18271 to system %s\n", mode);
 
-	ret = tda18271_tune(fe, sgIF * 1000, freq, 0, std, radio);
+	ret = tda18271_tune(fe, map, freq, 0);
 
 	if (ret < 0)
 		goto fail;
@@ -986,16 +923,9 @@
 
 	mutex_lock(&tda18271_list_mutex);
 
-	priv->count--;
+	if (priv)
+		hybrid_tuner_release_state(priv);
 
-	if (!priv->count) {
-		tda_dbg("destroying instance @ %d-%04x\n",
-			i2c_adapter_id(priv->i2c_adap),
-			priv->i2c_addr);
-		list_del(&priv->tda18271_list);
-
-		kfree(priv);
-	}
 	mutex_unlock(&tda18271_list_mutex);
 
 	fe->tuner_priv = NULL;
@@ -1020,15 +950,20 @@
 /* ------------------------------------------------------------------ */
 
 #define tda18271_update_std(std_cfg, name) do {				\
-	if (map->std_cfg.if_freq + map->std_cfg.std_bits > 0) {		\
+	if (map->std_cfg.if_freq +					\
+		map->std_cfg.agc_mode + map->std_cfg.std +		\
+		map->std_cfg.if_lvl + map->std_cfg.rfagc_top > 0) {	\
 		tda_dbg("Using custom std config for %s\n", name);	\
 		memcpy(&std->std_cfg, &map->std_cfg,			\
 			sizeof(struct tda18271_std_map_item));		\
 	} } while (0)
 
 #define tda18271_dump_std_item(std_cfg, name) do {			\
-	tda_dbg("(%s) if freq = %d, std bits = 0x%02x\n",		\
-		name, std->std_cfg.if_freq, std->std_cfg.std_bits);	\
+	tda_dbg("(%s) if_freq = %d, agc_mode = %d, std = %d, "		\
+		"if_lvl = %d, rfagc_top = 0x%02x\n",			\
+		name, std->std_cfg.if_freq,				\
+		std->std_cfg.agc_mode, std->std_cfg.std,		\
+		std->std_cfg.if_lvl, std->std_cfg.rfagc_top);		\
 	} while (0)
 
 static int tda18271_dump_std_map(struct dvb_frontend *fe)
@@ -1037,20 +972,20 @@
 	struct tda18271_std_map *std = &priv->std;
 
 	tda_dbg("========== STANDARD MAP SETTINGS ==========\n");
-	tda18271_dump_std_item(fm_radio, "fm");
-	tda18271_dump_std_item(atv_b,  "pal b");
-	tda18271_dump_std_item(atv_dk, "pal dk");
-	tda18271_dump_std_item(atv_gh, "pal gh");
-	tda18271_dump_std_item(atv_i,  "pal i");
-	tda18271_dump_std_item(atv_l,  "pal l");
-	tda18271_dump_std_item(atv_lc, "pal l'");
+	tda18271_dump_std_item(fm_radio, "  fm  ");
+	tda18271_dump_std_item(atv_b,  "atv b ");
+	tda18271_dump_std_item(atv_dk, "atv dk");
+	tda18271_dump_std_item(atv_gh, "atv gh");
+	tda18271_dump_std_item(atv_i,  "atv i ");
+	tda18271_dump_std_item(atv_l,  "atv l ");
+	tda18271_dump_std_item(atv_lc, "atv l'");
 	tda18271_dump_std_item(atv_mn, "atv mn");
 	tda18271_dump_std_item(atsc_6, "atsc 6");
 	tda18271_dump_std_item(dvbt_6, "dvbt 6");
 	tda18271_dump_std_item(dvbt_7, "dvbt 7");
 	tda18271_dump_std_item(dvbt_8, "dvbt 8");
-	tda18271_dump_std_item(qam_6,  "qam 6");
-	tda18271_dump_std_item(qam_8,  "qam 8");
+	tda18271_dump_std_item(qam_6,  "qam 6 ");
+	tda18271_dump_std_item(qam_8,  "qam 8 ");
 
 	return 0;
 }
@@ -1109,7 +1044,8 @@
 	}
 
 	tda_info("%s detected @ %d-%04x%s\n", name,
-		 i2c_adapter_id(priv->i2c_adap), priv->i2c_addr,
+		 i2c_adapter_id(priv->i2c_props.adap),
+		 priv->i2c_props.addr,
 		 (0 == ret) ? "" : ", device not supported.");
 
 	return ret;
@@ -1136,45 +1072,28 @@
 				     struct tda18271_config *cfg)
 {
 	struct tda18271_priv *priv = NULL;
-	int state_found = 0;
+	int instance;
 
 	mutex_lock(&tda18271_list_mutex);
 
-	list_for_each_entry(priv, &tda18271_list, tda18271_list) {
-		if ((i2c_adapter_id(priv->i2c_adap) == i2c_adapter_id(i2c)) &&
-		    (priv->i2c_addr == addr)) {
-			tda_dbg("attaching existing tuner @ %d-%04x\n",
-				i2c_adapter_id(priv->i2c_adap),
-				priv->i2c_addr);
-			priv->count++;
-			fe->tuner_priv = priv;
-			state_found = 1;
-			/* allow dvb driver to override i2c gate setting */
-			if ((cfg) && (cfg->gate != TDA18271_GATE_ANALOG))
-				priv->gate = cfg->gate;
-			break;
-		}
-	}
-	if (state_found == 0) {
-		tda_dbg("creating new tuner instance @ %d-%04x\n",
-			i2c_adapter_id(i2c), addr);
-
-		priv = kzalloc(sizeof(struct tda18271_priv), GFP_KERNEL);
-		if (priv == NULL) {
-			mutex_unlock(&tda18271_list_mutex);
-			return NULL;
-		}
-
-		priv->i2c_addr = addr;
-		priv->i2c_adap = i2c;
+	instance = hybrid_tuner_request_state(struct tda18271_priv, priv,
+					      hybrid_tuner_instance_list,
+					      i2c, addr, "tda18271");
+	switch (instance) {
+	case 0:
+		goto fail;
+		break;
+	case 1:
+		/* new tuner instance */
 		priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO;
+		priv->role = (cfg) ? cfg->role : TDA18271_MASTER;
 		priv->cal_initialized = false;
 		mutex_init(&priv->lock);
-		priv->count++;
 
 		fe->tuner_priv = priv;
 
-		list_add_tail(&priv->tda18271_list, &tda18271_list);
+		if (cfg)
+			priv->small_i2c = cfg->small_i2c;
 
 		if (tda18271_get_id(fe) < 0)
 			goto fail;
@@ -1186,9 +1105,18 @@
 		tda18271_init_regs(fe);
 
 		if ((tda18271_cal_on_startup) && (priv->id == TDA18271HDC2))
-			tda18271_rf_cal_init(fe);
+			tda18271c2_rf_cal_init(fe);
 
 		mutex_unlock(&priv->lock);
+		break;
+	default:
+		/* existing tuner instance */
+		fe->tuner_priv = priv;
+
+		/* allow dvb driver to override i2c gate setting */
+		if ((cfg) && (cfg->gate != TDA18271_GATE_ANALOG))
+			priv->gate = cfg->gate;
+		break;
 	}
 
 	/* override default std map with values in config struct */
@@ -1200,7 +1128,7 @@
 	memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops,
 	       sizeof(struct dvb_tuner_ops));
 
-	if (tda18271_debug & DBG_MAP)
+	if (tda18271_debug & (DBG_MAP | DBG_ADV))
 		tda18271_dump_std_map(fe);
 
 	return fe;
@@ -1214,7 +1142,7 @@
 MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver");
 MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
 MODULE_LICENSE("GPL");
-MODULE_VERSION("0.2");
+MODULE_VERSION("0.3");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff --git a/drivers/media/dvb/frontends/tda18271-priv.h b/drivers/media/dvb/frontends/tda18271-priv.h
index 7b939a5..2bc5eb3 100644
--- a/drivers/media/dvb/frontends/tda18271-priv.h
+++ b/drivers/media/dvb/frontends/tda18271-priv.h
@@ -24,6 +24,7 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/mutex.h>
+#include "tuner-i2c.h"
 #include "tda18271.h"
 
 #define R_ID     0x00	/* ID byte                */
@@ -85,6 +86,11 @@
 	int rf_b2;
 };
 
+enum tda18271_pll {
+	TDA18271_MAIN_PLL,
+	TDA18271_CAL_PLL,
+};
+
 enum tda18271_mode {
 	TDA18271_ANALOG,
 	TDA18271_DIGITAL,
@@ -98,19 +104,19 @@
 };
 
 struct tda18271_priv {
-	u8 i2c_addr;
-	struct i2c_adapter *i2c_adap;
 	unsigned char tda18271_regs[TDA18271_NUM_REGS];
 
-	struct list_head tda18271_list;
+	struct list_head	hybrid_tuner_instance_list;
+	struct tuner_i2c_props	i2c_props;
 
 	enum tda18271_mode mode;
+	enum tda18271_role role;
 	enum tda18271_i2c_gate gate;
 	enum tda18271_ver id;
 
-	unsigned int count;
 	unsigned int tm_rfcal;
 	unsigned int cal_initialized:1;
+	unsigned int small_i2c:1;
 
 	struct tda18271_map_layout *maps;
 	struct tda18271_std_map std;
@@ -133,7 +139,7 @@
 #define DBG_CAL  16
 
 #define tda_printk(kern, fmt, arg...) \
-	printk(kern "%s: " fmt, __FUNCTION__, ##arg)
+	printk(kern "%s: " fmt, __func__, ##arg)
 
 #define dprintk(kern, lvl, fmt, arg...) do {\
 	if (tda18271_debug & lvl) \
@@ -188,6 +194,8 @@
 extern int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len);
 extern int tda18271_init_regs(struct dvb_frontend *fe);
 
+extern int tda18271_charge_pump_source(struct dvb_frontend *fe,
+				       enum tda18271_pll pll, int force);
 extern int tda18271_set_standby_mode(struct dvb_frontend *fe,
 				     int sm, int sm_lt, int sm_xt);
 
diff --git a/drivers/media/dvb/frontends/tda18271-tables.c b/drivers/media/dvb/frontends/tda18271-tables.c
index e94afcf..83e7561 100644
--- a/drivers/media/dvb/frontends/tda18271-tables.c
+++ b/drivers/media/dvb/frontends/tda18271-tables.c
@@ -1187,37 +1187,65 @@
 /*---------------------------------------------------------------------*/
 
 static struct tda18271_std_map tda18271c1_std_map = {
-	.fm_radio = { .if_freq = 1250, .std_bits = 0x18 },
-	.atv_b    = { .if_freq = 6750, .std_bits = 0x0e },
-	.atv_dk   = { .if_freq = 7750, .std_bits = 0x0f },
-	.atv_gh   = { .if_freq = 7750, .std_bits = 0x0f },
-	.atv_i    = { .if_freq = 7750, .std_bits = 0x0f },
-	.atv_l    = { .if_freq = 7750, .std_bits = 0x0f },
-	.atv_lc   = { .if_freq = 1250, .std_bits = 0x0f },
-	.atv_mn   = { .if_freq = 5750, .std_bits = 0x0d },
-	.atsc_6   = { .if_freq = 3250, .std_bits = 0x1c },
-	.dvbt_6   = { .if_freq = 3300, .std_bits = 0x1c },
-	.dvbt_7   = { .if_freq = 3800, .std_bits = 0x1d },
-	.dvbt_8   = { .if_freq = 4300, .std_bits = 0x1e },
-	.qam_6    = { .if_freq = 4000, .std_bits = 0x1d },
-	.qam_8    = { .if_freq = 5000, .std_bits = 0x1f },
+	.fm_radio = { .if_freq = 1250, .fm_rfn = 1, .agc_mode = 3, .std = 0,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x18 */
+	.atv_b    = { .if_freq = 6750, .fm_rfn = 0, .agc_mode = 1, .std = 6,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */
+	.atv_dk   = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */
+	.atv_gh   = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */
+	.atv_i    = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */
+	.atv_l    = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */
+	.atv_lc   = { .if_freq = 1250, .fm_rfn = 0, .agc_mode = 1, .std = 7,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */
+	.atv_mn   = { .if_freq = 5750, .fm_rfn = 0, .agc_mode = 1, .std = 5,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0d */
+	.atsc_6   = { .if_freq = 3250, .fm_rfn = 0, .agc_mode = 3, .std = 4,
+		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */
+	.dvbt_6   = { .if_freq = 3300, .fm_rfn = 0, .agc_mode = 3, .std = 4,
+		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */
+	.dvbt_7   = { .if_freq = 3800, .fm_rfn = 0, .agc_mode = 3, .std = 5,
+		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */
+	.dvbt_8   = { .if_freq = 4300, .fm_rfn = 0, .agc_mode = 3, .std = 6,
+		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */
+	.qam_6    = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5,
+		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */
+	.qam_8    = { .if_freq = 5000, .fm_rfn = 0, .agc_mode = 3, .std = 7,
+		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1f */
 };
 
 static struct tda18271_std_map tda18271c2_std_map = {
-	.fm_radio = { .if_freq = 1250, .std_bits = 0x18 },
-	.atv_b    = { .if_freq = 6000, .std_bits = 0x0d },
-	.atv_dk   = { .if_freq = 6900, .std_bits = 0x0e },
-	.atv_gh   = { .if_freq = 7100, .std_bits = 0x0e },
-	.atv_i    = { .if_freq = 7250, .std_bits = 0x0e },
-	.atv_l    = { .if_freq = 6900, .std_bits = 0x0e },
-	.atv_lc   = { .if_freq = 1250, .std_bits = 0x0e },
-	.atv_mn   = { .if_freq = 5400, .std_bits = 0x0c },
-	.atsc_6   = { .if_freq = 3250, .std_bits = 0x1c },
-	.dvbt_6   = { .if_freq = 3300, .std_bits = 0x1c },
-	.dvbt_7   = { .if_freq = 3500, .std_bits = 0x1c },
-	.dvbt_8   = { .if_freq = 4000, .std_bits = 0x1d },
-	.qam_6    = { .if_freq = 4000, .std_bits = 0x1d },
-	.qam_8    = { .if_freq = 5000, .std_bits = 0x1f },
+	.fm_radio = { .if_freq = 1250, .fm_rfn = 1, .agc_mode = 3, .std = 0,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x18 */
+	.atv_b    = { .if_freq = 6000, .fm_rfn = 0, .agc_mode = 1, .std = 5,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0d */
+	.atv_dk   = { .if_freq = 6900, .fm_rfn = 0, .agc_mode = 1, .std = 6,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */
+	.atv_gh   = { .if_freq = 7100, .fm_rfn = 0, .agc_mode = 1, .std = 6,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */
+	.atv_i    = { .if_freq = 7250, .fm_rfn = 0, .agc_mode = 1, .std = 6,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */
+	.atv_l    = { .if_freq = 6900, .fm_rfn = 0, .agc_mode = 1, .std = 6,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */
+	.atv_lc   = { .if_freq = 1250, .fm_rfn = 0, .agc_mode = 1, .std = 6,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */
+	.atv_mn   = { .if_freq = 5400, .fm_rfn = 0, .agc_mode = 1, .std = 4,
+		      .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0c */
+	.atsc_6   = { .if_freq = 3250, .fm_rfn = 0, .agc_mode = 3, .std = 4,
+		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */
+	.dvbt_6   = { .if_freq = 3300, .fm_rfn = 0, .agc_mode = 3, .std = 4,
+		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */
+	.dvbt_7   = { .if_freq = 3500, .fm_rfn = 0, .agc_mode = 3, .std = 4,
+		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */
+	.dvbt_8   = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5,
+		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */
+	.qam_6    = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5,
+		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */
+	.qam_8    = { .if_freq = 5000, .fm_rfn = 0, .agc_mode = 3, .std = 7,
+		      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1f */
 };
 
 /*---------------------------------------------------------------------*/
diff --git a/drivers/media/dvb/frontends/tda18271.h b/drivers/media/dvb/frontends/tda18271.h
index 24b0e35..0e7af8d05 100644
--- a/drivers/media/dvb/frontends/tda18271.h
+++ b/drivers/media/dvb/frontends/tda18271.h
@@ -26,7 +26,17 @@
 
 struct tda18271_std_map_item {
 	u16 if_freq;
-	u8 std_bits;
+
+	/* EP3[4:3] */
+	unsigned int agc_mode:2;
+	/* EP3[2:0] */
+	unsigned int std:3;
+	/* EP4[7] */
+	unsigned int fm_rfn:1;
+	/* EP4[4:2] */
+	unsigned int if_lvl:3;
+	/* EB22[6:0] */
+	unsigned int rfagc_top:7;
 };
 
 struct tda18271_std_map {
@@ -46,6 +56,11 @@
 	struct tda18271_std_map_item qam_8;
 };
 
+enum tda18271_role {
+	TDA18271_MASTER = 0,
+	TDA18271_SLAVE,
+};
+
 enum tda18271_i2c_gate {
 	TDA18271_GATE_AUTO = 0,
 	TDA18271_GATE_ANALOG,
@@ -56,8 +71,14 @@
 	/* override default if freq / std settings (optional) */
 	struct tda18271_std_map *std_map;
 
+	/* master / slave tuner: master uses main pll, slave uses cal pll */
+	enum tda18271_role role;
+
 	/* use i2c gate provided by analog or digital demod */
 	enum tda18271_i2c_gate gate;
+
+	/* some i2c providers cant write all 39 registers at once */
+	unsigned int small_i2c:1;
 };
 
 #if defined(CONFIG_DVB_TDA18271) || (defined(CONFIG_DVB_TDA18271_MODULE) && defined(MODULE))
@@ -70,7 +91,7 @@
 						   struct i2c_adapter *i2c,
 						   struct tda18271_config *cfg)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif
diff --git a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb/frontends/tda8083.c
index 011b74f..5b843b2 100644
--- a/drivers/media/dvb/frontends/tda8083.c
+++ b/drivers/media/dvb/frontends/tda8083.c
@@ -68,7 +68,7 @@
 
 	if (ret != 1)
 		dprintk ("%s: writereg error (reg %02x, ret == %i)\n",
-			__FUNCTION__, reg, ret);
+			__func__, reg, ret);
 
 	return (ret != 1) ? -1 : 0;
 }
@@ -83,7 +83,7 @@
 
 	if (ret != 2)
 		dprintk ("%s: readreg error (reg %02x, ret == %i)\n",
-			__FUNCTION__, reg1, ret);
+			__func__, reg1, ret);
 
 	return ret == 2 ? 0 : -1;
 }
diff --git a/drivers/media/dvb/frontends/tda8083.h b/drivers/media/dvb/frontends/tda8083.h
index 2d33079..5a03c14 100644
--- a/drivers/media/dvb/frontends/tda8083.h
+++ b/drivers/media/dvb/frontends/tda8083.h
@@ -42,7 +42,7 @@
 static inline struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
 					   struct i2c_adapter* i2c)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_TDA8083
diff --git a/drivers/media/dvb/frontends/tda826x.c b/drivers/media/dvb/frontends/tda826x.c
index bd3ebc2..a051554 100644
--- a/drivers/media/dvb/frontends/tda826x.c
+++ b/drivers/media/dvb/frontends/tda826x.c
@@ -26,7 +26,7 @@
 
 #include "tda826x.h"
 
-static int debug = 0;
+static int debug;
 #define dprintk(args...) \
 	do { \
 		if (debug) printk(KERN_DEBUG "tda826x: " args); \
@@ -54,7 +54,7 @@
 	u8 buf [] = { 0x00, 0x8d };
 	struct i2c_msg msg = { .addr = priv->i2c_address, .flags = 0, .buf = buf, .len = 2 };
 
-	dprintk("%s:\n", __FUNCTION__);
+	dprintk("%s:\n", __func__);
 
 	if (!priv->has_loopthrough)
 		buf[1] = 0xad;
@@ -62,7 +62,7 @@
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
 	if ((ret = i2c_transfer (priv->i2c, &msg, 1)) != 1) {
-		dprintk("%s: i2c error\n", __FUNCTION__);
+		dprintk("%s: i2c error\n", __func__);
 	}
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 0);
@@ -75,13 +75,24 @@
 	struct tda826x_priv *priv = fe->tuner_priv;
 	int ret;
 	u32 div;
+	u32 ksyms;
+	u32 bandwidth;
 	u8 buf [11];
 	struct i2c_msg msg = { .addr = priv->i2c_address, .flags = 0, .buf = buf, .len = 11 };
 
-	dprintk("%s:\n", __FUNCTION__);
+	dprintk("%s:\n", __func__);
 
 	div = (params->frequency + (1000-1)) / 1000;
 
+	/* BW = ((1 + RO) * SR/2 + 5) * 1.3      [SR in MSPS, BW in MHz] */
+	/* with R0 = 0.35 and some transformations: */
+	ksyms = params->u.qpsk.symbol_rate / 1000;
+	bandwidth = (878 * ksyms + 6500000) / 1000000 + 1;
+	if (bandwidth < 5)
+		bandwidth = 5;
+	else if (bandwidth > 36)
+		bandwidth = 36;
+
 	buf[0] = 0x00; // subaddress
 	buf[1] = 0x09; // powerdown RSSI + the magic value 1
 	if (!priv->has_loopthrough)
@@ -89,7 +100,7 @@
 	buf[2] = (1<<5) | 0x0b; // 1Mhz + 0.45 VCO
 	buf[3] = div >> 7;
 	buf[4] = div << 1;
-	buf[5] = 0x77; // baseband cut-off 19 MHz
+	buf[5] = ((bandwidth - 5) << 3) | 7; /* baseband cut-off */
 	buf[6] = 0xfe; // baseband gain 9 db + no RF attenuation
 	buf[7] = 0x83; // charge pumps at high, tests off
 	buf[8] = 0x80; // recommended value 4 for AMPVCO + disable ports.
@@ -99,7 +110,7 @@
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
 	if ((ret = i2c_transfer (priv->i2c, &msg, 1)) != 1) {
-		dprintk("%s: i2c error\n", __FUNCTION__);
+		dprintk("%s: i2c error\n", __func__);
 	}
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 0);
@@ -138,7 +149,7 @@
 	};
 	int ret;
 
-	dprintk("%s:\n", __FUNCTION__);
+	dprintk("%s:\n", __func__);
 
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
diff --git a/drivers/media/dvb/frontends/tda826x.h b/drivers/media/dvb/frontends/tda826x.h
index ad99811..89e9792 100644
--- a/drivers/media/dvb/frontends/tda826x.h
+++ b/drivers/media/dvb/frontends/tda826x.h
@@ -45,7 +45,7 @@
 						  struct i2c_adapter *i2c,
 						  int has_loopthrough)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_TDA826X
diff --git a/drivers/media/dvb/frontends/tda827x.c b/drivers/media/dvb/frontends/tda827x.c
index 229b119..d30d2c9 100644
--- a/drivers/media/dvb/frontends/tda827x.c
+++ b/drivers/media/dvb/frontends/tda827x.c
@@ -25,7 +25,7 @@
 
 #include "tda827x.h"
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
 
@@ -142,7 +142,7 @@
 	int i, tuner_freq, if_freq;
 	u32 N;
 
-	dprintk("%s:\n", __FUNCTION__);
+	dprintk("%s:\n", __func__);
 	switch (params->u.ofdm.bandwidth) {
 	case BANDWIDTH_6_MHZ:
 		if_freq = 4000000;
@@ -186,7 +186,7 @@
 		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(priv->i2c_adap, &msg, 1) != 1) {
 		printk("%s: could not write to tuner at addr: 0x%02x\n",
-		       __FUNCTION__, priv->i2c_addr << 1);
+		       __func__, priv->i2c_addr << 1);
 		return -EIO;
 	}
 	msleep(500);
@@ -212,7 +212,7 @@
 	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
 			       .buf = buf, .len = sizeof(buf) };
 
-	dprintk("%s:\n", __FUNCTION__);
+	dprintk("%s:\n", __func__);
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
 	i2c_transfer(priv->i2c_adap, &msg, 1);
@@ -389,6 +389,79 @@
 	{ .lomax =         0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}
 };
 
+static int tda827xa_sleep(struct dvb_frontend *fe)
+{
+	struct tda827x_priv *priv = fe->tuner_priv;
+	static u8 buf[] = { 0x30, 0x90 };
+	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
+			       .buf = buf, .len = sizeof(buf) };
+
+	dprintk("%s:\n", __func__);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	if (priv->cfg && priv->cfg->sleep)
+		priv->cfg->sleep(fe);
+
+	return 0;
+}
+
+static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
+			      struct analog_parameters *params)
+{
+	struct tda827x_priv *priv = fe->tuner_priv;
+	unsigned char buf[] = {0x22, 0x01};
+	int arg;
+	int gp_func;
+	struct i2c_msg msg = { .addr = priv->cfg->switch_addr, .flags = 0,
+			       .buf = buf, .len = sizeof(buf) };
+
+	if (NULL == priv->cfg) {
+		dprintk("tda827x_config not defined, cannot set LNA gain!\n");
+		return;
+	}
+	if (priv->cfg->config) {
+		if (high)
+			dprintk("setting LNA to high gain\n");
+		else
+			dprintk("setting LNA to low gain\n");
+	}
+	switch (priv->cfg->config) {
+	case 0: /* no LNA */
+		break;
+	case 1: /* switch is GPIO 0 of tda8290 */
+	case 2:
+		if (params == NULL) {
+			gp_func = 0;
+			arg  = 0;
+		} else {
+			/* turn Vsync on */
+			gp_func = 1;
+			if (params->std & V4L2_STD_MN)
+				arg = 1;
+			else
+				arg = 0;
+		}
+		if (priv->cfg->tuner_callback)
+			priv->cfg->tuner_callback(priv->i2c_adap->algo_data,
+								gp_func, arg);
+		buf[1] = high ? 0 : 1;
+		if (priv->cfg->config == 2)
+			buf[1] = high ? 1 : 0;
+		i2c_transfer(priv->i2c_adap, &msg, 1);
+		break;
+	case 3: /* switch with GPIO of saa713x */
+		if (priv->cfg->tuner_callback)
+			priv->cfg->tuner_callback(priv->i2c_adap->algo_data, 0, high);
+		break;
+	}
+}
+
 static int tda827xa_set_params(struct dvb_frontend *fe,
 			       struct dvb_frontend_parameters *params)
 {
@@ -401,9 +474,9 @@
 	int i, tuner_freq, if_freq;
 	u32 N;
 
-	dprintk("%s:\n", __FUNCTION__);
-	if (priv->cfg && priv->cfg->lna_gain)
-		priv->cfg->lna_gain(fe, 1);
+	dprintk("%s:\n", __func__);
+
+	tda827xa_lna_gain(fe, 1, NULL);
 	msleep(20);
 
 	switch (params->u.ofdm.bandwidth) {
@@ -444,7 +517,7 @@
 		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(priv->i2c_adap, &msg, 1) != 1) {
 		printk("%s: could not write to tuner at addr: 0x%02x\n",
-		       __FUNCTION__, priv->i2c_addr << 1);
+		       __func__, priv->i2c_addr << 1);
 		return -EIO;
 	}
 	buf[0] = 0x90;
@@ -474,8 +547,7 @@
 	buf[1] >>= 4;
 	dprintk("tda8275a AGC2 gain is: %d\n", buf[1]);
 	if ((buf[1]) < 2) {
-		if (priv->cfg && priv->cfg->lna_gain)
-			priv->cfg->lna_gain(fe, 0);
+		tda827xa_lna_gain(fe, 0, NULL);
 		buf[0] = 0x60;
 		buf[1] = 0x0c;
 		if (fe->ops.i2c_gate_ctrl)
@@ -523,75 +595,6 @@
 	return 0;
 }
 
-static int tda827xa_sleep(struct dvb_frontend *fe)
-{
-	struct tda827x_priv *priv = fe->tuner_priv;
-	static u8 buf[] = { 0x30, 0x90 };
-	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
-			       .buf = buf, .len = sizeof(buf) };
-
-	dprintk("%s:\n", __FUNCTION__);
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-	i2c_transfer(priv->i2c_adap, &msg, 1);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-
-	if (priv->cfg && priv->cfg->sleep)
-		priv->cfg->sleep(fe);
-
-	return 0;
-}
-
-/* ------------------------------------------------------------------ */
-
-static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
-			      struct analog_parameters *params)
-{
-	struct tda827x_priv *priv = fe->tuner_priv;
-	unsigned char buf[] = {0x22, 0x01};
-	int arg;
-	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
-			       .buf = buf, .len = sizeof(buf) };
-
-	if (NULL == priv->cfg) {
-		dprintk("tda827x_config not defined, cannot set LNA gain!\n");
-		return;
-	}
-
-	if (priv->cfg->config) {
-		if (high)
-			dprintk("setting LNA to high gain\n");
-		else
-			dprintk("setting LNA to low gain\n");
-	}
-	switch (*priv->cfg->config) {
-	case 0: /* no LNA */
-		break;
-	case 1: /* switch is GPIO 0 of tda8290 */
-	case 2:
-		/* turn Vsync on */
-		if (params->std & V4L2_STD_MN)
-			arg = 1;
-		else
-			arg = 0;
-		if (priv->cfg->tuner_callback)
-			priv->cfg->tuner_callback(priv->i2c_adap->algo_data,
-						  1, arg);
-		buf[1] = high ? 0 : 1;
-		if (*priv->cfg->config == 2)
-			buf[1] = high ? 1 : 0;
-		i2c_transfer(priv->i2c_adap, &msg, 1);
-		break;
-	case 3: /* switch with GPIO of saa713x */
-		if (priv->cfg->tuner_callback)
-			priv->cfg->tuner_callback(priv->i2c_adap->algo_data,
-						  0, high);
-		break;
-	}
-}
 
 static int tda827xa_set_analog_params(struct dvb_frontend *fe,
 				      struct analog_parameters *params)
@@ -726,7 +729,7 @@
 static int tda827x_init(struct dvb_frontend *fe)
 {
 	struct tda827x_priv *priv = fe->tuner_priv;
-	dprintk("%s:\n", __FUNCTION__);
+	dprintk("%s:\n", __func__);
 	if (priv->cfg && priv->cfg->init)
 		priv->cfg->init(fe);
 
@@ -794,7 +797,7 @@
 		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(priv->i2c_adap, &msg, 1) != 1) {
 		printk("%s: could not read from tuner at addr: 0x%02x\n",
-		       __FUNCTION__, msg.addr << 1);
+		       __func__, msg.addr << 1);
 		return -EIO;
 	}
 	if ((data & 0x3c) == 0) {
@@ -818,7 +821,7 @@
 {
 	struct tda827x_priv *priv = NULL;
 
-	dprintk("%s:\n", __FUNCTION__);
+	dprintk("%s:\n", __func__);
 	priv = kzalloc(sizeof(struct tda827x_priv), GFP_KERNEL);
 	if (priv == NULL)
 		return NULL;
diff --git a/drivers/media/dvb/frontends/tda827x.h b/drivers/media/dvb/frontends/tda827x.h
index 92eb65b..b73c235 100644
--- a/drivers/media/dvb/frontends/tda827x.h
+++ b/drivers/media/dvb/frontends/tda827x.h
@@ -30,12 +30,12 @@
 struct tda827x_config
 {
 	/* saa7134 - provided callbacks */
-	void (*lna_gain) (struct dvb_frontend *fe, int high);
 	int (*init) (struct dvb_frontend *fe);
 	int (*sleep) (struct dvb_frontend *fe);
 
 	/* interface to tda829x driver */
-	unsigned int *config;
+	unsigned int config;
+	int 	     switch_addr;
 	int (*tuner_callback) (void *dev, int command, int arg);
 
 	void (*agcf)(struct dvb_frontend *fe);
@@ -61,7 +61,7 @@
 						  struct i2c_adapter *i2c,
 						  struct tda827x_config *cfg)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_TDA827X
diff --git a/drivers/media/dvb/frontends/tua6100.c b/drivers/media/dvb/frontends/tua6100.c
index 6ba0029..1790bae 100644
--- a/drivers/media/dvb/frontends/tua6100.c
+++ b/drivers/media/dvb/frontends/tua6100.c
@@ -58,7 +58,7 @@
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
 	if ((ret = i2c_transfer (priv->i2c, &msg, 1)) != 1) {
-		printk("%s: i2c error\n", __FUNCTION__);
+		printk("%s: i2c error\n", __func__);
 	}
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 0);
diff --git a/drivers/media/dvb/frontends/tua6100.h b/drivers/media/dvb/frontends/tua6100.h
index 03a665e..f83dbd5 100644
--- a/drivers/media/dvb/frontends/tua6100.h
+++ b/drivers/media/dvb/frontends/tua6100.h
@@ -39,7 +39,7 @@
 #else
 static inline struct dvb_frontend* tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_TUA6100
diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c
index 8791701..a184597 100644
--- a/drivers/media/dvb/frontends/ves1820.c
+++ b/drivers/media/dvb/frontends/ves1820.c
@@ -66,7 +66,7 @@
 
 	if (ret != 1)
 		printk("ves1820: %s(): writereg error (reg == 0x%02x, "
-			"val == 0x%02x, ret == %i)\n", __FUNCTION__, reg, data, ret);
+			"val == 0x%02x, ret == %i)\n", __func__, reg, data, ret);
 
 	return (ret != 1) ? -EREMOTEIO : 0;
 }
@@ -85,7 +85,7 @@
 
 	if (ret != 2)
 		printk("ves1820: %s(): readreg error (reg == 0x%02x, "
-		"ret == %i)\n", __FUNCTION__, reg, ret);
+		"ret == %i)\n", __func__, reg, ret);
 
 	return b1[0];
 }
diff --git a/drivers/media/dvb/frontends/ves1820.h b/drivers/media/dvb/frontends/ves1820.h
index e4a2a32..e902ed6 100644
--- a/drivers/media/dvb/frontends/ves1820.h
+++ b/drivers/media/dvb/frontends/ves1820.h
@@ -48,7 +48,7 @@
 static inline struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
 					   struct i2c_adapter* i2c, u8 pwm)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_VES1820
diff --git a/drivers/media/dvb/frontends/ves1x93.c b/drivers/media/dvb/frontends/ves1x93.c
index 23fd030..bd55896 100644
--- a/drivers/media/dvb/frontends/ves1x93.c
+++ b/drivers/media/dvb/frontends/ves1x93.c
@@ -48,7 +48,7 @@
 	u8 demod_type;
 };
 
-static int debug = 0;
+static int debug;
 #define dprintk	if (debug) printk
 
 #define DEMOD_VES1893		0
@@ -98,7 +98,7 @@
 	int err;
 
 	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
-		dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __FUNCTION__, err, reg, data);
+		dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __func__, err, reg, data);
 		return -EREMOTEIO;
 	}
 
@@ -179,7 +179,7 @@
 	u32 tmp;
 	u32 FIN;
 
-	dprintk("%s: srate == %d\n", __FUNCTION__, (unsigned int) srate);
+	dprintk("%s: srate == %d\n", __func__, (unsigned int) srate);
 
 	if (srate > state->config->xin/2)
 		srate = state->config->xin/2;
@@ -266,7 +266,7 @@
 	int i;
 	int val;
 
-	dprintk("%s: init chip\n", __FUNCTION__);
+	dprintk("%s: init chip\n", __func__);
 
 	for (i = 0; i < state->tab_size; i++) {
 		if (state->init_1x93_wtab[i]) {
diff --git a/drivers/media/dvb/frontends/ves1x93.h b/drivers/media/dvb/frontends/ves1x93.h
index d507f89..8a5a49e 100644
--- a/drivers/media/dvb/frontends/ves1x93.h
+++ b/drivers/media/dvb/frontends/ves1x93.h
@@ -47,7 +47,7 @@
 static inline struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
 					   struct i2c_adapter* i2c)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_VES1X93
diff --git a/drivers/media/dvb/frontends/xc5000.c b/drivers/media/dvb/frontends/xc5000.c
index f642ca2..43d35bd 100644
--- a/drivers/media/dvb/frontends/xc5000.c
+++ b/drivers/media/dvb/frontends/xc5000.c
@@ -151,7 +151,7 @@
 #define FM_Radio_INPUT2 	21
 #define FM_Radio_INPUT1 	22
 
-XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
+static XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
 	{"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020},
 	{"M/N-NTSC/PAL-A2",   0x0600, 0x8020},
 	{"M/N-NTSC/PAL-EIAJ", 0x0440, 0x8020},
@@ -209,7 +209,7 @@
 	struct xc5000_priv *priv = fe->tuner_priv;
 	int ret;
 
-	dprintk(1, "%s()\n", __FUNCTION__);
+	dprintk(1, "%s()\n", __func__);
 
 	if (priv->cfg->tuner_callback) {
 		ret = priv->cfg->tuner_callback(priv->cfg->priv,
@@ -330,7 +330,7 @@
 
 static int xc_initialize(struct xc5000_priv *priv)
 {
-	dprintk(1, "%s()\n", __FUNCTION__);
+	dprintk(1, "%s()\n", __func__);
 	return xc_write_reg(priv, XREG_INIT, 0);
 }
 
@@ -338,9 +338,9 @@
 	u16 VideoMode, u16 AudioMode)
 {
 	int ret;
-	dprintk(1, "%s(0x%04x,0x%04x)\n", __FUNCTION__, VideoMode, AudioMode);
+	dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, VideoMode, AudioMode);
 	dprintk(1, "%s() Standard = %s\n",
-		__FUNCTION__,
+		__func__,
 		XC5000_Standard[priv->video_standard].Name);
 
 	ret = xc_write_reg(priv, XREG_VIDEO_MODE, VideoMode);
@@ -361,7 +361,7 @@
 
 static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode)
 {
-	dprintk(1, "%s(%d) Source = %s\n", __FUNCTION__, rf_mode,
+	dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode,
 		rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE");
 
 	if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE))
@@ -369,7 +369,7 @@
 		rf_mode = XC_RF_MODE_CABLE;
 		printk(KERN_ERR
 			"%s(), Invalid mode, defaulting to CABLE",
-			__FUNCTION__);
+			__func__);
 	}
 	return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode);
 }
@@ -380,7 +380,7 @@
 {
 	u16 freq_code;
 
-	dprintk(1, "%s(%u)\n", __FUNCTION__, freq_hz);
+	dprintk(1, "%s(%u)\n", __func__, freq_hz);
 
 	if ((freq_hz > xc5000_tuner_ops.info.frequency_max) ||
 		(freq_hz < xc5000_tuner_ops.info.frequency_min))
@@ -396,7 +396,7 @@
 {
 	u32 freq_code = (freq_khz * 1024)/1000;
 	dprintk(1, "%s(freq_khz = %d) freq_code = 0x%x\n",
-		__FUNCTION__, freq_khz, freq_code);
+		__func__, freq_khz, freq_code);
 
 	return xc_write_reg(priv, XREG_IF_OUT, freq_code);
 }
@@ -488,7 +488,7 @@
 {
 	int found = 0;
 
-	dprintk(1, "%s(%u)\n", __FUNCTION__, freq_hz);
+	dprintk(1, "%s(%u)\n", __func__, freq_hz);
 
 	if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS)
 		return 0;
@@ -627,12 +627,12 @@
 	struct xc5000_priv *priv = fe->tuner_priv;
 	int ret;
 
-	dprintk(1, "%s() frequency=%d (Hz)\n", __FUNCTION__, params->frequency);
+	dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency);
 
 	switch(params->u.vsb.modulation) {
 	case VSB_8:
 	case VSB_16:
-		dprintk(1, "%s() VSB modulation\n", __FUNCTION__);
+		dprintk(1, "%s() VSB modulation\n", __func__);
 		priv->rf_mode = XC_RF_MODE_AIR;
 		priv->freq_hz = params->frequency - 1750000;
 		priv->bandwidth = BANDWIDTH_6_MHZ;
@@ -641,7 +641,7 @@
 	case QAM_64:
 	case QAM_256:
 	case QAM_AUTO:
-		dprintk(1, "%s() QAM modulation\n", __FUNCTION__);
+		dprintk(1, "%s() QAM modulation\n", __func__);
 		priv->rf_mode = XC_RF_MODE_CABLE;
 		priv->freq_hz = params->frequency - 1750000;
 		priv->bandwidth = BANDWIDTH_6_MHZ;
@@ -652,7 +652,7 @@
 	}
 
 	dprintk(1, "%s() frequency=%d (compensated)\n",
-		__FUNCTION__, priv->freq_hz);
+		__func__, priv->freq_hz);
 
 	ret = xc_SetSignalSource(priv, priv->rf_mode);
 	if (ret != XC_RESULT_SUCCESS) {
@@ -697,7 +697,7 @@
 		xc_load_fw_and_init_tuner(fe);
 
 	dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n",
-		__FUNCTION__, params->frequency);
+		__func__, params->frequency);
 
 	priv->rf_mode = XC_RF_MODE_CABLE; /* Fix me: it could be air. */
 
@@ -775,7 +775,7 @@
 static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq)
 {
 	struct xc5000_priv *priv = fe->tuner_priv;
-	dprintk(1, "%s()\n", __FUNCTION__);
+	dprintk(1, "%s()\n", __func__);
 	*freq = priv->freq_hz;
 	return 0;
 }
@@ -783,7 +783,7 @@
 static int xc5000_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
 {
 	struct xc5000_priv *priv = fe->tuner_priv;
-	dprintk(1, "%s()\n", __FUNCTION__);
+	dprintk(1, "%s()\n", __func__);
 
 	*bw = priv->bandwidth;
 	return 0;
@@ -796,7 +796,7 @@
 
 	xc_get_lock_status(priv, &lock_status);
 
-	dprintk(1, "%s() lock_status = 0x%08x\n", __FUNCTION__, lock_status);
+	dprintk(1, "%s() lock_status = 0x%08x\n", __func__, lock_status);
 
 	*status = lock_status;
 
@@ -836,7 +836,7 @@
 	struct xc5000_priv *priv = fe->tuner_priv;
 	int ret;
 
-	dprintk(1, "%s()\n", __FUNCTION__);
+	dprintk(1, "%s()\n", __func__);
 
 	/* On Pinnacle PCTV HD 800i, the tuner cannot be reinitialized
 	 * once shutdown without reloading the driver. Maybe I am not
@@ -848,7 +848,7 @@
 	if(ret != XC_RESULT_SUCCESS) {
 		printk(KERN_ERR
 			"xc5000: %s() unable to shutdown tuner\n",
-			__FUNCTION__);
+			__func__);
 		return -EREMOTEIO;
 	}
 	else {
@@ -860,7 +860,7 @@
 static int xc5000_init(struct dvb_frontend *fe)
 {
 	struct xc5000_priv *priv = fe->tuner_priv;
-	dprintk(1, "%s()\n", __FUNCTION__);
+	dprintk(1, "%s()\n", __func__);
 
 	if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) {
 		printk(KERN_ERR "xc5000: Unable to initialise tuner\n");
@@ -875,7 +875,7 @@
 
 static int xc5000_release(struct dvb_frontend *fe)
 {
-	dprintk(1, "%s()\n", __FUNCTION__);
+	dprintk(1, "%s()\n", __func__);
 	kfree(fe->tuner_priv);
 	fe->tuner_priv = NULL;
 	return 0;
@@ -907,7 +907,7 @@
 	struct xc5000_priv *priv = NULL;
 	u16 id = 0;
 
-	dprintk(1, "%s()\n", __FUNCTION__);
+	dprintk(1, "%s()\n", __func__);
 
 	priv = kzalloc(sizeof(struct xc5000_priv), GFP_KERNEL);
 	if (priv == NULL)
diff --git a/drivers/media/dvb/frontends/xc5000.h b/drivers/media/dvb/frontends/xc5000.h
index 32a5f1c..b890883 100644
--- a/drivers/media/dvb/frontends/xc5000.h
+++ b/drivers/media/dvb/frontends/xc5000.h
@@ -55,7 +55,7 @@
 						 struct i2c_adapter *i2c,
 						 struct xc5000_config *cfg)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif // CONFIG_DVB_TUNER_XC5000
diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c
index 276e3b6..36a5a1c 100644
--- a/drivers/media/dvb/frontends/zl10353.c
+++ b/drivers/media/dvb/frontends/zl10353.c
@@ -46,7 +46,7 @@
 		if (debug) printk(KERN_DEBUG "zl10353: " args); \
 	} while (0)
 
-static int debug_regs = 0;
+static int debug_regs;
 
 static int zl10353_single_write(struct dvb_frontend *fe, u8 reg, u8 val)
 {
@@ -88,7 +88,7 @@
 
 	if (ret != 2) {
 		printk("%s: readreg error (reg=%d, ret==%i)\n",
-		       __FUNCTION__, reg, ret);
+		       __func__, reg, ret);
 		return ret;
 	}
 
@@ -152,7 +152,7 @@
 	*nominal_rate = value;
 
 	dprintk("%s: bw %d, adc_clock %d => 0x%x\n",
-		__FUNCTION__, bw, adc_clock, *nominal_rate);
+		__func__, bw, adc_clock, *nominal_rate);
 }
 
 static void zl10353_calc_input_freq(struct dvb_frontend *fe,
@@ -181,7 +181,7 @@
 	*input_freq = -value;
 
 	dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n",
-		__FUNCTION__, if2, ife, adc_clock, -(int)value, *input_freq);
+		__func__, if2, ife, adc_clock, -(int)value, *input_freq);
 }
 
 static int zl10353_sleep(struct dvb_frontend *fe)
diff --git a/drivers/media/dvb/frontends/zl10353.h b/drivers/media/dvb/frontends/zl10353.h
index fc734c2..fdbb88f 100644
--- a/drivers/media/dvb/frontends/zl10353.h
+++ b/drivers/media/dvb/frontends/zl10353.h
@@ -47,7 +47,7 @@
 static inline struct dvb_frontend* zl10353_attach(const struct zl10353_config *config,
 					   struct i2c_adapter *i2c)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif /* CONFIG_DVB_ZL10353 */
diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c
index 08a2599..960ed57 100644
--- a/drivers/media/dvb/pluto2/pluto2.c
+++ b/drivers/media/dvb/pluto2/pluto2.c
@@ -39,6 +39,8 @@
 #include "dvbdev.h"
 #include "tda1004x.h"
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 #define DRIVER_NAME		"pluto2"
 
 #define REG_PIDn(n)		((n) << 2)	/* PID n pattern registers */
@@ -662,7 +664,8 @@
 		goto err_pluto_hw_exit;
 
 	/* dvb */
-	ret = dvb_register_adapter(&pluto->dvb_adapter, DRIVER_NAME, THIS_MODULE, &pdev->dev);
+	ret = dvb_register_adapter(&pluto->dvb_adapter, DRIVER_NAME,
+				   THIS_MODULE, &pdev->dev, adapter_nr);
 	if (ret < 0)
 		goto err_i2c_del_adapter;
 
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 0e5701b..747e7f1 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -112,6 +112,8 @@
 module_param(tv_standard, int, 0444);
 MODULE_PARM_DESC(tv_standard, "TV standard: 0 PAL (default), 1 NTSC");
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 static void restart_feeds(struct av7110 *av7110);
 
 static int av7110_num;
@@ -359,7 +361,7 @@
 {
 	dprintk(8, "%c %08lx %u\n", dir == DEBI_READ ? 'R' : 'W', addr, len);
 	if (saa7146_wait_for_debi_done(av7110->dev, 0)) {
-		printk(KERN_ERR "%s: saa7146_wait_for_debi_done timed out\n", __FUNCTION__);
+		printk(KERN_ERR "%s: saa7146_wait_for_debi_done timed out\n", __func__);
 		return;
 	}
 
@@ -497,7 +499,7 @@
 		       saa7146_read(av7110->dev, SSR));
 
 	if (saa7146_wait_for_debi_done(av7110->dev, 0)) {
-		printk(KERN_ERR "%s: saa7146_wait_for_debi_done timed out\n", __FUNCTION__);
+		printk(KERN_ERR "%s: saa7146_wait_for_debi_done timed out\n", __func__);
 		BUG(); /* maybe we should try resetting the debi? */
 	}
 
@@ -827,7 +829,7 @@
 	if (ret != 0 || handle >= 32) {
 		printk("dvb-ttpci: %s error  buf %04x %04x %04x %04x  "
 				"ret %d  handle %04x\n",
-				__FUNCTION__, buf[0], buf[1], buf[2], buf[3],
+				__func__, buf[0], buf[1], buf[2], buf[3],
 				ret, handle);
 		dvbdmxfilter->hw_handle = 0xffff;
 		if (!ret)
@@ -854,7 +856,7 @@
 	handle = dvbdmxfilter->hw_handle;
 	if (handle >= 32) {
 		printk("%s tried to stop invalid filter %04x, filter type = %x\n",
-				__FUNCTION__, handle, dvbdmxfilter->type);
+				__func__, handle, dvbdmxfilter->type);
 		return -EINVAL;
 	}
 
@@ -867,7 +869,7 @@
 	if (ret != 0 || answ[1] != handle) {
 		printk("dvb-ttpci: %s error  cmd %04x %04x %04x  ret %x  "
 				"resp %04x %04x  pid %d\n",
-				__FUNCTION__, buf[0], buf[1], buf[2], ret,
+				__func__, buf[0], buf[1], buf[2], ret,
 				answ[0], answ[1], dvbdmxfilter->feed->pid);
 		if (!ret)
 			ret = -1;
@@ -1122,7 +1124,7 @@
 
 	ret = av7110_fw_request(av7110, &tag, 0, fwstc, 4);
 	if (ret) {
-		printk(KERN_ERR "%s: av7110_fw_request error\n", __FUNCTION__);
+		printk(KERN_ERR "%s: av7110_fw_request error\n", __func__);
 		return ret;
 	}
 	dprintk(2, "fwstc = %04hx %04hx %04hx %04hx\n",
@@ -2461,7 +2463,7 @@
 		goto err_kfree_0;
 
 	ret = dvb_register_adapter(&av7110->dvb_adapter, av7110->card_name,
-				   THIS_MODULE, &dev->pci->dev);
+				   THIS_MODULE, &dev->pci->dev, adapter_nr);
 	if (ret < 0)
 		goto err_put_firmware_1;
 
diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h
index 39fbf7d..e494e04 100644
--- a/drivers/media/dvb/ttpci/av7110.h
+++ b/drivers/media/dvb/ttpci/av7110.h
@@ -40,7 +40,7 @@
 extern int av7110_debug;
 
 #define dprintk(level,args...) \
-	    do { if ((av7110_debug & level)) { printk("dvb-ttpci: %s(): ", __FUNCTION__); printk(args); } } while (0)
+	    do { if ((av7110_debug & level)) { printk("dvb-ttpci: %s(): ", __func__); printk(args); } } while (0)
 
 #define MAXFILT 32
 
diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c
index a468aa2..9d81074 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.c
+++ b/drivers/media/dvb/ttpci/av7110_hw.c
@@ -53,11 +53,11 @@
 	struct saa7146_dev *dev = av7110->dev;
 
 	if (count <= 0 || count > 32764) {
-		printk("%s: invalid count %d\n", __FUNCTION__, count);
+		printk("%s: invalid count %d\n", __func__, count);
 		return -1;
 	}
 	if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
-		printk("%s: wait_for_debi_done failed\n", __FUNCTION__);
+		printk("%s: wait_for_debi_done failed\n", __func__);
 		return -1;
 	}
 	saa7146_write(dev, DEBI_CONFIG, config);
@@ -76,11 +76,11 @@
 	u32 result = 0;
 
 	if (count > 32764 || count <= 0) {
-		printk("%s: invalid count %d\n", __FUNCTION__, count);
+		printk("%s: invalid count %d\n", __func__, count);
 		return 0;
 	}
 	if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
-		printk("%s: wait_for_debi_done #1 failed\n", __FUNCTION__);
+		printk("%s: wait_for_debi_done #1 failed\n", __func__);
 		return 0;
 	}
 	saa7146_write(dev, DEBI_AD, av7110->debi_bus);
@@ -91,7 +91,7 @@
 	if (count > 4)
 		return count;
 	if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
-		printk("%s: wait_for_debi_done #2 failed\n", __FUNCTION__);
+		printk("%s: wait_for_debi_done #2 failed\n", __func__);
 		return 0;
 	}
 
@@ -332,7 +332,7 @@
 			break;
 		if (err) {
 			printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n",
-				__FUNCTION__, stat & flags);
+				__func__, stat & flags);
 			return -ETIMEDOUT;
 		}
 		msleep(1);
@@ -362,7 +362,7 @@
 		if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
 			break;
 		if (err) {
-			printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__);
+			printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __func__);
 			av7110->arm_errors++;
 			return -ETIMEDOUT;
 		}
@@ -379,7 +379,7 @@
 		if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
 			break;
 		if (err) {
-			printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
+			printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __func__);
 			return -ETIMEDOUT;
 		}
 		msleep(1);
@@ -419,14 +419,14 @@
 			stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
 			if (stat & flags[0]) {
 				printk(KERN_ERR "%s: %s QUEUE overflow\n",
-					__FUNCTION__, type);
+					__func__, type);
 				return -1;
 			}
 			if ((stat & flags[1]) == 0)
 				break;
 			if (err) {
 				printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n",
-					__FUNCTION__, type);
+					__func__, type);
 				return -ETIMEDOUT;
 			}
 			msleep(1);
@@ -454,7 +454,7 @@
 			break;
 		if (err) {
 			printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete\n",
-			       __FUNCTION__, (buf[0] >> 8) & 0xff);
+			       __func__, (buf[0] >> 8) & 0xff);
 			return -ETIMEDOUT;
 		}
 		msleep(1);
@@ -462,11 +462,11 @@
 
 	stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
 	if (stat & GPMQOver) {
-		printk(KERN_ERR "dvb-ttpci: %s(): GPMQOver\n", __FUNCTION__);
+		printk(KERN_ERR "dvb-ttpci: %s(): GPMQOver\n", __func__);
 		return -ENOSPC;
 	}
 	else if (stat & OSDQOver) {
-		printk(KERN_ERR "dvb-ttpci: %s(): OSDQOver\n", __FUNCTION__);
+		printk(KERN_ERR "dvb-ttpci: %s(): OSDQOver\n", __func__);
 		return -ENOSPC;
 	}
 #endif
@@ -491,7 +491,7 @@
 	mutex_unlock(&av7110->dcomlock);
 	if (ret && ret!=-ERESTARTSYS)
 		printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n",
-		       __FUNCTION__, ret);
+		       __func__, ret);
 	return ret;
 }
 
@@ -575,7 +575,7 @@
 		if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
 			break;
 		if (err) {
-			printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __FUNCTION__);
+			printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __func__);
 			mutex_unlock(&av7110->dcomlock);
 			return -ETIMEDOUT;
 		}
@@ -591,7 +591,7 @@
 		if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
 			break;
 		if (err) {
-			printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
+			printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __func__);
 			mutex_unlock(&av7110->dcomlock);
 			return -ETIMEDOUT;
 		}
@@ -602,12 +602,12 @@
 #ifdef COM_DEBUG
 	stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
 	if (stat & GPMQOver) {
-		printk(KERN_ERR "%s: GPMQOver\n", __FUNCTION__);
+		printk(KERN_ERR "%s: GPMQOver\n", __func__);
 		mutex_unlock(&av7110->dcomlock);
 		return -1;
 	}
 	else if (stat & OSDQOver) {
-		printk(KERN_ERR "%s: OSDQOver\n", __FUNCTION__);
+		printk(KERN_ERR "%s: OSDQOver\n", __func__);
 		mutex_unlock(&av7110->dcomlock);
 		return -1;
 	}
@@ -741,7 +741,7 @@
 			break;
 		if (err) {
 			printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n",
-			       __FUNCTION__);
+			       __func__);
 			mutex_unlock(&av7110->dcomlock);
 			return -ETIMEDOUT;
 		}
@@ -768,7 +768,7 @@
 			break;
 		if (ret) {
 			printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n",
-			       __FUNCTION__);
+			       __func__);
 			mutex_unlock(&av7110->dcomlock);
 			return -ETIMEDOUT;
 		}
@@ -782,7 +782,7 @@
 			break;
 		if (ret) {
 			printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n",
-			       __FUNCTION__);
+			       __func__);
 			mutex_unlock(&av7110->dcomlock);
 			return -ETIMEDOUT;
 		}
diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c
index a283e1d..23a1c63 100644
--- a/drivers/media/dvb/ttpci/av7110_ir.c
+++ b/drivers/media/dvb/ttpci/av7110_ir.c
@@ -133,7 +133,7 @@
 		break;
 
 	default:
-		printk("%s invalid protocol %x\n", __FUNCTION__, ir->protocol);
+		printk("%s invalid protocol %x\n", __func__, ir->protocol);
 		return;
 	}
 
@@ -143,7 +143,7 @@
 	keycode = ir->key_map[data];
 
 	dprintk(16, "%s: code %08x -> addr %i data 0x%02x -> keycode %i\n",
-		__FUNCTION__, ircom, addr, data, keycode);
+		__func__, ircom, addr, data, keycode);
 
 	/* check device address */
 	if (!(ir->device_mask & (1 << addr)))
@@ -151,7 +151,7 @@
 
 	if (!keycode) {
 		printk ("%s: code %08x -> addr %i data 0x%02x -> unknown key!\n",
-			__FUNCTION__, ircom, addr, data);
+			__func__, ircom, addr, data);
 		return;
 	}
 
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
index e2f066f..b4a0cc5 100644
--- a/drivers/media/dvb/ttpci/av7110_v4l.c
+++ b/drivers/media/dvb/ttpci/av7110_v4l.c
@@ -573,7 +573,7 @@
 	struct saa7146_dev *dev = fh->dev;
 	struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
 
-	dprintk(2, "%s\n", __FUNCTION__);
+	dprintk(2, "%s\n", __func__);
 	av7110->wssMode = 0;
 	av7110->wssData = 0;
 	if (FW_VERSION(av7110->arm_app) < 0x2623)
@@ -590,7 +590,7 @@
 	struct v4l2_sliced_vbi_data d;
 	int rc;
 
-	dprintk(2, "%s\n", __FUNCTION__);
+	dprintk(2, "%s\n", __func__);
 	if (FW_VERSION(av7110->arm_app) < 0x2623 || !av7110->wssMode || count != sizeof d)
 		return -EINVAL;
 	if (copy_from_user(&d, data, count))
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 2d64d55..b30a528 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -178,7 +178,7 @@
 	udelay(1);
 
 	result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 3, 1, 0, 0);
-	if ((result == -ETIMEDOUT) || ((result == 0xff) && ((address & 3) < 2))) {
+	if (result == -ETIMEDOUT) {
 		ciintf_slot_shutdown(ca, slot);
 		printk(KERN_INFO "budget-av: cam ejected 3\n");
 		return -ETIMEDOUT;
@@ -577,7 +577,7 @@
 	.mclk = 88000000UL,
 	.invert = 0,
 	.skip_reinit = 0,
-	.lock_output = STV0229_LOCKOUTPUT_1,
+	.lock_output = STV0299_LOCKOUTPUT_1,
 	.volt13_op0_op1 = STV0299_VOLT13_OP0,
 	.min_delay_ms = 100,
 	.set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
@@ -590,7 +590,7 @@
 	.mclk = 88000000UL,
 	.invert = 0,
 	.skip_reinit = 0,
-	.lock_output = STV0229_LOCKOUTPUT_0,
+	.lock_output = STV0299_LOCKOUTPUT_0,
 	.volt13_op0_op1 = STV0299_VOLT13_OP0,
 	.min_delay_ms = 100,
 	.set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
@@ -602,7 +602,7 @@
 	.mclk = 88000000UL,
 	.invert = 1,
 	.skip_reinit = 0,
-	.lock_output = STV0229_LOCKOUTPUT_1,
+	.lock_output = STV0299_LOCKOUTPUT_1,
 	.volt13_op0_op1 = STV0299_VOLT13_OP0,
 	.min_delay_ms = 100,
 	.set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
@@ -869,7 +869,7 @@
 	.mclk = 88000000UL,
 	.invert = 0,
 	.skip_reinit = 0,
-	.lock_output = STV0229_LOCKOUTPUT_1,
+	.lock_output = STV0299_LOCKOUTPUT_1,
 	.volt13_op0_op1 = STV0299_VOLT13_OP0,
 	.min_delay_ms = 100,
 	.set_symbol_rate = philips_sd1878_ci_set_symbol_rate,
@@ -941,6 +941,12 @@
 	switch (saa->pci->subsystem_device) {
 
 	case SUBID_DVBS_KNC1:
+		/*
+		 * maybe that setting is needed for other dvb-s cards as well,
+		 * but so far it has been only confirmed for this type
+		 */
+		budget_av->reinitialise_demod = 1;
+		/* fall through */
 	case SUBID_DVBS_KNC1_PLUS:
 	case SUBID_DVBS_EASYWATCH_1:
 		if (saa->pci->subsystem_vendor == 0x1894) {
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index 5093492..6530323 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -86,7 +86,7 @@
 module_param(rc5_device, int, 0644);
 MODULE_PARM_DESC(rc5_device, "only IR commands to given RC5 device (device = 0 - 31, any device = 255, default: autodetect)");
 
-static int ir_debug = 0;
+static int ir_debug;
 module_param(ir_debug, int, 0644);
 MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
 
@@ -728,7 +728,7 @@
 	.mclk = 64000000UL,
 	.invert = 0,
 	.skip_reinit = 1,
-	.lock_output = STV0229_LOCKOUTPUT_1,
+	.lock_output = STV0299_LOCKOUTPUT_1,
 	.volt13_op0_op1 = STV0299_VOLT13_OP1,
 	.min_delay_ms = 50,
 	.set_symbol_rate = philips_su1278_tt_set_symbol_rate,
@@ -1121,7 +1121,7 @@
 
 			budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
 			if (dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0) == NULL) {
-				printk("%s: No LNBP21 found!\n", __FUNCTION__);
+				printk("%s: No LNBP21 found!\n", __func__);
 				dvb_frontend_detach(budget_ci->budget.dvb_frontend);
 				budget_ci->budget.dvb_frontend = NULL;
 			}
diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c
index 0252081..18cac4b 100644
--- a/drivers/media/dvb/ttpci/budget-core.c
+++ b/drivers/media/dvb/ttpci/budget-core.c
@@ -57,6 +57,8 @@
 MODULE_PARM_DESC(debug, "Turn on/off budget debugging (default:off).");
 MODULE_PARM_DESC(bufsize, "DMA buffer size in KB, default: 188, min: 188, max: 1410 (Activy: 564)");
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 /****************************************************************************
  * TT budget / WinTV Nova
  ****************************************************************************/
@@ -223,7 +225,7 @@
 
 	if (budget->buffer_warnings && time_after(jiffies, budget->buffer_warning_time)) {
 		printk("%s %s: used %d times >80%% of buffer (%u bytes now)\n",
-			budget->dev->name, __FUNCTION__, budget->buffer_warnings, count);
+			budget->dev->name, __func__, budget->buffer_warnings, count);
 		budget->buffer_warning_time = jiffies + BUFFER_WARNING_WAIT;
 		budget->buffer_warnings = 0;
 	}
@@ -471,9 +473,10 @@
 		budget->buffer_width, budget->buffer_height);
 	printk("%s: dma buffer size %u\n", budget->dev->name, budget->buffer_size);
 
-	if ((ret = dvb_register_adapter(&budget->dvb_adapter, budget->card->name, owner, &budget->dev->pci->dev)) < 0) {
+	ret = dvb_register_adapter(&budget->dvb_adapter, budget->card->name,
+				   owner, &budget->dev->pci->dev, adapter_nr);
+	if (ret < 0)
 		return ret;
-	}
 
 	/* set dd1 stream a & b */
 	saa7146_write(dev, DD1_STREAM_B, 0x00000000);
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index 14b00f5..2293d80 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -45,6 +45,7 @@
 #include "tda826x.h"
 #include "lnbp21.h"
 #include "bsru6.h"
+#include "bsbe1.h"
 
 static int diseqc_method;
 module_param(diseqc_method, int, 0444);
@@ -257,11 +258,17 @@
 
 static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
-	struct budget* budget = (struct budget*) fe->dvb->priv;
+	struct budget *budget = fe->dvb->priv;
+	u8 *tuner_addr = fe->tuner_priv;
 	u32 div;
 	u8 cfg, cpump, band_select;
 	u8 data[4];
-	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+	struct i2c_msg msg = { .flags = 0, .buf = data, .len = sizeof(data) };
+
+	if (tuner_addr)
+		msg.addr = *tuner_addr;
+	else
+		msg.addr = 0x61;
 
 	div = (36125000 + params->frequency) / 166666;
 
@@ -292,6 +299,12 @@
 	.demod_address = 0x55,
 };
 
+static struct l64781_config grundig_29504_401_config_activy = {
+	.demod_address = 0x54,
+};
+
+static u8 tuner_address_grundig_29504_401_activy = 0x60;
+
 static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
 	struct budget* budget = (struct budget*) fe->dvb->priv;
@@ -346,14 +359,48 @@
 static struct s5h1420_config s5h1420_config = {
 	.demod_address = 0x53,
 	.invert = 1,
+	.cdclk_polarity = 1,
 };
 
 static struct tda10086_config tda10086_config = {
 	.demod_address = 0x0e,
 	.invert = 0,
 	.diseqc_tone = 1,
+	.xtal_freq = TDA10086_XTAL_16M,
 };
 
+static struct stv0299_config alps_bsru6_config_activy = {
+	.demod_address = 0x68,
+	.inittab = alps_bsru6_inittab,
+	.mclk = 88000000UL,
+	.invert = 1,
+	.op0_off = 1,
+	.min_delay_ms = 100,
+	.set_symbol_rate = alps_bsru6_set_symbol_rate,
+};
+
+static struct stv0299_config alps_bsbe1_config_activy = {
+	.demod_address = 0x68,
+	.inittab = alps_bsbe1_inittab,
+	.mclk = 88000000UL,
+	.invert = 1,
+	.op0_off = 1,
+	.min_delay_ms = 100,
+	.set_symbol_rate = alps_bsbe1_set_symbol_rate,
+};
+
+
+static int i2c_readreg(struct i2c_adapter *i2c, u8 adr, u8 reg)
+{
+	u8 val;
+	struct i2c_msg msg[] = {
+		{ .addr = adr, .flags = 0, .buf = &reg, .len = 1 },
+		{ .addr = adr, .flags = I2C_M_RD, .buf = &val, .len = 1 }
+	};
+
+	return (i2c_transfer(i2c, msg, 2) != 2) ? -EIO : val;
+}
+
 static u8 read_pwm(struct budget* budget)
 {
 	u8 b = 0xff;
@@ -369,6 +416,8 @@
 
 static void frontend_init(struct budget *budget)
 {
+	(void)alps_bsbe1_config; /* avoid warning */
+
 	switch(budget->dev->pci->subsystem_device) {
 	case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659))
 	case 0x1013:
@@ -414,15 +463,43 @@
 		}
 		break;
 
-	case 0x4f60: // Fujitsu Siemens Activy Budget-S PCI rev AL (stv0299/ALPS BSRU6(tsa5059))
-		budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap);
-		if (budget->dvb_frontend) {
-			budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
-			budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
-			budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;
-			budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
+	case 0x4f60: /* Fujitsu Siemens Activy Budget-S PCI rev AL (stv0299/tsa5059) */
+	{
+		int subtype = i2c_readreg(&budget->i2c_adap, 0x50, 0x67);
+
+		if (subtype < 0)
+			break;
+		/* fixme: find a better way to identify the card */
+		if (subtype < 0x36) {
+			/* assume ALPS BSRU6 */
+			budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config_activy, &budget->i2c_adap);
+			if (budget->dvb_frontend) {
+				printk(KERN_INFO "budget: tuner ALPS BSRU6 detected\n");
+				budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+				budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+				budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;
+				budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
+				break;
+			}
+		} else {
+			/* assume ALPS BSBE1 */
+			/* reset tuner */
+			saa7146_setgpio(budget->dev, 3, SAA7146_GPIO_OUTLO);
+			msleep(50);
+			saa7146_setgpio(budget->dev, 3, SAA7146_GPIO_OUTHI);
+			msleep(250);
+			budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config_activy, &budget->i2c_adap);
+			if (budget->dvb_frontend) {
+				printk(KERN_INFO "budget: tuner ALPS BSBE1 detected\n");
+				budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
+				budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+				budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;
+				budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
+				break;
+			}
 		}
 		break;
+	}
 
 	case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI rev GR (tda8083/Grundig 29504-451(tsa5522))
 		budget->dvb_frontend = dvb_attach(tda8083_attach, &grundig_29504_451_config, &budget->i2c_adap);
@@ -433,12 +510,20 @@
 		}
 		break;
 
+	case 0x5f61: /* Fujitsu Siemens Activy Budget-T PCI rev GR (L64781/Grundig 29504-401(tsa5060)) */
+		budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config_activy, &budget->i2c_adap);
+		if (budget->dvb_frontend) {
+			budget->dvb_frontend->tuner_priv = &tuner_address_grundig_29504_401_activy;
+			budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;
+		}
+		break;
+
 	case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260))
 		budget->dvb_frontend = dvb_attach(s5h1420_attach, &s5h1420_config, &budget->i2c_adap);
 		if (budget->dvb_frontend) {
 			budget->dvb_frontend->ops.tuner_ops.set_params = s5h1420_tuner_set_params;
 			if (dvb_attach(lnbp21_attach, budget->dvb_frontend, &budget->i2c_adap, 0, 0) == NULL) {
-				printk("%s: No LNBP21 found!\n", __FUNCTION__);
+				printk("%s: No LNBP21 found!\n", __func__);
 				goto error_out;
 			}
 			break;
@@ -454,9 +539,9 @@
 		budget->dvb_frontend = dvb_attach(tda10086_attach, &tda10086_config, &budget->i2c_adap);
 		if (budget->dvb_frontend) {
 			if (dvb_attach(tda826x_attach, budget->dvb_frontend, 0x60, &budget->i2c_adap, 0) == NULL)
-				printk("%s: No tda826x found!\n", __FUNCTION__);
+				printk("%s: No tda826x found!\n", __func__);
 			if (dvb_attach(lnbp21_attach, budget->dvb_frontend, &budget->i2c_adap, 0, 0) == NULL) {
-				printk("%s: No LNBP21 found!\n", __FUNCTION__);
+				printk("%s: No LNBP21 found!\n", __func__);
 				goto error_out;
 			}
 			break;
@@ -537,6 +622,7 @@
 MAKE_BUDGET_INFO(ttbs1401, "TT-Budget-S-1401 PCI", BUDGET_TT);
 MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY);
 MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY);
+MAKE_BUDGET_INFO(fsact,	 "Fujitsu Siemens Activy Budget-T PCI (rev GR/Grundig frontend)", BUDGET_FS_ACTIVY);
 
 static struct pci_device_id pci_tbl[] = {
 	MAKE_EXTENSION_PCI(ttbs,  0x13c2, 0x1003),
@@ -547,6 +633,7 @@
 	MAKE_EXTENSION_PCI(ttbs1401, 0x13c2, 0x1018),
 	MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60),
 	MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61),
+	MAKE_EXTENSION_PCI(fsact, 0x1131, 0x5f61),
 	{
 		.vendor    = 0,
 	}
diff --git a/drivers/media/dvb/ttpci/budget.h b/drivers/media/dvb/ttpci/budget.h
index d764ffa..dd450b7 100644
--- a/drivers/media/dvb/ttpci/budget.h
+++ b/drivers/media/dvb/ttpci/budget.h
@@ -1,3 +1,4 @@
+
 #ifndef __BUDGET_DVB__
 #define __BUDGET_DVB__
 
@@ -21,7 +22,7 @@
 #endif
 
 #define dprintk(level,args...) \
-	    do { if ((budget_debug & level)) { printk("%s: %s(): ", KBUILD_MODNAME, __FUNCTION__); printk(args); } } while (0)
+	    do { if ((budget_debug & level)) { printk("%s: %s(): ", KBUILD_MODNAME, __func__); printk(args); } } while (0)
 
 struct budget_info {
 	char *name;
diff --git a/drivers/media/dvb/ttpci/ttpci-eeprom.c b/drivers/media/dvb/ttpci/ttpci-eeprom.c
index 1f31e91..7dd54b3 100644
--- a/drivers/media/dvb/ttpci/ttpci-eeprom.c
+++ b/drivers/media/dvb/ttpci/ttpci-eeprom.c
@@ -95,7 +95,7 @@
 		{ .addr = 0x50, .flags = I2C_M_RD, .buf = encodedMAC, .len = 20 }
 	};
 
-	/* dprintk("%s\n", __FUNCTION__); */
+	/* dprintk("%s\n", __func__); */
 
 	ret = i2c_transfer(adapter, msg, 2);
 
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index 7902ae1..732ce4d 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -56,10 +56,11 @@
 */
 
 static int debug;
-
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 #define dprintk(x...) do { if (debug) printk(KERN_DEBUG x); } while (0)
 
 #define ISO_BUF_COUNT      4
@@ -153,12 +154,12 @@
 			   (u8 *) data, len, &actual_len, 1000);
 	if (err != 0) {
 		dprintk("%s: usb_bulk_msg(send) failed, err == %i!\n",
-			__FUNCTION__, err);
+			__func__, err);
 		mutex_unlock(&ttusb->semusb);
 		return err;
 	}
 	if (actual_len != len) {
-		dprintk("%s: only wrote %d of %d bytes\n", __FUNCTION__,
+		dprintk("%s: only wrote %d of %d bytes\n", __func__,
 			actual_len, len);
 		mutex_unlock(&ttusb->semusb);
 		return -1;
@@ -168,7 +169,7 @@
 			   ttusb->last_result, 32, &actual_len, 1000);
 
 	if (err != 0) {
-		printk("%s: failed, receive error %d\n", __FUNCTION__,
+		printk("%s: failed, receive error %d\n", __func__,
 		       err);
 		mutex_unlock(&ttusb->semusb);
 		return err;
@@ -229,7 +230,7 @@
 		if (err || b[0] != 0x55 || b[1] != id) {
 			dprintk
 			    ("%s: usb_bulk_msg(recv) failed, err == %i, id == %02x, b == ",
-			     __FUNCTION__, err, id);
+			     __func__, err, id);
 			return -EREMOTEIO;
 		}
 
@@ -273,7 +274,7 @@
 				    snd_buf, snd_len, rcv_buf, rcv_len);
 
 		if (err < rcv_len) {
-			dprintk("%s: i == %i\n", __FUNCTION__, i);
+			dprintk("%s: i == %i\n", __func__, i);
 			break;
 		}
 
@@ -327,7 +328,7 @@
       done:
 	if (err) {
 		dprintk("%s: usb_bulk_msg() failed, return value %i!\n",
-			__FUNCTION__, err);
+			__func__, err);
 	}
 
 	return err;
@@ -427,7 +428,7 @@
 	if ((err = ttusb_result(ttusb, get_version, sizeof(get_version))))
 		return err;
 
-	dprintk("%s: stc-version: %c%c%c%c%c\n", __FUNCTION__,
+	dprintk("%s: stc-version: %c%c%c%c%c\n", __func__,
 		get_version[4], get_version[5], get_version[6],
 		get_version[7], get_version[8]);
 
@@ -437,7 +438,7 @@
 	    memcmp(get_version + 4, "V 2.2", 5)) {
 		printk
 		    ("%s: unknown STC version %c%c%c%c%c, please report!\n",
-		     __FUNCTION__, get_version[4], get_version[5],
+		     __func__, get_version[4], get_version[5],
 		     get_version[6], get_version[7], get_version[8]);
 	}
 
@@ -453,7 +454,7 @@
 	    ttusb_result(ttusb, get_dsp_version, sizeof(get_dsp_version));
 	if (err)
 		return err;
-	printk("%s: dsp-version: %c%c%c\n", __FUNCTION__,
+	printk("%s: dsp-version: %c%c%c\n", __func__,
 	       get_dsp_version[4], get_dsp_version[5], get_dsp_version[6]);
 	return 0;
 }
@@ -476,7 +477,7 @@
 	/* Diseqc */
 	if ((err = ttusb_cmd(ttusb, b, 4 + b[3], 0))) {
 		dprintk("%s: usb_bulk_msg() failed, return value %i!\n",
-			__FUNCTION__, err);
+			__func__, err);
 	}
 
 	return err;
@@ -494,7 +495,7 @@
 	/* SetLNB */
 	if ((err = ttusb_cmd(ttusb, b, sizeof(b), 0))) {
 		dprintk("%s: usb_bulk_msg() failed, return value %i!\n",
-			__FUNCTION__, err);
+			__func__, err);
 	}
 
 	return err;
@@ -528,7 +529,7 @@
 	err = ttusb_cmd(ttusb, b, sizeof(b), 0);
 	if (err) {
 		dprintk("%s: usb_bulk_msg() failed, return value %i!\n",
-			__FUNCTION__, err);
+			__func__, err);
 	}
 }
 #endif
@@ -542,7 +543,7 @@
 				  const u8 * data, int len);
 #endif
 
-static int numpkt = 0, numts, numstuff, numsec, numinvalid;
+static int numpkt, numts, numstuff, numsec, numinvalid;
 static unsigned long lastj;
 
 static void ttusb_process_muxpack(struct ttusb *ttusb, const u8 * muxpack,
@@ -554,7 +555,7 @@
 		csum ^= le16_to_cpup((u16 *) (muxpack + i));
 	if (csum) {
 		printk("%s: muxpack with incorrect checksum, ignoring\n",
-		       __FUNCTION__);
+		       __func__);
 		numinvalid++;
 		return;
 	}
@@ -563,7 +564,7 @@
 	cc &= 0x7FFF;
 	if ((cc != ttusb->cc) && (ttusb->cc != -1))
 		printk("%s: cc discontinuity (%d frames missing)\n",
-		       __FUNCTION__, (cc - ttusb->cc) & 0x7FFF);
+		       __func__, (cc - ttusb->cc) & 0x7FFF);
 	ttusb->cc = (cc + 1) & 0x7FFF;
 	if (muxpack[0] & 0x80) {
 #ifdef TTUSB_HWSECTIONS
@@ -613,7 +614,7 @@
 	int maxwork = 1024;
 	while (len) {
 		if (!(maxwork--)) {
-			printk("%s: too much work\n", __FUNCTION__);
+			printk("%s: too much work\n", __func__);
 			break;
 		}
 
@@ -632,7 +633,7 @@
 #else
 				if (ttusb->insync) {
 					printk("%s: lost sync.\n",
-					       __FUNCTION__);
+					       __func__);
 					ttusb->insync = 0;
 				}
 #endif
@@ -691,7 +692,7 @@
 					else {
 						dprintk
 						    ("%s: invalid state: first byte is %x\n",
-						     __FUNCTION__,
+						     __func__,
 						     ttusb->muxpack[0]);
 						ttusb->mux_state = 0;
 					}
@@ -740,7 +741,7 @@
 
 #if 0
 	printk("%s: status %d, errcount == %d, length == %i\n",
-	       __FUNCTION__,
+	       __func__,
 	       urb->status, urb->error_count, urb->actual_length);
 #endif
 
@@ -833,7 +834,7 @@
 	int i, j, err, buffer_offset = 0;
 
 	if (ttusb->iso_streaming) {
-		printk("%s: iso xfer already running!\n", __FUNCTION__);
+		printk("%s: iso xfer already running!\n", __func__);
 		return 0;
 	}
 
@@ -869,7 +870,7 @@
 			ttusb_stop_iso_xfer(ttusb);
 			printk
 			    ("%s: failed urb submission (%i: err = %i)!\n",
-			     __FUNCTION__, i, err);
+			     __func__, i, err);
 			return err;
 		}
 	}
@@ -1005,7 +1006,7 @@
 	return 0;
 }
 
-static struct file_operations stc_fops = {
+static const struct file_operations stc_fops = {
 	.owner = THIS_MODULE,
 	.read = stc_read,
 	.open = stc_open,
@@ -1313,7 +1314,7 @@
 	.mclk = 88000000UL,
 	.invert = 1,
 	.skip_reinit = 0,
-	.lock_output = STV0229_LOCKOUTPUT_1,
+	.lock_output = STV0299_LOCKOUTPUT_1,
 	.volt13_op0_op1 = STV0299_VOLT13_OP1,
 	.min_delay_ms = 100,
 	.set_symbol_rate = alps_stv0299_set_symbol_rate,
@@ -1643,7 +1644,7 @@
 	struct ttusb *ttusb;
 	int result;
 
-	dprintk("%s: TTUSB DVB connected\n", __FUNCTION__);
+	dprintk("%s: TTUSB DVB connected\n", __func__);
 
 	udev = interface_to_usbdev(intf);
 
@@ -1669,7 +1670,10 @@
 
 	mutex_unlock(&ttusb->semi2c);
 
-	if ((result = dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE, &udev->dev)) < 0) {
+	result = dvb_register_adapter(&ttusb->adapter,
+				      "Technotrend/Hauppauge Nova-USB",
+				      THIS_MODULE, &udev->dev, adapter_nr);
+	if (result < 0) {
 		ttusb_free_iso_urbs(ttusb);
 		kfree(ttusb);
 		return result;
@@ -1773,7 +1777,7 @@
 
 	kfree(ttusb);
 
-	dprintk("%s: TTUSB DVB disconnected\n", __FUNCTION__);
+	dprintk("%s: TTUSB DVB disconnected\n", __func__);
 }
 
 static struct usb_device_id ttusb_table[] = {
diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
index 1ec981d..42eee04 100644
--- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
@@ -52,6 +52,8 @@
 module_param(enable_rc, int, 0644);
 MODULE_PARM_DESC(enable_rc, "Turn on/off IR remote control(default: off)");
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 #define dprintk	if (debug) printk
 
 #define DRIVER_NAME		"TechnoTrend/Hauppauge DEC USB"
@@ -217,11 +219,11 @@
 		case -ETIME:
 			/* this urb is dead, cleanup */
 			dprintk("%s:urb shutting down with status: %d\n",
-					__FUNCTION__, urb->status);
+					__func__, urb->status);
 			return;
 		default:
 			dprintk("%s:nonzero status received: %d\n",
-					__FUNCTION__,urb->status);
+					__func__,urb->status);
 			goto exit;
 	}
 
@@ -235,7 +237,7 @@
 		 * keyrepeat signal is recieved for lets say 200ms.
 		 * this should/could be added later ...
 		 * for now lets report each signal as a key down and up*/
-		dprintk("%s:rc signal:%d\n", __FUNCTION__, buffer[4]);
+		dprintk("%s:rc signal:%d\n", __func__, buffer[4]);
 		input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 1);
 		input_sync(dec->rc_input_dev);
 		input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 0);
@@ -245,7 +247,7 @@
 exit:	retval = usb_submit_urb(urb, GFP_ATOMIC);
 	if(retval)
 		printk("%s - usb_commit_urb failed with result: %d\n",
-			__FUNCTION__, retval);
+			__func__, retval);
 }
 
 static u16 crc16(u16 crc, const u8 *buf, size_t len)
@@ -268,7 +270,7 @@
 	int result, actual_len, i;
 	u8 *b;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	b = kmalloc(COMMAND_PACKET_SIZE + 4, GFP_KERNEL);
 	if (!b)
@@ -276,7 +278,7 @@
 
 	if ((result = mutex_lock_interruptible(&dec->usb_mutex))) {
 		kfree(b);
-		printk("%s: Failed to lock usb mutex.\n", __FUNCTION__);
+		printk("%s: Failed to lock usb mutex.\n", __func__);
 		return result;
 	}
 
@@ -289,7 +291,7 @@
 		memcpy(&b[4], params, param_length);
 
 	if (debug) {
-		printk("%s: command: ", __FUNCTION__);
+		printk("%s: command: ", __func__);
 		for (i = 0; i < param_length + 4; i++)
 			printk("0x%02X ", b[i]);
 		printk("\n");
@@ -300,7 +302,7 @@
 
 	if (result) {
 		printk("%s: command bulk message failed: error %d\n",
-		       __FUNCTION__, result);
+		       __func__, result);
 		mutex_unlock(&dec->usb_mutex);
 		kfree(b);
 		return result;
@@ -311,13 +313,13 @@
 
 	if (result) {
 		printk("%s: result bulk message failed: error %d\n",
-		       __FUNCTION__, result);
+		       __func__, result);
 		mutex_unlock(&dec->usb_mutex);
 		kfree(b);
 		return result;
 	} else {
 		if (debug) {
-			printk("%s: result: ", __FUNCTION__);
+			printk("%s: result: ", __func__);
 			for (i = 0; i < actual_len; i++)
 				printk("0x%02X ", b[i]);
 			printk("\n");
@@ -343,7 +345,7 @@
 	int result;
 	unsigned int tmp;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	result = ttusb_dec_send_command(dec, 0x08, 0, NULL, &c_length, c);
 	if (result)
@@ -400,7 +402,7 @@
 	u16 audio = htons(dec->pid[DMX_PES_AUDIO]);
 	u16 video = htons(dec->pid[DMX_PES_VIDEO]);
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	memcpy(&b[0], &pcr, 2);
 	memcpy(&b[2], &audio, 2);
@@ -419,12 +421,12 @@
 static void ttusb_dec_process_pva(struct ttusb_dec *dec, u8 *pva, int length)
 {
 	if (length < 8) {
-		printk("%s: packet too short - discarding\n", __FUNCTION__);
+		printk("%s: packet too short - discarding\n", __func__);
 		return;
 	}
 
 	if (length > 8 + MAX_PVA_LENGTH) {
-		printk("%s: packet too long - discarding\n", __FUNCTION__);
+		printk("%s: packet too long - discarding\n", __func__);
 		return;
 	}
 
@@ -507,7 +509,7 @@
 		break;
 
 	default:
-		printk("%s: unknown PVA type: %02x.\n", __FUNCTION__,
+		printk("%s: unknown PVA type: %02x.\n", __func__,
 		       pva[2]);
 		break;
 	}
@@ -546,7 +548,7 @@
 	u16 packet_id;
 
 	if (dec->packet_length % 2) {
-		printk("%s: odd sized packet - discarding\n", __FUNCTION__);
+		printk("%s: odd sized packet - discarding\n", __func__);
 		return;
 	}
 
@@ -554,7 +556,7 @@
 		csum ^= ((dec->packet[i] << 8) + dec->packet[i + 1]);
 
 	if (csum) {
-		printk("%s: checksum failed - discarding\n", __FUNCTION__);
+		printk("%s: checksum failed - discarding\n", __func__);
 		return;
 	}
 
@@ -563,7 +565,7 @@
 
 	if ((packet_id != dec->next_packet_id) && dec->next_packet_id) {
 		printk("%s: warning: lost packets between %u and %u\n",
-		       __FUNCTION__, dec->next_packet_id - 1, packet_id);
+		       __func__, dec->next_packet_id - 1, packet_id);
 	}
 
 	if (packet_id == 0xffff)
@@ -652,7 +654,7 @@
 					dec->packet_state = 7;
 				} else {
 					printk("%s: unknown packet type: "
-					       "%02x%02x\n", __FUNCTION__,
+					       "%02x%02x\n", __func__,
 					       dec->packet[0], dec->packet[1]);
 					dec->packet_state = 0;
 				}
@@ -724,7 +726,7 @@
 
 		default:
 			printk("%s: illegal packet state encountered.\n",
-			       __FUNCTION__);
+			       __func__);
 			dec->packet_state = 0;
 		}
 	}
@@ -792,7 +794,7 @@
 	} else {
 		 /* -ENOENT is expected when unlinking urbs */
 		if (urb->status != -ENOENT)
-			dprintk("%s: urb error: %d\n", __FUNCTION__,
+			dprintk("%s: urb error: %d\n", __func__,
 				urb->status);
 	}
 
@@ -804,7 +806,7 @@
 {
 	int i, j, buffer_offset = 0;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	for (i = 0; i < ISO_BUF_COUNT; i++) {
 		int frame_offset = 0;
@@ -834,7 +836,7 @@
 {
 	int i;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	if (mutex_lock_interruptible(&dec->iso_mutex))
 		return;
@@ -889,7 +891,7 @@
 {
 	int i, result;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	if (mutex_lock_interruptible(&dec->iso_mutex))
 		return -EAGAIN;
@@ -905,7 +907,7 @@
 			if ((result = usb_submit_urb(dec->iso_urb[i],
 						     GFP_ATOMIC))) {
 				printk("%s: failed urb submission %d: "
-				       "error %d\n", __FUNCTION__, i, result);
+				       "error %d\n", __func__, i, result);
 
 				while (i) {
 					usb_kill_urb(dec->iso_urb[i - 1]);
@@ -932,7 +934,7 @@
 	u8 b0[] = { 0x05 };
 	int result = 0;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	dprintk("  ts_type:");
 
@@ -1012,7 +1014,7 @@
 	unsigned long flags;
 	u8 x = 1;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	pid = htons(dvbdmxfeed->pid);
 	memcpy(&b0[0], &pid, 2);
@@ -1052,7 +1054,7 @@
 {
 	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	if (!dvbdmx->dmx.frontend)
 		return -EINVAL;
@@ -1113,7 +1115,7 @@
 
 static int ttusb_dec_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
 {
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	switch (dvbdmxfeed->type) {
 	case DMX_TYPE_TS:
@@ -1132,7 +1134,7 @@
 {
 	int i;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	for (i = 0; i < ISO_BUF_COUNT; i++)
 		usb_free_urb(dec->iso_urb[i]);
@@ -1147,7 +1149,7 @@
 {
 	int i;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	dec->iso_buffer = pci_alloc_consistent(NULL,
 					       ISO_FRAME_SIZE *
@@ -1214,7 +1216,7 @@
 
 	dec->rc_input_dev = input_dev;
 	if (usb_submit_urb(dec->irq_urb, GFP_KERNEL))
-		printk("%s: usb_submit_urb failed\n",__FUNCTION__);
+		printk("%s: usb_submit_urb failed\n",__func__);
 	/* enable irq pipe */
 	ttusb_dec_send_command(dec,0xb0,sizeof(b),b,NULL,NULL);
 
@@ -1223,7 +1225,7 @@
 
 static void ttusb_dec_init_v_pes(struct ttusb_dec *dec)
 {
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	dec->v_pes[0] = 0x00;
 	dec->v_pes[1] = 0x00;
@@ -1233,7 +1235,7 @@
 
 static int ttusb_dec_init_usb(struct ttusb_dec *dec)
 {
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	mutex_init(&dec->usb_mutex);
 	mutex_init(&dec->iso_mutex);
@@ -1281,11 +1283,11 @@
 	u32 crc32_csum, crc32_check, tmp;
 	const struct firmware *fw_entry = NULL;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	if (request_firmware(&fw_entry, dec->firmware_name, &dec->udev->dev)) {
 		printk(KERN_ERR "%s: Firmware (%s) unavailable.\n",
-		       __FUNCTION__, dec->firmware_name);
+		       __func__, dec->firmware_name);
 		return 1;
 	}
 
@@ -1294,7 +1296,7 @@
 
 	if (firmware_size < 60) {
 		printk("%s: firmware size too small for DSP code (%zu < 60).\n",
-			__FUNCTION__, firmware_size);
+			__func__, firmware_size);
 		release_firmware(fw_entry);
 		return -1;
 	}
@@ -1308,7 +1310,7 @@
 	if (crc32_csum != crc32_check) {
 		printk("%s: crc32 check of DSP code failed (calculated "
 		       "0x%08x != 0x%08x in file), file invalid.\n",
-			__FUNCTION__, crc32_csum, crc32_check);
+			__func__, crc32_csum, crc32_check);
 		release_firmware(fw_entry);
 		return -1;
 	}
@@ -1376,7 +1378,7 @@
 	int result;
 	unsigned int mode, model, version;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	result = ttusb_dec_get_stb_state(dec, &mode, &model, &version);
 
@@ -1415,7 +1417,7 @@
 			default:
 				printk(KERN_ERR "%s: unknown model returned "
 				       "by firmware (%08x) - please report\n",
-				       __FUNCTION__, model);
+				       __func__, model);
 				return -1;
 				break;
 			}
@@ -1434,12 +1436,14 @@
 {
 	int result;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	if ((result = dvb_register_adapter(&dec->adapter,
-					   dec->model_name, THIS_MODULE, &dec->udev->dev)) < 0) {
+					   dec->model_name, THIS_MODULE,
+					   &dec->udev->dev,
+					   adapter_nr)) < 0) {
 		printk("%s: dvb_register_adapter failed: error %d\n",
-		       __FUNCTION__, result);
+		       __func__, result);
 
 		return result;
 	}
@@ -1454,7 +1458,7 @@
 	dec->demux.write_to_decoder = NULL;
 
 	if ((result = dvb_dmx_init(&dec->demux)) < 0) {
-		printk("%s: dvb_dmx_init failed: error %d\n", __FUNCTION__,
+		printk("%s: dvb_dmx_init failed: error %d\n", __func__,
 		       result);
 
 		dvb_unregister_adapter(&dec->adapter);
@@ -1468,7 +1472,7 @@
 
 	if ((result = dvb_dmxdev_init(&dec->dmxdev, &dec->adapter)) < 0) {
 		printk("%s: dvb_dmxdev_init failed: error %d\n",
-		       __FUNCTION__, result);
+		       __func__, result);
 
 		dvb_dmx_release(&dec->demux);
 		dvb_unregister_adapter(&dec->adapter);
@@ -1480,7 +1484,7 @@
 
 	if ((result = dec->demux.dmx.add_frontend(&dec->demux.dmx,
 						  &dec->frontend)) < 0) {
-		printk("%s: dvb_dmx_init failed: error %d\n", __FUNCTION__,
+		printk("%s: dvb_dmx_init failed: error %d\n", __func__,
 		       result);
 
 		dvb_dmxdev_release(&dec->dmxdev);
@@ -1492,7 +1496,7 @@
 
 	if ((result = dec->demux.dmx.connect_frontend(&dec->demux.dmx,
 						      &dec->frontend)) < 0) {
-		printk("%s: dvb_dmx_init failed: error %d\n", __FUNCTION__,
+		printk("%s: dvb_dmx_init failed: error %d\n", __func__,
 		       result);
 
 		dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend);
@@ -1510,7 +1514,7 @@
 
 static void ttusb_dec_exit_dvb(struct ttusb_dec *dec)
 {
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	dvb_net_release(&dec->dvb_net);
 	dec->demux.dmx.close(&dec->demux.dmx);
@@ -1528,7 +1532,7 @@
 static void ttusb_dec_exit_rc(struct ttusb_dec *dec)
 {
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 	/* we have to check whether the irq URB is already submitted.
 	  * As the irq is submitted after the interface is changed,
 	  * this is the best method i figured out.
@@ -1552,7 +1556,7 @@
 {
 	int i;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	dec->iso_stream_count = 0;
 
@@ -1612,12 +1616,12 @@
 	struct usb_device *udev;
 	struct ttusb_dec *dec;
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	udev = interface_to_usbdev(intf);
 
 	if (!(dec = kzalloc(sizeof(struct ttusb_dec), GFP_KERNEL))) {
-		printk("%s: couldn't allocate memory.\n", __FUNCTION__);
+		printk("%s: couldn't allocate memory.\n", __func__);
 		return -ENOMEM;
 	}
 
@@ -1692,7 +1696,7 @@
 
 	usb_set_intfdata(intf, NULL);
 
-	dprintk("%s\n", __FUNCTION__);
+	dprintk("%s\n", __func__);
 
 	if (dec->active) {
 		ttusb_dec_exit_tasklet(dec);
@@ -1749,7 +1753,7 @@
 	int result;
 
 	if ((result = usb_register(&ttusb_dec_driver)) < 0) {
-		printk("%s: initialisation failed: error %d.\n", __FUNCTION__,
+		printk("%s: initialisation failed: error %d.\n", __func__,
 		       result);
 		return result;
 	}
diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
index a6fb1d6..eb5eaec 100644
--- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
+++ b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
@@ -53,7 +53,7 @@
 		return ret;
 
 	if(len != 4) {
-		printk(KERN_ERR "%s: unexpected reply\n", __FUNCTION__);
+		printk(KERN_ERR "%s: unexpected reply\n", __func__);
 		return -EIO;
 	}
 
@@ -70,7 +70,7 @@
 			break;
 		default:
 			pr_info("%s: returned unknown value: %d\n",
-				__FUNCTION__, result[3]);
+				__func__, result[3]);
 			return -EIO;
 	}
 
diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c
index 36c0e36..4e3f83e 100644
--- a/drivers/media/radio/dsbr100.c
+++ b/drivers/media/radio/dsbr100.c
@@ -438,7 +438,9 @@
 	.open		= usb_dsbr100_open,
 	.release	= usb_dsbr100_close,
 	.ioctl		= video_ioctl2,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
+#endif
 	.llseek		= no_llseek,
 };
 
diff --git a/drivers/media/radio/miropcm20-radio.c b/drivers/media/radio/miropcm20-radio.c
index 3ae56fe..09fe6f1 100644
--- a/drivers/media/radio/miropcm20-radio.c
+++ b/drivers/media/radio/miropcm20-radio.c
@@ -221,7 +221,9 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl		= pcm20_ioctl,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
+#endif
 	.llseek         = no_llseek,
 };
 
diff --git a/drivers/media/radio/miropcm20-rds.c b/drivers/media/radio/miropcm20-rds.c
index aed1147..06dfed9 100644
--- a/drivers/media/radio/miropcm20-rds.c
+++ b/drivers/media/radio/miropcm20-rds.c
@@ -19,7 +19,7 @@
 #include "miropcm20-rds-core.h"
 
 static char * text_buffer;
-static int rds_users = 0;
+static int rds_users;
 
 
 static int rds_f_open(struct inode *in, struct file *fi)
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index c69bde3..1ec18ed 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -382,7 +382,9 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl		= video_ioctl2,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
+#endif
 	.llseek         = no_llseek,
 };
 
diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c
index 9b1f7a9..46cdb54 100644
--- a/drivers/media/radio/radio-aztech.c
+++ b/drivers/media/radio/radio-aztech.c
@@ -346,7 +346,9 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl		= video_ioctl2,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
+#endif
 	.llseek         = no_llseek,
 };
 
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index 57b9e3a..b14db53 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -69,13 +69,13 @@
 
 static int io=-1;		/* default to isapnp activation */
 static int radio_nr = -1;
-static int users=0;
-static int curtuner=0;
-static int tunestat=0;
-static int sigstrength=0;
+static int users;
+static int curtuner;
+static int tunestat;
+static int sigstrength;
 static wait_queue_head_t read_queue;
 static struct timer_list readtimer;
-static __u8 rdsin=0,rdsout=0,rdsstat=0;
+static __u8 rdsin, rdsout, rdsstat;
 static unsigned char rdsbuf[RDS_BUFFER];
 static spinlock_t cadet_io_lock;
 
@@ -563,7 +563,9 @@
 	.read		= cadet_read,
 	.ioctl		= video_ioctl2,
 	.poll		= cadet_poll,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
+#endif
 	.llseek         = no_llseek,
 };
 
diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
index 99a3231..de49be9 100644
--- a/drivers/media/radio/radio-gemtek-pci.c
+++ b/drivers/media/radio/radio-gemtek-pci.c
@@ -368,7 +368,9 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl		= video_ioctl2,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
+#endif
 	.llseek         = no_llseek,
 };
 
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index 246422b..81f6aeb 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -397,7 +397,9 @@
 	.open		= video_exclusive_open,
 	.release	= video_exclusive_release,
 	.ioctl		= video_ioctl2,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
+#endif
 	.llseek		= no_llseek
 };
 
diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c
index bc51f4d..bddd3c4 100644
--- a/drivers/media/radio/radio-maestro.c
+++ b/drivers/media/radio/radio-maestro.c
@@ -100,7 +100,9 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl		= video_ioctl2,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
+#endif
 	.llseek         = no_llseek,
 };
 
diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c
index 8e184cf..0133ecf 100644
--- a/drivers/media/radio/radio-maxiradio.c
+++ b/drivers/media/radio/radio-maxiradio.c
@@ -103,7 +103,9 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl          = video_ioctl2,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
+#endif
 	.llseek         = no_llseek,
 };
 
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
index 82aedfc..0708021 100644
--- a/drivers/media/radio/radio-rtrack2.c
+++ b/drivers/media/radio/radio-rtrack2.c
@@ -288,7 +288,9 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl		= video_ioctl2,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
+#endif
 	.llseek         = no_llseek,
 };
 
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index 53e1148..66e052f 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -288,7 +288,9 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl		= video_ioctl2,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
+#endif
 	.llseek         = no_llseek,
 };
 
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index ebc5fbbc..b0ccf7c 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -29,6 +29,8 @@
 #include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
 #define RADIO_VERSION KERNEL_VERSION(0,0,2)
 
+#define AUD_VOL_INDEX 1
+
 static struct v4l2_queryctrl radio_qctrl[] = {
 	{
 		.id            = V4L2_CID_AUDIO_MUTE,
@@ -37,13 +39,14 @@
 		.maximum       = 1,
 		.default_value = 1,
 		.type          = V4L2_CTRL_TYPE_BOOLEAN,
-	},{
+	},
+	[AUD_VOL_INDEX] = {
 		.id            = V4L2_CID_AUDIO_VOLUME,
 		.name          = "Volume",
 		.minimum       = 0,
-		.maximum       = 65535,
-		.step          = 1<<12,
-		.default_value = 0xff,
+		.maximum       = 15,
+		.step          = 1,
+		.default_value = 0,
 		.type          = V4L2_CTRL_TYPE_INTEGER,
 	}
 };
@@ -61,7 +64,7 @@
 struct fmr2_device
 {
 	int port;
-	int curvol; /* 0-65535, if not volume 0 or 65535 */
+	int curvol; /* 0-15 */
 	int mute;
 	int stereo; /* card is producing stereo audio */
 	unsigned long curfreq; /* freq in kHz */
@@ -176,51 +179,35 @@
 /* !!! not tested, in my card this does't work !!! */
 static int fmr2_setvolume(struct fmr2_device *dev)
 {
-	int i,a,n, port = dev->port;
+	int vol[16] = { 0x021, 0x084, 0x090, 0x104,
+			0x110, 0x204, 0x210, 0x402,
+			0x404, 0x408, 0x410, 0x801,
+			0x802, 0x804, 0x808, 0x810 };
+	int i, a, port = dev->port;
+	int n = vol[dev->curvol & 0x0f];
 
-	if (dev->card_type != 11) return 1;
+	if (dev->card_type != 11)
+		return 1;
 
-	switch( (dev->curvol+(1<<11)) >> 12 )
-	{
-	case 0: case 1: n = 0x21; break;
-	case 2: n = 0x84; break;
-	case 3: n = 0x90; break;
-	case 4: n = 0x104; break;
-	case 5: n = 0x110; break;
-	case 6: n = 0x204; break;
-	case 7: n = 0x210; break;
-	case 8: n = 0x402; break;
-	case 9: n = 0x404; break;
-	default:
-	case 10: n = 0x408; break;
-	case 11: n = 0x410; break;
-	case 12: n = 0x801; break;
-	case 13: n = 0x802; break;
-	case 14: n = 0x804; break;
-	case 15: n = 0x808; break;
-	case 16: n = 0x810; break;
-	}
-	for(i=12;--i>=0;)
-	{
+	for (i = 12; --i >= 0; ) {
 		a = ((n >> i) & 1) << 6; /* if (a=0) a= 0; else a= 0x40; */
-		outb(a|4, port);
-		wait(4,port);
-		outb(a|0x24, port);
-		wait(4,port);
-		outb(a|4, port);
-		wait(4,port);
+		outb(a | 4, port);
+		wait(4, port);
+		outb(a | 0x24, port);
+		wait(4, port);
+		outb(a | 4, port);
+		wait(4, port);
 	}
-	for(i=6;--i>=0;)
-	{
+	for (i = 6; --i >= 0; ) {
 		a = ((0x18 >> i) & 1) << 6;
-		outb(a|4, port);
+		outb(a | 4, port);
 		wait(4,port);
-		outb(a|0x24, port);
+		outb(a | 0x24, port);
 		wait(4,port);
 		outb(a|4, port);
 		wait(4,port);
 	}
-	wait(4,port);
+	wait(4, port);
 	outb(0x14, port);
 
 	return 0;
@@ -312,16 +299,10 @@
 					struct v4l2_queryctrl *qc)
 {
 	int i;
-	struct video_device *dev = video_devdata(file);
-	struct fmr2_device *fmr2 = dev->priv;
 
 	for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
-		if ((fmr2->card_type != 11)
-				&& V4L2_CID_AUDIO_VOLUME)
-			radio_qctrl[i].step = 65535;
 		if (qc->id && qc->id == radio_qctrl[i].id) {
-			memcpy(qc, &(radio_qctrl[i]),
-						sizeof(*qc));
+			memcpy(qc, &radio_qctrl[i], sizeof(*qc));
 			return 0;
 		}
 	}
@@ -354,24 +335,13 @@
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
 		fmr2->mute = ctrl->value;
-		if (fmr2->card_type != 11) {
-			if (!fmr2->mute)
-				fmr2->curvol = 65535;
-			else
-				fmr2->curvol = 0;
-		}
 		break;
 	case V4L2_CID_AUDIO_VOLUME:
-		fmr2->curvol = ctrl->value;
-		if (fmr2->card_type != 11) {
-			if (fmr2->curvol) {
-				fmr2->curvol = 65535;
-				fmr2->mute = 0;
-			} else {
-				fmr2->curvol = 0;
-				fmr2->mute = 1;
-			}
-		}
+		if (ctrl->value > radio_qctrl[AUD_VOL_INDEX].maximum)
+			fmr2->curvol = radio_qctrl[AUD_VOL_INDEX].maximum;
+		else
+			fmr2->curvol = ctrl->value;
+
 		break;
 	default:
 		return -EINVAL;
@@ -387,6 +357,7 @@
 	mutex_lock(&lock);
 	if (fmr2->curvol && !fmr2->mute) {
 		fmr2_setvolume(fmr2);
+		/* Set frequency and unmute card */
 		fmr2_setfreq(fmr2);
 	} else
 		fmr2_mute(fmr2->port);
@@ -433,7 +404,9 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl          = video_ioctl2,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
+#endif
 	.llseek         = no_llseek,
 };
 
@@ -487,6 +460,11 @@
 	fmr2_product_info(&fmr2_unit);
 	mutex_unlock(&lock);
 	debug_print((KERN_DEBUG "card_type %d\n", fmr2_unit.card_type));
+
+	/* Only card_type == 11 implements volume */
+	if (fmr2_unit.card_type != 11)
+		radio_qctrl[AUD_VOL_INDEX].maximum = 1;
+
 	return 0;
 }
 
diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c
index 649f14d..77354ca 100644
--- a/drivers/media/radio/radio-si470x.c
+++ b/drivers/media/radio/radio-si470x.c
@@ -85,6 +85,7 @@
  *		Oliver Neukum <oliver@neukum.org>
  *		Version 1.0.7
  *		- usb autosuspend support
+ *             - unplugging fixed
  *
  * ToDo:
  * - add seeking support
@@ -97,10 +98,10 @@
 /* driver definitions */
 #define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>"
 #define DRIVER_NAME "radio-si470x"
-#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 6)
+#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 7)
 #define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver"
 #define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers"
-#define DRIVER_VERSION "1.0.6"
+#define DRIVER_VERSION "1.0.7"
 
 
 /* kernel includes */
@@ -424,6 +425,7 @@
 
 	/* driver management */
 	unsigned int users;
+       unsigned char disconnected;
 
 	/* Silabs internal registers (0..15) */
 	unsigned short registers[RADIO_REGISTER_NUM];
@@ -440,6 +442,12 @@
 
 
 /*
+ * Lock to prevent kfree of data before all users have releases the device.
+ */
+static DEFINE_MUTEX(open_close_lock);
+
+
+/*
  * The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW,
  * 62.5 kHz otherwise.
  * The tuner is able to have a channel spacing of 50, 100 or 200 kHz.
@@ -577,7 +585,7 @@
 		usb_rcvintpipe(radio->usbdev, 1),
 		(void *) &buf, sizeof(buf), &size, usb_timeout);
 	if (size != sizeof(buf))
-		printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_register: "
+	       printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: "
 			"return size differs: %d != %zu\n", size, sizeof(buf));
 	if (retval < 0)
 		printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: "
@@ -875,6 +883,8 @@
 	struct si470x_device *radio = container_of(work, struct si470x_device,
 		work.work);
 
+       if (radio->disconnected)
+	       return;
 	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
 		return;
 
@@ -1001,13 +1011,21 @@
 static int si470x_fops_release(struct inode *inode, struct file *file)
 {
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
-	int retval;
+       int retval = 0;
 
 	if (!radio)
 		return -ENODEV;
 
+       mutex_lock(&open_close_lock);
 	radio->users--;
 	if (radio->users == 0) {
+	       if (radio->disconnected) {
+		       video_unregister_device(radio->videodev);
+		       kfree(radio->buffer);
+		       kfree(radio);
+		       goto done;
+	       }
+
 		/* stop rds reception */
 		cancel_delayed_work_sync(&radio->work);
 
@@ -1016,10 +1034,11 @@
 
 		retval = si470x_stop(radio);
 		usb_autopm_put_interface(radio->intf);
-		return retval;
 	}
 
-	return 0;
+done:
+       mutex_unlock(&open_close_lock);
+       return retval;
 }
 
 
@@ -1032,7 +1051,9 @@
 	.read		= si470x_fops_read,
 	.poll		= si470x_fops_poll,
 	.ioctl		= video_ioctl2,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
+#endif
 	.open		= si470x_fops_open,
 	.release	= si470x_fops_release,
 };
@@ -1157,6 +1178,9 @@
 {
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
 
+       if (radio->disconnected)
+	       return -EIO;
+
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_VOLUME:
 		ctrl->value = radio->registers[SYSCONFIG2] &
@@ -1181,6 +1205,9 @@
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
 	int retval;
 
+       if (radio->disconnected)
+	       return -EIO;
+
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_VOLUME:
 		radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME;
@@ -1243,6 +1270,8 @@
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
 	int retval;
 
+       if (radio->disconnected)
+	       return -EIO;
 	if (tuner->index > 0)
 		return -EINVAL;
 
@@ -1299,6 +1328,8 @@
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
 	int retval;
 
+       if (radio->disconnected)
+	       return -EIO;
 	if (tuner->index > 0)
 		return -EINVAL;
 
@@ -1324,6 +1355,9 @@
 {
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
 
+       if (radio->disconnected)
+	       return -EIO;
+
 	freq->type = V4L2_TUNER_RADIO;
 	freq->frequency = si470x_get_freq(radio);
 
@@ -1340,6 +1374,8 @@
 	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
 	int retval;
 
+       if (radio->disconnected)
+	       return -EIO;
 	if (freq->type != V4L2_TUNER_RADIO)
 		return -EINVAL;
 
@@ -1510,11 +1546,16 @@
 {
 	struct si470x_device *radio = usb_get_intfdata(intf);
 
+       mutex_lock(&open_close_lock);
+       radio->disconnected = 1;
 	cancel_delayed_work_sync(&radio->work);
 	usb_set_intfdata(intf, NULL);
-	video_unregister_device(radio->videodev);
-	kfree(radio->buffer);
-	kfree(radio);
+       if (radio->users == 0) {
+	       video_unregister_device(radio->videodev);
+	       kfree(radio->buffer);
+	       kfree(radio);
+       }
+       mutex_unlock(&open_close_lock);
 }
 
 
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c
index 535ffe8..acc3208 100644
--- a/drivers/media/radio/radio-terratec.c
+++ b/drivers/media/radio/radio-terratec.c
@@ -360,7 +360,9 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl		= video_ioctl2,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
+#endif
 	.llseek         = no_llseek,
 };
 
diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c
index c11981f..4ebdfbad 100644
--- a/drivers/media/radio/radio-trust.c
+++ b/drivers/media/radio/radio-trust.c
@@ -340,7 +340,9 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl		= video_ioctl2,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
+#endif
 	.llseek         = no_llseek,
 };
 
diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c
index 1366326..18f2abd 100644
--- a/drivers/media/radio/radio-typhoon.c
+++ b/drivers/media/radio/radio-typhoon.c
@@ -35,6 +35,7 @@
 #include <linux/init.h>		/* Initdata                       */
 #include <linux/ioport.h>	/* request_region		  */
 #include <linux/proc_fs.h>	/* radio card status report	  */
+#include <linux/seq_file.h>
 #include <asm/io.h>		/* outb, outb_p                   */
 #include <asm/uaccess.h>	/* copy to/from user              */
 #include <linux/videodev2.h>	/* kernel radio structs           */
@@ -93,9 +94,6 @@
 static void typhoon_mute(struct typhoon_device *dev);
 static void typhoon_unmute(struct typhoon_device *dev);
 static int typhoon_setvol(struct typhoon_device *dev, int vol);
-#ifdef CONFIG_RADIO_TYPHOON_PROC_FS
-static int typhoon_get_info(char *buf, char **start, off_t offset, int len);
-#endif
 
 static void typhoon_setvol_generic(struct typhoon_device *dev, int vol)
 {
@@ -340,7 +338,9 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl		= video_ioctl2,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
+#endif
 	.llseek         = no_llseek,
 };
 
@@ -366,30 +366,39 @@
 
 #ifdef CONFIG_RADIO_TYPHOON_PROC_FS
 
-static int typhoon_get_info(char *buf, char **start, off_t offset, int len)
+static int typhoon_proc_show(struct seq_file *m, void *v)
 {
-	char *out = buf;
-
 	#ifdef MODULE
 	    #define MODULEPROCSTRING "Driver loaded as a module"
 	#else
 	    #define MODULEPROCSTRING "Driver compiled into kernel"
 	#endif
 
-	/* output must be kept under PAGE_SIZE */
-	out += sprintf(out, BANNER);
-	out += sprintf(out, "Load type: " MODULEPROCSTRING "\n\n");
-	out += sprintf(out, "frequency = %lu kHz\n",
+	seq_puts(m, BANNER);
+	seq_puts(m, "Load type: " MODULEPROCSTRING "\n\n");
+	seq_printf(m, "frequency = %lu kHz\n",
 		typhoon_unit.curfreq >> 4);
-	out += sprintf(out, "volume = %d\n", typhoon_unit.curvol);
-	out += sprintf(out, "mute = %s\n", typhoon_unit.muted ?
+	seq_printf(m, "volume = %d\n", typhoon_unit.curvol);
+	seq_printf(m, "mute = %s\n", typhoon_unit.muted ?
 		"on" : "off");
-	out += sprintf(out, "iobase = 0x%x\n", typhoon_unit.iobase);
-	out += sprintf(out, "mute frequency = %lu kHz\n",
+	seq_printf(m, "iobase = 0x%x\n", typhoon_unit.iobase);
+	seq_printf(m, "mute frequency = %lu kHz\n",
 		typhoon_unit.mutefreq >> 4);
-	return out - buf;
+	return 0;
 }
 
+static int typhoon_proc_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, typhoon_proc_show, NULL);
+}
+
+static const struct file_operations typhoon_proc_fops = {
+	.owner		= THIS_MODULE,
+	.open		= typhoon_proc_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
 #endif /* CONFIG_RADIO_TYPHOON_PROC_FS */
 
 MODULE_AUTHOR("Dr. Henrik Seidel");
@@ -404,7 +413,7 @@
 module_param(radio_nr, int, 0);
 
 #ifdef MODULE
-static unsigned long mutefreq = 0;
+static unsigned long mutefreq;
 module_param(mutefreq, ulong, 0);
 MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)");
 #endif
@@ -450,8 +459,7 @@
 	typhoon_mute(&typhoon_unit);
 
 #ifdef CONFIG_RADIO_TYPHOON_PROC_FS
-	if (!create_proc_info_entry("driver/radio-typhoon", 0, NULL,
-				    typhoon_get_info))
+	if (!proc_create("driver/radio-typhoon", 0, NULL, &typhoon_proc_fops))
 		printk(KERN_ERR "radio-typhoon: registering /proc/driver/radio-typhoon failed\n");
 #endif
 
diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c
index 203f437..43773c5 100644
--- a/drivers/media/radio/radio-zoltrix.c
+++ b/drivers/media/radio/radio-zoltrix.c
@@ -401,7 +401,9 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl		= video_ioctl2,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
+#endif
 	.llseek         = no_llseek,
 };
 
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 1832966..fe9a4cc 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -270,6 +270,15 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called saa7115.
 
+config VIDEO_SAA717X
+	tristate "Philips SAA7171/3/4 audio/video decoders"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for the Philips SAA7171/3/4 audio/video decoders.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called saa717x.
+
 config VIDEO_SAA7191
 	tristate "Philips SAA7191 video decoder"
 	depends on VIDEO_V4L1 && I2C
@@ -689,6 +698,8 @@
 
 source "drivers/media/video/cx23885/Kconfig"
 
+source "drivers/media/video/au0828/Kconfig"
+
 source "drivers/media/video/ivtv/Kconfig"
 
 config VIDEO_M32R_AR
@@ -836,4 +847,49 @@
 
 endif # V4L_USB_DRIVERS
 
+config SOC_CAMERA
+	tristate "SoC camera support"
+	depends on VIDEO_V4L2
+	select VIDEOBUF_DMA_SG
+	help
+	  SoC Camera is a common API to several cameras, not connecting
+	  over a bus like PCI or USB. For example some i2c camera connected
+	  directly to the data bus of an SoC.
+
+config SOC_CAMERA_MT9M001
+	tristate "mt9m001 support"
+	depends on SOC_CAMERA
+	select GPIO_PCA953X if MT9M001_PCA9536_SWITCH
+	help
+	  This driver supports MT9M001 cameras from Micron, monochrome
+	  and colour models.
+
+config MT9M001_PCA9536_SWITCH
+	bool "pca9536 datawidth switch for mt9m001"
+	depends on SOC_CAMERA_MT9M001 && GENERIC_GPIO
+	help
+	  Select this if your MT9M001 camera uses a PCA9536 I2C GPIO
+	  extender to switch between 8 and 10 bit datawidth modes
+
+config SOC_CAMERA_MT9V022
+	tristate "mt9v022 support"
+	depends on SOC_CAMERA
+	select GPIO_PCA953X if MT9V022_PCA9536_SWITCH
+	help
+	  This driver supports MT9V022 cameras from Micron
+
+config MT9V022_PCA9536_SWITCH
+	bool "pca9536 datawidth switch for mt9v022"
+	depends on SOC_CAMERA_MT9V022 && GENERIC_GPIO
+	help
+	  Select this if your MT9V022 camera uses a PCA9536 I2C GPIO
+	  extender to switch between 8 and 10 bit datawidth modes
+
+config VIDEO_PXA27x
+	tristate "PXA27x Quick Capture Interface driver"
+	depends on VIDEO_DEV && PXA27x
+	select SOC_CAMERA
+	---help---
+	  This is a v4l2 driver for the PXA27x Quick Capture Interface
+
 endif # VIDEO_CAPTURE_DRIVERS
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 3f209b3..be14227 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -4,7 +4,7 @@
 
 zr36067-objs	:=	zoran_procfs.o zoran_device.o \
 			zoran_driver.o zoran_card.o
-tuner-objs	:=	tuner-core.o tuner-types.o
+tuner-objs	:=	tuner-core.o
 
 msp3400-objs	:=	msp3400-driver.o msp3400-kthreads.o
 
@@ -38,6 +38,7 @@
 obj-$(CONFIG_VIDEO_SAA7111) += saa7111.o
 obj-$(CONFIG_VIDEO_SAA7114) += saa7114.o
 obj-$(CONFIG_VIDEO_SAA711X) += saa7115.o
+obj-$(CONFIG_VIDEO_SAA717X) += saa717x.o
 obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o
 obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o
 obj-$(CONFIG_VIDEO_SAA7191) += saa7191.o
@@ -87,6 +88,8 @@
 
 obj-$(CONFIG_TUNER_XC2028) += tuner-xc2028.o
 obj-$(CONFIG_TUNER_SIMPLE) += tuner-simple.o
+# tuner-types will be merged into tuner-simple, in the future
+obj-$(CONFIG_TUNER_SIMPLE) += tuner-types.o
 obj-$(CONFIG_TUNER_MT20XX) += mt20xx.o
 obj-$(CONFIG_TUNER_TDA8290) += tda8290.o
 obj-$(CONFIG_TUNER_TEA5767) += tea5767.o
@@ -135,5 +138,12 @@
 obj-$(CONFIG_VIDEO_VIVI) += vivi.o
 obj-$(CONFIG_VIDEO_CX23885) += cx23885/
 
+obj-$(CONFIG_VIDEO_PXA27x)	+= pxa_camera.o
+obj-$(CONFIG_SOC_CAMERA)	+= soc_camera.o
+obj-$(CONFIG_SOC_CAMERA_MT9M001)	+= mt9m001.o
+obj-$(CONFIG_SOC_CAMERA_MT9V022)	+= mt9v022.o
+
+obj-$(CONFIG_VIDEO_AU0828) += au0828/
+
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
 EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c
index fea2e72..f794f2d 100644
--- a/drivers/media/video/adv7170.c
+++ b/drivers/media/video/adv7170.c
@@ -56,7 +56,7 @@
 #define I2C_NAME(x) (x)->name
 
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c
index 10d4d89..8ee07a6 100644
--- a/drivers/media/video/adv7175.c
+++ b/drivers/media/video/adv7175.c
@@ -52,7 +52,7 @@
 #define I2C_NAME(s) (s)->name
 
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c
index c94a4d0..8c7d195 100644
--- a/drivers/media/video/arv.c
+++ b/drivers/media/video/arv.c
@@ -125,8 +125,8 @@
 /* default frequency */
 #define DEFAULT_FREQ	50	/* 50 or 75 (MHz) is available as BCLK */
 static int freq = DEFAULT_FREQ;	/* BCLK: available 50 or 70 (MHz) */
-static int vga = 0;		/* default mode(0:QVGA mode, other:VGA mode) */
-static int vga_interlace = 0;	/* 0 is normal mode for, else interlace mode */
+static int vga;			/* default mode(0:QVGA mode, other:VGA mode) */
+static int vga_interlace;	/* 0 is normal mode for, else interlace mode */
 module_param(freq, int, 0);
 module_param(vga, int, 0);
 module_param(vga_interlace, int, 0);
@@ -747,7 +747,9 @@
 	.release	= video_exclusive_release,
 	.read		= ar_read,
 	.ioctl		= ar_ioctl,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
+#endif
 	.llseek		= no_llseek,
 };
 
diff --git a/drivers/media/video/au0828/Kconfig b/drivers/media/video/au0828/Kconfig
new file mode 100644
index 0000000..c97c4bd
--- /dev/null
+++ b/drivers/media/video/au0828/Kconfig
@@ -0,0 +1,12 @@
+
+config VIDEO_AU0828
+	tristate "Auvitek AU0828 support"
+	depends on VIDEO_DEV && I2C && INPUT
+	select I2C_ALGOBIT
+	select DVB_AU8522 if !DVB_FE_CUSTOMIZE
+	select DVB_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
+	---help---
+	  This is a video4linux driver for Auvitek's USB device.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called au0828
diff --git a/drivers/media/video/au0828/Makefile b/drivers/media/video/au0828/Makefile
new file mode 100644
index 0000000..9f4f572
--- /dev/null
+++ b/drivers/media/video/au0828/Makefile
@@ -0,0 +1,9 @@
+au0828-objs	:= au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o
+
+obj-$(CONFIG_VIDEO_AU0828) += au0828.o
+
+EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+
+EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/video/au0828/au0828-cards.c b/drivers/media/video/au0828/au0828-cards.c
new file mode 100644
index 0000000..8ca91f8
--- /dev/null
+++ b/drivers/media/video/au0828/au0828-cards.c
@@ -0,0 +1,182 @@
+/*
+ *  Driver for the Auvitek USB bridge
+ *
+ *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "au0828.h"
+#include "au0828-cards.h"
+
+struct au0828_board au0828_boards[] = {
+	[AU0828_BOARD_UNKNOWN] = {
+		.name	= "Unknown board",
+	},
+	[AU0828_BOARD_HAUPPAUGE_HVR850] = {
+		.name	= "Hauppauge HVR850",
+	},
+	[AU0828_BOARD_HAUPPAUGE_HVR950Q] = {
+		.name	= "Hauppauge HVR950Q",
+	},
+	[AU0828_BOARD_DVICO_FUSIONHDTV7] = {
+		.name	= "DViCO FusionHDTV USB",
+	},
+};
+const unsigned int au0828_bcount = ARRAY_SIZE(au0828_boards);
+
+/* Tuner callback function for au0828 boards. Currently only needed
+ * for HVR1500Q, which has an xc5000 tuner.
+ */
+int au0828_tuner_callback(void *priv, int command, int arg)
+{
+	struct au0828_dev *dev = priv;
+
+	dprintk(1, "%s()\n", __func__);
+
+	switch (dev->board) {
+	case AU0828_BOARD_HAUPPAUGE_HVR850:
+	case AU0828_BOARD_HAUPPAUGE_HVR950Q:
+	case AU0828_BOARD_DVICO_FUSIONHDTV7:
+		if (command == 0) {
+			/* Tuner Reset Command from xc5000 */
+			/* Drive the tuner into reset and out */
+			au0828_clear(dev, REG_001, 2);
+			mdelay(200);
+			au0828_set(dev, REG_001, 2);
+			mdelay(50);
+			return 0;
+		} else {
+			printk(KERN_ERR
+				"%s(): Unknown command.\n", __func__);
+			return -EINVAL;
+		}
+		break;
+	}
+
+	return 0; /* Should never be here */
+}
+
+static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data)
+{
+	struct tveeprom tv;
+
+	tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data);
+
+	/* Make sure we support the board model */
+	switch (tv.model) {
+	case 72001: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and basic analog video */
+	case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and basic analog video */
+		break;
+	default:
+		printk(KERN_WARNING "%s: warning: "
+		       "unknown hauppauge model #%d\n", __func__, tv.model);
+		break;
+	}
+
+	printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n",
+	       __func__, tv.model);
+}
+
+void au0828_card_setup(struct au0828_dev *dev)
+{
+	static u8 eeprom[256];
+
+	dprintk(1, "%s()\n", __func__);
+
+	if (dev->i2c_rc == 0) {
+		dev->i2c_client.addr = 0xa0 >> 1;
+		tveeprom_read(&dev->i2c_client, eeprom, sizeof(eeprom));
+	}
+
+	switch (dev->board) {
+	case AU0828_BOARD_HAUPPAUGE_HVR850:
+	case AU0828_BOARD_HAUPPAUGE_HVR950Q:
+		if (dev->i2c_rc == 0)
+			hauppauge_eeprom(dev, eeprom+0xa0);
+		break;
+	}
+}
+
+/*
+ * The bridge has between 8 and 12 gpios.
+ * Regs 1 and 0 deal with output enables.
+ * Regs 3 and 2 deal with direction.
+ */
+void au0828_gpio_setup(struct au0828_dev *dev)
+{
+	dprintk(1, "%s()\n", __func__);
+
+	switch (dev->board) {
+	case AU0828_BOARD_HAUPPAUGE_HVR850:
+	case AU0828_BOARD_HAUPPAUGE_HVR950Q:
+		/* GPIO's
+		 * 4 - CS5340
+		 * 5 - AU8522 Demodulator
+		 * 6 - eeprom W/P
+		 * 9 - XC5000 Tuner
+		 */
+
+		/* Into reset */
+		au0828_write(dev, REG_003, 0x02);
+		au0828_write(dev, REG_002, 0x88 | 0x20);
+		au0828_write(dev, REG_001, 0x0);
+		au0828_write(dev, REG_000, 0x0);
+		msleep(100);
+
+		/* Out of reset */
+		au0828_write(dev, REG_003, 0x02);
+		au0828_write(dev, REG_001, 0x02);
+		au0828_write(dev, REG_002, 0x88 | 0x20);
+		au0828_write(dev, REG_000, 0x88 | 0x20 | 0x40);
+		msleep(250);
+		break;
+	case AU0828_BOARD_DVICO_FUSIONHDTV7:
+		/* GPIO's
+		 * 6 - ?
+		 * 8 - AU8522 Demodulator
+		 * 9 - XC5000 Tuner
+		 */
+
+		/* Into reset */
+		au0828_write(dev, REG_003, 0x02);
+		au0828_write(dev, REG_002, 0xa0);
+		au0828_write(dev, REG_001, 0x0);
+		au0828_write(dev, REG_000, 0x0);
+		msleep(100);
+
+		/* Out of reset */
+		au0828_write(dev, REG_003, 0x02);
+		au0828_write(dev, REG_002, 0xa0);
+		au0828_write(dev, REG_001, 0x02);
+		au0828_write(dev, REG_000, 0xa0);
+		msleep(250);
+		break;
+	}
+}
+
+/* table of devices that work with this driver */
+struct usb_device_id au0828_usb_id_table [] = {
+	{ USB_DEVICE(0x2040, 0x7200),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+	{ USB_DEVICE(0x2040, 0x7240),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR850 },
+	{ USB_DEVICE(0x0fe9, 0xd620),
+		.driver_info = AU0828_BOARD_DVICO_FUSIONHDTV7 },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(usb, au0828_usb_id_table);
diff --git a/drivers/media/video/au0828/au0828-cards.h b/drivers/media/video/au0828/au0828-cards.h
new file mode 100644
index 0000000..e26f54a
--- /dev/null
+++ b/drivers/media/video/au0828/au0828-cards.h
@@ -0,0 +1,25 @@
+/*
+ *  Driver for the Auvitek USB bridge
+ *
+ *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define AU0828_BOARD_UNKNOWN		0
+#define AU0828_BOARD_HAUPPAUGE_HVR950Q	1
+#define AU0828_BOARD_HAUPPAUGE_HVR850 	2
+#define AU0828_BOARD_DVICO_FUSIONHDTV7	3
diff --git a/drivers/media/video/au0828/au0828-core.c b/drivers/media/video/au0828/au0828-core.c
new file mode 100644
index 0000000..e65d564
--- /dev/null
+++ b/drivers/media/video/au0828/au0828-core.c
@@ -0,0 +1,270 @@
+/*
+ *  Driver for the Auvitek USB bridge
+ *
+ *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/mutex.h>
+
+#include "au0828.h"
+
+/*
+ * 1 = General debug messages
+ * 2 = USB handling
+ * 4 = I2C related
+ * 8 = Bridge related
+ */
+unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages");
+
+unsigned int usb_debug;
+module_param(usb_debug, int, 0644);
+MODULE_PARM_DESC(usb_debug, "enable usb debug messages");
+
+unsigned int bridge_debug;
+module_param(bridge_debug, int, 0644);
+MODULE_PARM_DESC(bridge_debug, "enable bridge debug messages");
+
+#define _AU0828_BULKPIPE 0x03
+#define _BULKPIPESIZE 0xffff
+
+static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
+	u16 index, unsigned char *cp, u16 size);
+static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
+	u16 index, unsigned char *cp, u16 size);
+
+/* USB Direction */
+#define CMD_REQUEST_IN		0x00
+#define CMD_REQUEST_OUT		0x01
+
+u32 au0828_readreg(struct au0828_dev *dev, u16 reg)
+{
+	recv_control_msg(dev, CMD_REQUEST_IN, 0, reg, dev->ctrlmsg, 1);
+	dprintk(8, "%s(0x%x) = 0x%x\n", __func__, reg, dev->ctrlmsg[0]);
+	return dev->ctrlmsg[0];
+}
+
+u32 au0828_writereg(struct au0828_dev *dev, u16 reg, u32 val)
+{
+	dprintk(8, "%s(0x%x, 0x%x)\n", __func__, reg, val);
+	return send_control_msg(dev, CMD_REQUEST_OUT, val, reg,
+				dev->ctrlmsg, 0);
+}
+
+static void cmd_msg_dump(struct au0828_dev *dev)
+{
+	int i;
+
+	for (i = 0; i < sizeof(dev->ctrlmsg); i += 16)
+		dprintk(2, "%s() %02x %02x %02x %02x %02x %02x %02x %02x "
+				"%02x %02x %02x %02x %02x %02x %02x %02x\n",
+			__func__,
+			dev->ctrlmsg[i+0], dev->ctrlmsg[i+1],
+			dev->ctrlmsg[i+2], dev->ctrlmsg[i+3],
+			dev->ctrlmsg[i+4], dev->ctrlmsg[i+5],
+			dev->ctrlmsg[i+6], dev->ctrlmsg[i+7],
+			dev->ctrlmsg[i+8], dev->ctrlmsg[i+9],
+			dev->ctrlmsg[i+10], dev->ctrlmsg[i+11],
+			dev->ctrlmsg[i+12], dev->ctrlmsg[i+13],
+			dev->ctrlmsg[i+14], dev->ctrlmsg[i+15]);
+}
+
+static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
+	u16 index, unsigned char *cp, u16 size)
+{
+	int status = -ENODEV;
+	mutex_lock(&dev->mutex);
+	if (dev->usbdev) {
+
+		/* cp must be memory that has been allocated by kmalloc */
+		status = usb_control_msg(dev->usbdev,
+				usb_sndctrlpipe(dev->usbdev, 0),
+				request,
+				USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+				value, index,
+				cp, size, 1000);
+
+		status = min(status, 0);
+
+		if (status < 0) {
+			printk(KERN_ERR "%s() Failed sending control message, error %d.\n",
+				__func__, status);
+		}
+
+	}
+	mutex_unlock(&dev->mutex);
+	return status;
+}
+
+static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
+	u16 index, unsigned char *cp, u16 size)
+{
+	int status = -ENODEV;
+	mutex_lock(&dev->mutex);
+	if (dev->usbdev) {
+
+		memset(dev->ctrlmsg, 0, sizeof(dev->ctrlmsg));
+
+		/* cp must be memory that has been allocated by kmalloc */
+		status = usb_control_msg(dev->usbdev,
+				usb_rcvctrlpipe(dev->usbdev, 0),
+				request,
+				USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+				value, index,
+				cp, size, 1000);
+
+		status = min(status, 0);
+
+		if (status < 0) {
+			printk(KERN_ERR "%s() Failed receiving control message, error %d.\n",
+				__func__, status);
+		} else
+			cmd_msg_dump(dev);
+	}
+	mutex_unlock(&dev->mutex);
+	return status;
+}
+
+static void au0828_usb_disconnect(struct usb_interface *interface)
+{
+	struct au0828_dev *dev = usb_get_intfdata(interface);
+
+	dprintk(1, "%s()\n", __func__);
+
+	/* Digital TV */
+	au0828_dvb_unregister(dev);
+
+	/* I2C */
+	au0828_i2c_unregister(dev);
+
+	usb_set_intfdata(interface, NULL);
+
+	mutex_lock(&dev->mutex);
+	dev->usbdev = NULL;
+	mutex_unlock(&dev->mutex);
+
+	kfree(dev);
+
+}
+
+static int au0828_usb_probe(struct usb_interface *interface,
+	const struct usb_device_id *id)
+{
+	int ifnum;
+	struct au0828_dev *dev;
+	struct usb_device *usbdev = interface_to_usbdev(interface);
+
+	ifnum = interface->altsetting->desc.bInterfaceNumber;
+
+	if (ifnum != 0)
+		return -ENODEV;
+
+	dprintk(1, "%s() vendor id 0x%x device id 0x%x ifnum:%d\n", __func__,
+		le16_to_cpu(usbdev->descriptor.idVendor),
+		le16_to_cpu(usbdev->descriptor.idProduct),
+		ifnum);
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (dev == NULL) {
+		printk(KERN_ERR "%s() Unable to allocate memory\n", __func__);
+		return -ENOMEM;
+	}
+
+	mutex_init(&dev->mutex);
+	mutex_init(&dev->dvb.lock);
+	dev->usbdev = usbdev;
+	dev->board = id->driver_info;
+
+	usb_set_intfdata(interface, dev);
+
+	/* Power Up the bridge */
+	au0828_write(dev, REG_600, 1 << 4);
+
+	/* Bring up the GPIO's and supporting devices */
+	au0828_gpio_setup(dev);
+
+	/* I2C */
+	au0828_i2c_register(dev);
+
+	/* Setup */
+	au0828_card_setup(dev);
+
+	/* Digital TV */
+	au0828_dvb_register(dev);
+
+	printk(KERN_INFO "Registered device AU0828 [%s]\n",
+		au0828_boards[dev->board].name == NULL ? "Unset" :
+		au0828_boards[dev->board].name);
+
+	return 0;
+}
+
+static struct usb_driver au0828_usb_driver = {
+	.name		= DRIVER_NAME,
+	.probe		= au0828_usb_probe,
+	.disconnect	= au0828_usb_disconnect,
+	.id_table	= au0828_usb_id_table,
+};
+
+static int __init au0828_init(void)
+{
+	int ret;
+
+	if (debug)
+		printk(KERN_INFO "%s() Debugging is enabled\n", __func__);
+
+	if (usb_debug) {
+		printk(KERN_INFO "%s() USB Debugging is enabled\n", __func__);
+		debug |= 2;
+	}
+
+	if (i2c_debug) {
+		printk(KERN_INFO "%s() I2C Debugging is enabled\n", __func__);
+		debug |= 4;
+	}
+
+	if (bridge_debug) {
+		printk(KERN_INFO "%s() Bridge Debugging is enabled\n",
+		       __func__);
+		debug |= 8;
+	}
+
+	printk(KERN_INFO "au0828 driver loaded\n");
+
+	ret = usb_register(&au0828_usb_driver);
+	if (ret)
+		printk(KERN_ERR "usb_register failed, error = %d\n", ret);
+
+	return ret;
+}
+
+static void __exit au0828_exit(void)
+{
+	usb_deregister(&au0828_usb_driver);
+}
+
+module_init(au0828_init);
+module_exit(au0828_exit);
+
+MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products");
+MODULE_AUTHOR("Steven Toth <stoth@hauppauge.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/au0828/au0828-dvb.c b/drivers/media/video/au0828/au0828-dvb.c
new file mode 100644
index 0000000..85d0ae9
--- /dev/null
+++ b/drivers/media/video/au0828/au0828-dvb.c
@@ -0,0 +1,373 @@
+/*
+ *  Driver for the Auvitek USB bridge
+ *
+ *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/suspend.h>
+#include <media/v4l2-common.h>
+
+#include "au0828.h"
+#include "au8522.h"
+#include "xc5000.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define _AU0828_BULKPIPE 0x83
+#define _BULKPIPESIZE 0xe522
+
+static struct au8522_config hauppauge_hvr950q_config = {
+	.demod_address = 0x8e >> 1,
+	.status_mode   = AU8522_DEMODLOCKING,
+};
+
+static struct xc5000_config hauppauge_hvr950q_tunerconfig = {
+	.i2c_address      = 0x61,
+	.if_khz           = 6000,
+	.tuner_callback   = au0828_tuner_callback
+};
+
+/*-------------------------------------------------------------------*/
+static void urb_completion(struct urb *purb)
+{
+	u8 *ptr;
+	struct au0828_dev *dev = purb->context;
+	int ptype = usb_pipetype(purb->pipe);
+
+	dprintk(2, "%s()\n", __func__);
+
+	if (!dev)
+		return;
+
+	if (dev->urb_streaming == 0)
+		return;
+
+	if (ptype != PIPE_BULK) {
+		printk(KERN_ERR "%s() Unsupported URB type %d\n",
+		       __func__, ptype);
+		return;
+	}
+
+	ptr = (u8 *)purb->transfer_buffer;
+
+	/* Feed the transport payload into the kernel demux */
+	dvb_dmx_swfilter_packets(&dev->dvb.demux,
+		purb->transfer_buffer, purb->actual_length / 188);
+
+	/* Clean the buffer before we requeue */
+	memset(purb->transfer_buffer, 0, URB_BUFSIZE);
+
+	/* Requeue URB */
+	usb_submit_urb(purb, GFP_ATOMIC);
+}
+
+static int stop_urb_transfer(struct au0828_dev *dev)
+{
+	int i;
+
+	dprintk(2, "%s()\n", __func__);
+
+	for (i = 0; i < URB_COUNT; i++) {
+		usb_kill_urb(dev->urbs[i]);
+		kfree(dev->urbs[i]->transfer_buffer);
+		usb_free_urb(dev->urbs[i]);
+	}
+
+	dev->urb_streaming = 0;
+
+	return 0;
+}
+
+static int start_urb_transfer(struct au0828_dev *dev)
+{
+	struct urb *purb;
+	int i, ret = -ENOMEM;
+
+	dprintk(2, "%s()\n", __func__);
+
+	if (dev->urb_streaming) {
+		dprintk(2, "%s: iso xfer already running!\n", __func__);
+		return 0;
+	}
+
+	for (i = 0; i < URB_COUNT; i++) {
+
+		dev->urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
+		if (!dev->urbs[i])
+			goto err;
+
+		purb = dev->urbs[i];
+
+		purb->transfer_buffer = kzalloc(URB_BUFSIZE, GFP_KERNEL);
+		if (!purb->transfer_buffer) {
+			usb_free_urb(purb);
+			dev->urbs[i] = 0;
+			goto err;
+		}
+
+		purb->status = -EINPROGRESS;
+		usb_fill_bulk_urb(purb,
+				  dev->usbdev,
+				  usb_rcvbulkpipe(dev->usbdev, _AU0828_BULKPIPE),
+				  purb->transfer_buffer,
+				  URB_BUFSIZE,
+				  urb_completion,
+				  dev);
+
+	}
+
+	for (i = 0; i < URB_COUNT; i++) {
+		ret = usb_submit_urb(dev->urbs[i], GFP_ATOMIC);
+		if (ret != 0) {
+			stop_urb_transfer(dev);
+			printk(KERN_ERR "%s: failed urb submission, "
+			       "err = %d\n", __func__, ret);
+			return ret;
+		}
+	}
+
+	dev->urb_streaming = 1;
+	ret = 0;
+
+err:
+	return ret;
+}
+
+static int au0828_dvb_start_feed(struct dvb_demux_feed *feed)
+{
+	struct dvb_demux *demux = feed->demux;
+	struct au0828_dev *dev = (struct au0828_dev *) demux->priv;
+	struct au0828_dvb *dvb = &dev->dvb;
+	int ret = 0;
+
+	dprintk(1, "%s()\n", __func__);
+
+	if (!demux->dmx.frontend)
+		return -EINVAL;
+
+	if (dvb) {
+		mutex_lock(&dvb->lock);
+		if (dvb->feeding++ == 0) {
+			/* Start transport */
+			au0828_write(dev, 0x608, 0x90);
+			au0828_write(dev, 0x609, 0x72);
+			au0828_write(dev, 0x60a, 0x71);
+			au0828_write(dev, 0x60b, 0x01);
+			ret = start_urb_transfer(dev);
+		}
+		mutex_unlock(&dvb->lock);
+	}
+
+	return ret;
+}
+
+static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed)
+{
+	struct dvb_demux *demux = feed->demux;
+	struct au0828_dev *dev = (struct au0828_dev *) demux->priv;
+	struct au0828_dvb *dvb = &dev->dvb;
+	int ret = 0;
+
+	dprintk(1, "%s()\n", __func__);
+
+	if (dvb) {
+		mutex_lock(&dvb->lock);
+		if (--dvb->feeding == 0) {
+			/* Stop transport */
+			au0828_write(dev, 0x608, 0x00);
+			au0828_write(dev, 0x609, 0x00);
+			au0828_write(dev, 0x60a, 0x00);
+			au0828_write(dev, 0x60b, 0x00);
+			ret = stop_urb_transfer(dev);
+		}
+		mutex_unlock(&dvb->lock);
+	}
+
+	return ret;
+}
+
+int dvb_register(struct au0828_dev *dev)
+{
+	struct au0828_dvb *dvb = &dev->dvb;
+	int result;
+
+	dprintk(1, "%s()\n", __func__);
+
+	/* register adapter */
+	result = dvb_register_adapter(&dvb->adapter, DRIVER_NAME, THIS_MODULE,
+				      &dev->usbdev->dev, adapter_nr);
+	if (result < 0) {
+		printk(KERN_ERR "%s: dvb_register_adapter failed "
+		       "(errno = %d)\n", DRIVER_NAME, result);
+		goto fail_adapter;
+	}
+	dvb->adapter.priv = dev;
+
+	/* register frontend */
+	result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
+	if (result < 0) {
+		printk(KERN_ERR "%s: dvb_register_frontend failed "
+		       "(errno = %d)\n", DRIVER_NAME, result);
+		goto fail_frontend;
+	}
+
+	/* register demux stuff */
+	dvb->demux.dmx.capabilities =
+		DMX_TS_FILTERING | DMX_SECTION_FILTERING |
+		DMX_MEMORY_BASED_FILTERING;
+	dvb->demux.priv       = dev;
+	dvb->demux.filternum  = 256;
+	dvb->demux.feednum    = 256;
+	dvb->demux.start_feed = au0828_dvb_start_feed;
+	dvb->demux.stop_feed  = au0828_dvb_stop_feed;
+	result = dvb_dmx_init(&dvb->demux);
+	if (result < 0) {
+		printk(KERN_ERR "%s: dvb_dmx_init failed (errno = %d)\n",
+		       DRIVER_NAME, result);
+		goto fail_dmx;
+	}
+
+	dvb->dmxdev.filternum    = 256;
+	dvb->dmxdev.demux        = &dvb->demux.dmx;
+	dvb->dmxdev.capabilities = 0;
+	result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
+	if (result < 0) {
+		printk(KERN_ERR "%s: dvb_dmxdev_init failed (errno = %d)\n",
+		       DRIVER_NAME, result);
+		goto fail_dmxdev;
+	}
+
+	dvb->fe_hw.source = DMX_FRONTEND_0;
+	result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+	if (result < 0) {
+		printk(KERN_ERR "%s: add_frontend failed "
+		       "(DMX_FRONTEND_0, errno = %d)\n", DRIVER_NAME, result);
+		goto fail_fe_hw;
+	}
+
+	dvb->fe_mem.source = DMX_MEMORY_FE;
+	result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+	if (result < 0) {
+		printk(KERN_ERR "%s: add_frontend failed "
+		       "(DMX_MEMORY_FE, errno = %d)\n", DRIVER_NAME, result);
+		goto fail_fe_mem;
+	}
+
+	result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+	if (result < 0) {
+		printk(KERN_ERR "%s: connect_frontend failed (errno = %d)\n",
+		       DRIVER_NAME, result);
+		goto fail_fe_conn;
+	}
+
+	/* register network adapter */
+	dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
+	return 0;
+
+fail_fe_conn:
+	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+fail_fe_mem:
+	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+fail_fe_hw:
+	dvb_dmxdev_release(&dvb->dmxdev);
+fail_dmxdev:
+	dvb_dmx_release(&dvb->demux);
+fail_dmx:
+	dvb_unregister_frontend(dvb->frontend);
+fail_frontend:
+	dvb_frontend_detach(dvb->frontend);
+	dvb_unregister_adapter(&dvb->adapter);
+fail_adapter:
+	return result;
+}
+
+void au0828_dvb_unregister(struct au0828_dev *dev)
+{
+	struct au0828_dvb *dvb = &dev->dvb;
+
+	dprintk(1, "%s()\n", __func__);
+
+	if (dvb->frontend == NULL)
+		return;
+
+	dvb_net_release(&dvb->net);
+	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+	dvb_dmxdev_release(&dvb->dmxdev);
+	dvb_dmx_release(&dvb->demux);
+	dvb_unregister_frontend(dvb->frontend);
+	dvb_frontend_detach(dvb->frontend);
+	dvb_unregister_adapter(&dvb->adapter);
+}
+
+/* All the DVB attach calls go here, this function get's modified
+ * for each new card. No other function in this file needs
+ * to change.
+ */
+int au0828_dvb_register(struct au0828_dev *dev)
+{
+	struct au0828_dvb *dvb = &dev->dvb;
+	int ret;
+
+	dprintk(1, "%s()\n", __func__);
+
+	/* init frontend */
+	switch (dev->board) {
+	case AU0828_BOARD_HAUPPAUGE_HVR850:
+	case AU0828_BOARD_HAUPPAUGE_HVR950Q:
+	case AU0828_BOARD_DVICO_FUSIONHDTV7:
+		dvb->frontend = dvb_attach(au8522_attach,
+				&hauppauge_hvr950q_config,
+				&dev->i2c_adap);
+		if (dvb->frontend != NULL) {
+			hauppauge_hvr950q_tunerconfig.priv = dev;
+			dvb_attach(xc5000_attach, dvb->frontend,
+				&dev->i2c_adap,
+				&hauppauge_hvr950q_tunerconfig);
+		}
+		break;
+	default:
+		printk(KERN_WARNING "The frontend of your DVB/ATSC card "
+		       "isn't supported yet\n");
+		break;
+	}
+	if (NULL == dvb->frontend) {
+		printk(KERN_ERR "%s() Frontend initialization failed\n",
+		       __func__);
+		return -1;
+	}
+
+	/* Put the analog decoder in standby to keep it quiet */
+	au0828_call_i2c_clients(dev, TUNER_SET_STANDBY, NULL);
+
+	if (dvb->frontend->ops.analog_ops.standby)
+		dvb->frontend->ops.analog_ops.standby(dvb->frontend);
+
+	/* register everything */
+	ret = dvb_register(dev);
+	if (ret < 0) {
+		if (dvb->frontend->ops.release)
+			dvb->frontend->ops.release(dvb->frontend);
+		return ret;
+	}
+
+	return 0;
+}
diff --git a/drivers/media/video/au0828/au0828-i2c.c b/drivers/media/video/au0828/au0828-i2c.c
new file mode 100644
index 0000000..94c8b74
--- /dev/null
+++ b/drivers/media/video/au0828/au0828-i2c.c
@@ -0,0 +1,385 @@
+/*
+ *  Driver for the Auvitek AU0828 USB bridge
+ *
+ *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include "au0828.h"
+
+#include <media/v4l2-common.h>
+
+unsigned int i2c_debug;
+module_param(i2c_debug, int, 0444);
+MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
+
+unsigned int i2c_scan;
+module_param(i2c_scan, int, 0444);
+MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
+
+#define I2C_WAIT_DELAY 512
+#define I2C_WAIT_RETRY 64
+
+static inline int i2c_slave_did_write_ack(struct i2c_adapter *i2c_adap)
+{
+	struct au0828_dev *dev = i2c_adap->algo_data;
+	return au0828_read(dev, REG_201) & 0x08 ? 0 : 1;
+}
+
+static inline int i2c_slave_did_read_ack(struct i2c_adapter *i2c_adap)
+{
+	struct au0828_dev *dev = i2c_adap->algo_data;
+	return au0828_read(dev, REG_201) & 0x02 ? 0 : 1;
+}
+
+static int i2c_wait_read_ack(struct i2c_adapter *i2c_adap)
+{
+	int count;
+
+	for (count = 0; count < I2C_WAIT_RETRY; count++) {
+		if (!i2c_slave_did_read_ack(i2c_adap))
+			break;
+		udelay(I2C_WAIT_DELAY);
+	}
+
+	if (I2C_WAIT_RETRY == count)
+		return 0;
+
+	return 1;
+}
+
+static inline int i2c_is_read_busy(struct i2c_adapter *i2c_adap)
+{
+	struct au0828_dev *dev = i2c_adap->algo_data;
+	return au0828_read(dev, REG_201) & 0x01 ? 0 : 1;
+}
+
+static int i2c_wait_read_done(struct i2c_adapter *i2c_adap)
+{
+	int count;
+
+	for (count = 0; count < I2C_WAIT_RETRY; count++) {
+		if (!i2c_is_read_busy(i2c_adap))
+			break;
+		udelay(I2C_WAIT_DELAY);
+	}
+
+	if (I2C_WAIT_RETRY == count)
+		return 0;
+
+	return 1;
+}
+
+static inline int i2c_is_write_done(struct i2c_adapter *i2c_adap)
+{
+	struct au0828_dev *dev = i2c_adap->algo_data;
+	return au0828_read(dev, REG_201) & 0x04 ? 1 : 0;
+}
+
+static int i2c_wait_write_done(struct i2c_adapter *i2c_adap)
+{
+	int count;
+
+	for (count = 0; count < I2C_WAIT_RETRY; count++) {
+		if (i2c_is_write_done(i2c_adap))
+			break;
+		udelay(I2C_WAIT_DELAY);
+	}
+
+	if (I2C_WAIT_RETRY == count)
+		return 0;
+
+	return 1;
+}
+
+static inline int i2c_is_busy(struct i2c_adapter *i2c_adap)
+{
+	struct au0828_dev *dev = i2c_adap->algo_data;
+	return au0828_read(dev, REG_201) & 0x10 ? 1 : 0;
+}
+
+static int i2c_wait_done(struct i2c_adapter *i2c_adap)
+{
+	int count;
+
+	for (count = 0; count < I2C_WAIT_RETRY; count++) {
+		if (!i2c_is_busy(i2c_adap))
+			break;
+		udelay(I2C_WAIT_DELAY);
+	}
+
+	if (I2C_WAIT_RETRY == count)
+		return 0;
+
+	return 1;
+}
+
+/* FIXME: Implement join handling correctly */
+static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
+	const struct i2c_msg *msg, int joined_rlen)
+{
+	int i, strobe = 0;
+	struct au0828_dev *dev = i2c_adap->algo_data;
+
+	dprintk(4, "%s()\n", __func__);
+
+	au0828_write(dev, REG_2FF, 0x01);
+	au0828_write(dev, REG_202, 0x07);
+
+	/* Hardware needs 8 bit addresses */
+	au0828_write(dev, REG_203, msg->addr << 1);
+
+	dprintk(4, "SEND: %02x\n", msg->addr);
+
+	for (i = 0; i < msg->len;) {
+
+		dprintk(4, " %02x\n", msg->buf[i]);
+
+		au0828_write(dev, REG_205, msg->buf[i]);
+
+		strobe++;
+		i++;
+
+		if ((strobe >= 4) || (i >= msg->len)) {
+
+			/* Strobe the byte into the bus */
+			if (i < msg->len)
+				au0828_write(dev, REG_200, 0x41);
+			else
+				au0828_write(dev, REG_200, 0x01);
+
+			/* Reset strobe trigger */
+			strobe = 0;
+
+			if (!i2c_wait_write_done(i2c_adap))
+				return -EIO;
+
+		}
+
+	}
+	if (!i2c_wait_done(i2c_adap))
+		return -EIO;
+
+	dprintk(4, "\n");
+
+	return msg->len;
+}
+
+/* FIXME: Implement join handling correctly */
+static int i2c_readbytes(struct i2c_adapter *i2c_adap,
+	const struct i2c_msg *msg, int joined)
+{
+	struct au0828_dev *dev = i2c_adap->algo_data;
+	int i;
+
+	dprintk(4, "%s()\n", __func__);
+
+	au0828_write(dev, REG_2FF, 0x01);
+	au0828_write(dev, REG_202, 0x07);
+
+	/* Hardware needs 8 bit addresses */
+	au0828_write(dev, REG_203, msg->addr << 1);
+
+	dprintk(4, " RECV:\n");
+
+	/* Deal with i2c_scan */
+	if (msg->len == 0) {
+		au0828_write(dev, REG_200, 0x20);
+		if (i2c_wait_read_ack(i2c_adap))
+			return -EIO;
+		return 0;
+	}
+
+	for (i = 0; i < msg->len;) {
+
+		i++;
+
+		if (i < msg->len)
+			au0828_write(dev, REG_200, 0x60);
+		else
+			au0828_write(dev, REG_200, 0x20);
+
+		if (!i2c_wait_read_done(i2c_adap))
+			return -EIO;
+
+		msg->buf[i-1] = au0828_read(dev, REG_209) & 0xff;
+
+		dprintk(4, " %02x\n", msg->buf[i-1]);
+	}
+	if (!i2c_wait_done(i2c_adap))
+		return -EIO;
+
+	dprintk(4, "\n");
+
+	return msg->len;
+}
+
+static int i2c_xfer(struct i2c_adapter *i2c_adap,
+		    struct i2c_msg *msgs, int num)
+{
+	int i, retval = 0;
+
+	dprintk(4, "%s(num = %d)\n", __func__, num);
+
+	for (i = 0; i < num; i++) {
+		dprintk(4, "%s(num = %d) addr = 0x%02x  len = 0x%x\n",
+			__func__, num, msgs[i].addr, msgs[i].len);
+		if (msgs[i].flags & I2C_M_RD) {
+			/* read */
+			retval = i2c_readbytes(i2c_adap, &msgs[i], 0);
+		} else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) &&
+			   msgs[i].addr == msgs[i + 1].addr) {
+			/* write then read from same address */
+			retval = i2c_sendbytes(i2c_adap, &msgs[i],
+					       msgs[i + 1].len);
+			if (retval < 0)
+				goto err;
+			i++;
+			retval = i2c_readbytes(i2c_adap, &msgs[i], 1);
+		} else {
+			/* write */
+			retval = i2c_sendbytes(i2c_adap, &msgs[i], 0);
+		}
+		if (retval < 0)
+			goto err;
+	}
+	return num;
+
+err:
+	return retval;
+}
+
+static int attach_inform(struct i2c_client *client)
+{
+	dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
+		client->driver->driver.name, client->addr, client->name);
+
+	if (!client->driver->command)
+		return 0;
+
+	return 0;
+}
+
+static int detach_inform(struct i2c_client *client)
+{
+	dprintk(1, "i2c detach [client=%s]\n", client->name);
+
+	return 0;
+}
+
+void au0828_call_i2c_clients(struct au0828_dev *dev,
+			      unsigned int cmd, void *arg)
+{
+	if (dev->i2c_rc != 0)
+		return;
+
+	i2c_clients_command(&dev->i2c_adap, cmd, arg);
+}
+
+static u32 au0828_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm au0828_i2c_algo_template = {
+	.master_xfer	= i2c_xfer,
+	.functionality	= au0828_functionality,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_adapter au0828_i2c_adap_template = {
+	.name              = DRIVER_NAME,
+	.owner             = THIS_MODULE,
+	.id                = I2C_HW_B_AU0828,
+	.algo              = &au0828_i2c_algo_template,
+	.class             = I2C_CLASS_TV_ANALOG,
+	.client_register   = attach_inform,
+	.client_unregister = detach_inform,
+};
+
+static struct i2c_client au0828_i2c_client_template = {
+	.name	= "au0828 internal",
+};
+
+static char *i2c_devs[128] = {
+	[0x8e >> 1] = "au8522",
+	[0xa0 >> 1] = "eeprom",
+	[0xc2 >> 1] = "tuner/xc5000",
+};
+
+static void do_i2c_scan(char *name, struct i2c_client *c)
+{
+	unsigned char buf;
+	int i, rc;
+
+	for (i = 0; i < 128; i++) {
+		c->addr = i;
+		rc = i2c_master_recv(c, &buf, 0);
+		if (rc < 0)
+			continue;
+		printk(KERN_INFO "%s: i2c scan: found device @ 0x%x  [%s]\n",
+		       name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
+	}
+}
+
+/* init + register i2c algo-bit adapter */
+int au0828_i2c_register(struct au0828_dev *dev)
+{
+	dprintk(1, "%s()\n", __func__);
+
+	memcpy(&dev->i2c_adap, &au0828_i2c_adap_template,
+	       sizeof(dev->i2c_adap));
+	memcpy(&dev->i2c_algo, &au0828_i2c_algo_template,
+	       sizeof(dev->i2c_algo));
+	memcpy(&dev->i2c_client, &au0828_i2c_client_template,
+	       sizeof(dev->i2c_client));
+
+	dev->i2c_adap.dev.parent = &dev->usbdev->dev;
+
+	strlcpy(dev->i2c_adap.name, DRIVER_NAME,
+		sizeof(dev->i2c_adap.name));
+
+	dev->i2c_algo.data = dev;
+	dev->i2c_adap.algo_data = dev;
+	i2c_set_adapdata(&dev->i2c_adap, dev);
+	i2c_add_adapter(&dev->i2c_adap);
+
+	dev->i2c_client.adapter = &dev->i2c_adap;
+
+	if (0 == dev->i2c_rc) {
+		printk(KERN_INFO "%s: i2c bus registered\n", DRIVER_NAME);
+		if (i2c_scan)
+			do_i2c_scan(DRIVER_NAME, &dev->i2c_client);
+	} else
+		printk(KERN_INFO "%s: i2c bus register FAILED\n", DRIVER_NAME);
+
+	return dev->i2c_rc;
+}
+
+int au0828_i2c_unregister(struct au0828_dev *dev)
+{
+	i2c_del_adapter(&dev->i2c_adap);
+	return 0;
+}
+
diff --git a/drivers/media/video/au0828/au0828-reg.h b/drivers/media/video/au0828/au0828-reg.h
new file mode 100644
index 0000000..3982755
--- /dev/null
+++ b/drivers/media/video/au0828/au0828-reg.h
@@ -0,0 +1,38 @@
+/*
+ *  Driver for the Auvitek USB bridge
+ *
+ *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* We'll start to rename these registers once we have a better
+ * understanding of their meaning.
+ */
+#define REG_000 0x000
+#define REG_001 0x001
+#define REG_002 0x002
+#define REG_003 0x003
+
+#define REG_200 0x200
+#define REG_201 0x201
+#define REG_202 0x202
+#define REG_203 0x203
+#define REG_205 0x205
+#define REG_209 0x209
+#define REG_2FF 0x2ff
+
+#define REG_600 0x600
diff --git a/drivers/media/video/au0828/au0828.h b/drivers/media/video/au0828/au0828.h
new file mode 100644
index 0000000..0200b9f
--- /dev/null
+++ b/drivers/media/video/au0828/au0828.h
@@ -0,0 +1,128 @@
+/*
+ *  Driver for the Auvitek AU0828 USB bridge
+ *
+ *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <media/tveeprom.h>
+
+/* DVB */
+#include "demux.h"
+#include "dmxdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+#include "dvbdev.h"
+
+#include "au0828-reg.h"
+#include "au0828-cards.h"
+
+#define DRIVER_NAME "au0828"
+#define URB_COUNT   16
+#define URB_BUFSIZE (0xe522)
+
+struct au0828_board {
+	char *name;
+};
+
+struct au0828_dvb {
+	struct mutex lock;
+	struct dvb_adapter adapter;
+	struct dvb_frontend *frontend;
+	struct dvb_demux demux;
+	struct dmxdev dmxdev;
+	struct dmx_frontend fe_hw;
+	struct dmx_frontend fe_mem;
+	struct dvb_net net;
+	int feeding;
+};
+
+struct au0828_dev {
+	struct mutex mutex;
+	struct usb_device	*usbdev;
+	int			board;
+	u8			ctrlmsg[64];
+
+	/* I2C */
+	struct i2c_adapter		i2c_adap;
+	struct i2c_algo_bit_data	i2c_algo;
+	struct i2c_client		i2c_client;
+	u32 				i2c_rc;
+
+	/* Digital */
+	struct au0828_dvb		dvb;
+
+	/* USB / URB Related */
+	int		urb_streaming;
+	struct urb	*urbs[URB_COUNT];
+
+};
+
+struct au0828_buff {
+	struct au0828_dev	*dev;
+	struct urb		*purb;
+	struct list_head	buff_list;
+};
+
+/* ----------------------------------------------------------- */
+#define au0828_read(dev, reg) au0828_readreg(dev, reg)
+#define au0828_write(dev, reg, value) au0828_writereg(dev, reg, value)
+#define au0828_andor(dev, reg, mask, value) 				\
+	 au0828_writereg(dev, reg, 					\
+	(au0828_readreg(dev, reg) & ~(mask)) | ((value) & (mask)))
+
+#define au0828_set(dev, reg, bit) au0828_andor(dev, (reg), (bit), (bit))
+#define au0828_clear(dev, reg, bit) au0828_andor(dev, (reg), (bit), 0)
+
+/* ----------------------------------------------------------- */
+/* au0828-core.c */
+extern u32 au0828_read(struct au0828_dev *dev, u16 reg);
+extern u32 au0828_write(struct au0828_dev *dev, u16 reg, u32 val);
+extern unsigned int debug;
+extern unsigned int usb_debug;
+extern unsigned int bridge_debug;
+
+/* ----------------------------------------------------------- */
+/* au0828-cards.c */
+extern struct au0828_board au0828_boards[];
+extern struct usb_device_id au0828_usb_id_table[];
+extern const unsigned int au0828_bcount;
+extern void au0828_gpio_setup(struct au0828_dev *dev);
+extern int au0828_tuner_callback(void *priv, int command, int arg);
+extern void au0828_card_setup(struct au0828_dev *dev);
+
+/* ----------------------------------------------------------- */
+/* au0828-i2c.c */
+extern int au0828_i2c_register(struct au0828_dev *dev);
+extern int au0828_i2c_unregister(struct au0828_dev *dev);
+extern void au0828_call_i2c_clients(struct au0828_dev *dev,
+	unsigned int cmd, void *arg);
+extern unsigned int i2c_debug;
+
+/* ----------------------------------------------------------- */
+/* au0828-dvb.c */
+extern int au0828_dvb_register(struct au0828_dev *dev);
+extern void au0828_dvb_unregister(struct au0828_dev *dev);
+
+#define dprintk(level, fmt, arg...)\
+	do { if (debug & level)\
+		printk(KERN_DEBUG DRIVER_NAME "/0: " fmt, ## arg);\
+	} while (0)
diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c
index e663cc0..8bfd5c7 100644
--- a/drivers/media/video/bt819.c
+++ b/drivers/media/video/bt819.c
@@ -57,7 +57,7 @@
 #define I2C_NAME(s) (s)->name
 
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
diff --git a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c
index 7dee2e3..98ee2d8 100644
--- a/drivers/media/video/bt856.c
+++ b/drivers/media/video/bt856.c
@@ -56,7 +56,7 @@
 #define I2C_NAME(s) (s)->name
 
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index 7374c02..f20a01c 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -71,6 +71,8 @@
 static void sigmaSLC_muxsel(struct bttv *btv, unsigned int input);
 static void sigmaSQ_muxsel(struct bttv *btv, unsigned int input);
 
+static void geovision_muxsel(struct bttv *btv, unsigned int input);
+
 static int terratec_active_radio_upgrade(struct bttv *btv);
 static int tea5757_read(struct bttv *btv);
 static int tea5757_write(struct bttv *btv, int value);
@@ -301,6 +303,7 @@
 	{ 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE,    "DViCO FusionHDTV 5 Lite" },
 	{ 0x00261822, BTTV_BOARD_TWINHAN_DST,	"DNTV Live! Mini "},
 	{ 0xd200dbc0, BTTV_BOARD_DVICO_FUSIONHDTV_2,	"DViCO FusionHDTV 2" },
+	{ 0x763c008a, BTTV_BOARD_GEOVISION_GV600,	"GeoVision GV-600" },
 
 	{ 0, -1, NULL }
 };
@@ -576,6 +579,8 @@
 		.needs_tvaudio	= 1,
 		.pll		= PLL_28,
 		.tuner_type	= UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
 	},
 	[BTTV_BOARD_WINVIEW_601] = {
 		.name		= "Leadtek WinView 601",
@@ -2322,7 +2327,7 @@
 		.tuner          = 0,
 		.svhs           = 2,
 		.muxsel         = { 2, 3, 1, 0 },
-		.tuner_type     = TUNER_PHILIPS_ATSC,
+		.tuner_type     = TUNER_PHILIPS_FCV1236D,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.has_dvb        = 1,
@@ -2961,7 +2966,7 @@
 	[BTTV_BOARD_DVICO_FUSIONHDTV_2] = {
 		.name           = "DViCO FusionHDTV 2",
 		.tuner          = 0,
-		.tuner_type     = TUNER_PHILIPS_ATSC, /* FCV1236D */
+		.tuner_type     = TUNER_PHILIPS_FCV1236D,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.video_inputs   = 3,
@@ -2992,6 +2997,45 @@
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
+	[BTTV_BOARD_GEOVISION_GV600] = {
+		/* emhn@usb.ve */
+		.name             = "Geovision GV-600",
+		.video_inputs     = 16,
+		.audio_inputs     = 0,
+		.tuner            = UNSET,
+		.svhs             = UNSET,
+		.gpiomask         = 0x0,
+		.muxsel           = { 2, 2, 2, 2, 2, 2, 2, 2,
+				      2, 2, 2, 2, 2, 2, 2, 2 },
+		.muxsel_hook      = geovision_muxsel,
+		.gpiomux          = { 0 },
+		.no_msp34xx       = 1,
+		.pll              = PLL_28,
+		.tuner_type       = UNSET,
+		.tuner_addr	  = ADDR_UNSET,
+		.radio_addr       = ADDR_UNSET,
+	},
+	[BTTV_BOARD_KOZUMI_KTV_01C] = {
+		/* Mauro Lacy <mauro@lacy.com.ar>
+		 * Based on MagicTV and Conceptronic CONTVFMi */
+
+		.name           = "Kozumi KTV-01C",
+		.video_inputs   = 3,
+		.audio_inputs   = 1,
+		.tuner          = 0,
+		.svhs           = 2,
+		.gpiomask       = 0x008007,
+		.muxsel         = { 2, 3, 1, 1 },
+		.gpiomux        = { 0, 1, 2, 2 }, /* CONTVFMi */
+		.gpiomute 	= 3, /* CONTVFMi */
+		.needs_tvaudio  = 0,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3, /* TCL MK3 */
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.pll            = PLL_28,
+		.has_radio      = 1,
+		.has_remote     = 1,
+	},
 };
 
 static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -3331,6 +3375,13 @@
 	gpio_bits( 3<<9, inmux<<9 );
 }
 
+static void geovision_muxsel(struct bttv *btv, unsigned int input)
+{
+	unsigned int inmux = input % 16;
+	gpio_inout(0xf, 0xf);
+	gpio_bits(0xf, inmux);
+}
+
 /* ----------------------------------------------------------------------- */
 
 static void bttv_reset_audio(struct bttv *btv)
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index fcf8f2d..2ca3e9c 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -2372,7 +2372,7 @@
 	if (check_btres(fh, RESOURCE_OVERLAY)) {
 		struct bttv_buffer *new;
 
-		new = videobuf_pci_alloc(sizeof(*new));
+		new = videobuf_sg_alloc(sizeof(*new));
 		new->crop = btv->crop[!!fh->do_crop].rect;
 		bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
 		retval = bttv_switch_overlay(btv,fh,new);
@@ -2760,7 +2760,7 @@
 	mutex_lock(&fh->cap.vb_lock);
 	if (on) {
 		fh->ov.tvnorm = btv->tvnorm;
-		new = videobuf_pci_alloc(sizeof(*new));
+		new = videobuf_sg_alloc(sizeof(*new));
 		new->crop = btv->crop[!!fh->do_crop].rect;
 		bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
 	} else {
@@ -2834,7 +2834,7 @@
 		if (check_btres(fh, RESOURCE_OVERLAY)) {
 			struct bttv_buffer *new;
 
-			new = videobuf_pci_alloc(sizeof(*new));
+			new = videobuf_sg_alloc(sizeof(*new));
 			new->crop = btv->crop[!!fh->do_crop].rect;
 			bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
 			retval = bttv_switch_overlay(btv, fh, new);
@@ -3117,12 +3117,18 @@
 
 static int bttv_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
 {
+	if (unlikely(a->index))
+		return -EINVAL;
+
 	strcpy(a->name, "audio");
 	return 0;
 }
 
 static int bttv_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
 {
+	if (unlikely(a->index))
+		return -EINVAL;
+
 	return 0;
 }
 
@@ -3184,7 +3190,7 @@
 			/* need to capture a new frame */
 			if (locked_btres(fh->btv,RESOURCE_VIDEO_STREAM))
 				goto err;
-			fh->cap.read_buf = videobuf_pci_alloc(fh->cap.msize);
+			fh->cap.read_buf = videobuf_sg_alloc(fh->cap.msize);
 			if (NULL == fh->cap.read_buf)
 				goto err;
 			fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR;
@@ -3251,14 +3257,14 @@
 	fh->ov.setup_ok = 0;
 	v4l2_prio_open(&btv->prio,&fh->prio);
 
-	videobuf_queue_pci_init(&fh->cap, &bttv_video_qops,
-			    btv->c.pci, &btv->s_lock,
+	videobuf_queue_sg_init(&fh->cap, &bttv_video_qops,
+			    &btv->c.pci->dev, &btv->s_lock,
 			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
 			    V4L2_FIELD_INTERLACED,
 			    sizeof(struct bttv_buffer),
 			    fh);
-	videobuf_queue_pci_init(&fh->vbi, &bttv_vbi_qops,
-			    btv->c.pci, &btv->s_lock,
+	videobuf_queue_sg_init(&fh->vbi, &bttv_vbi_qops,
+			    &btv->c.pci->dev, &btv->s_lock,
 			    V4L2_BUF_TYPE_VBI_CAPTURE,
 			    V4L2_FIELD_SEQ_TB,
 			    sizeof(struct bttv_buffer),
@@ -3457,6 +3463,9 @@
 	struct bttv *btv = fh->btv;
 	struct rds_command cmd;
 
+	file->private_data = NULL;
+	kfree(fh);
+
 	btv->radio_user--;
 
 	bttv_call_i2c_clients(btv, RDS_CMD_CLOSE, &cmd);
@@ -3510,7 +3519,7 @@
 		return -EINVAL;
 
 	strcpy(i->name, "Radio");
-	 i->type = V4L2_INPUT_TYPE_TUNER;
+	i->type = V4L2_INPUT_TYPE_TUNER;
 
 	return 0;
 }
@@ -3518,10 +3527,9 @@
 static int radio_g_audio(struct file *file, void *priv,
 					struct v4l2_audio *a)
 {
-	if (a->index != 0)
+	if (unlikely(a->index))
 		return -EINVAL;
 
-	memset(a, 0, sizeof(*a));
 	strcpy(a->name, "Radio");
 
 	return 0;
@@ -3543,11 +3551,17 @@
 static int radio_s_audio(struct file *file, void *priv,
 					struct v4l2_audio *a)
 {
+	if (unlikely(a->index))
+		return -EINVAL;
+
 	return 0;
 }
 
 static int radio_s_input(struct file *filp, void *priv, unsigned int i)
 {
+	if (unlikely(i))
+		return -EINVAL;
+
 	return 0;
 }
 
diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c
index fc9ecb2..a38af98 100644
--- a/drivers/media/video/bt8xx/bttv-input.c
+++ b/drivers/media/video/bt8xx/bttv-input.c
@@ -278,6 +278,12 @@
 		ir->mask_keyup   = 0x004000;
 		ir->polling      = 50; /* ms */
 		break;
+	case BTTV_BOARD_KOZUMI_KTV_01C:
+		ir_codes         = ir_codes_pctv_sedna;
+		ir->mask_keycode = 0x001f00;
+		ir->mask_keyup   = 0x006000;
+		ir->polling      = 50; /* ms */
+		break;
 	}
 	if (NULL == ir_codes) {
 		dprintk(KERN_INFO "Ooops: IR config error [card=%d]\n", btv->c.type);
diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c
index 75fa82c..bfdbc46 100644
--- a/drivers/media/video/bt8xx/bttv-vbi.c
+++ b/drivers/media/video/bt8xx/bttv-vbi.c
@@ -54,7 +54,7 @@
 #define VBI_DEFLINES 16
 
 static unsigned int vbibufs = 4;
-static unsigned int vbi_debug = 0;
+static unsigned int vbi_debug;
 
 module_param(vbibufs,   int, 0444);
 module_param(vbi_debug, int, 0644);
diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h
index bf4c339..f239320 100644
--- a/drivers/media/video/bt8xx/bttv.h
+++ b/drivers/media/video/bt8xx/bttv.h
@@ -19,6 +19,7 @@
 #include <media/ir-common.h>
 #include <media/ir-kbd-i2c.h>
 #include <media/i2c-addr.h>
+#include <media/tuner.h>
 
 /* ---------------------------------------------------------- */
 /* exported by bttv-cards.c                                   */
@@ -173,6 +174,8 @@
 #define BTTV_BOARD_VOODOOTV_200		   0x93
 #define BTTV_BOARD_DVICO_FUSIONHDTV_2	   0x94
 #define BTTV_BOARD_TYPHOON_TVTUNERPCI	   0x95
+#define BTTV_BOARD_GEOVISION_GV600	   0x96
+#define BTTV_BOARD_KOZUMI_KTV_01C          0x97
 
 
 /* more card-specific defines */
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
index 1305d31..03816b7 100644
--- a/drivers/media/video/bt8xx/bttvp.h
+++ b/drivers/media/video/bt8xx/bttvp.h
@@ -42,7 +42,6 @@
 
 #include <linux/device.h>
 #include <media/videobuf-dma-sg.h>
-#include <media/tuner.h>
 #include <media/tveeprom.h>
 #include <media/ir-common.h>
 
diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c
index 0322653..b364ada 100644
--- a/drivers/media/video/bw-qcam.c
+++ b/drivers/media/video/bw-qcam.c
@@ -523,7 +523,7 @@
 	int ret=1;
 	unsigned int hi, lo;
 	unsigned int hi2, lo2;
-	static int state = 0;
+	static int state;
 
 	if (buffer == NULL)
 	{
@@ -898,7 +898,9 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl          = qcam_ioctl,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
+#endif
 	.read		= qcam_read,
 	.llseek         = no_llseek,
 };
@@ -912,7 +914,7 @@
 
 #define MAX_CAMS 4
 static struct qcam_device *qcams[MAX_CAMS];
-static unsigned int num_cams = 0;
+static unsigned int num_cams;
 
 static int init_bwqcam(struct parport *port)
 {
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c
index cf1546b5..fe1e67b 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -36,6 +36,7 @@
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
 #include <linux/mutex.h>
+#include <linux/jiffies.h>
 
 #include <asm/uaccess.h>
 
@@ -69,7 +70,7 @@
 
 static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 };
 static int probe = 2;
-static int force_rgb = 0;
+static int force_rgb;
 static int video_nr = -1;
 
 static inline void qcam_set_ack(struct qcam_device *qcam, unsigned int i)
@@ -95,7 +96,8 @@
 	unsigned long oldjiffies = jiffies;
 	unsigned int i;
 
-	for (oldjiffies = jiffies; (jiffies - oldjiffies) < msecs_to_jiffies(40); )
+	for (oldjiffies = jiffies;
+	     time_before(jiffies, oldjiffies + msecs_to_jiffies(40)); )
 		if (qcam_ready1(qcam) == value)
 			return 0;
 
@@ -120,7 +122,8 @@
 	unsigned long oldjiffies = jiffies;
 	unsigned int i;
 
-	for (oldjiffies = jiffies; (jiffies - oldjiffies) < msecs_to_jiffies(40); )
+	for (oldjiffies = jiffies;
+	     time_before(jiffies, oldjiffies + msecs_to_jiffies(40)); )
 		if (qcam_ready2(qcam) == value)
 			return 0;
 
@@ -689,7 +692,9 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl          = qcam_ioctl,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
+#endif
 	.read		= qcam_read,
 	.llseek         = no_llseek,
 };
@@ -741,7 +746,7 @@
 }
 
 static struct qcam_device *qcams[MAX_CAMS];
-static unsigned int num_cams = 0;
+static unsigned int num_cams;
 
 static int init_cqcam(struct parport *port)
 {
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
index 7ae499c..5195b1f 100644
--- a/drivers/media/video/cafe_ccic.c
+++ b/drivers/media/video/cafe_ccic.c
@@ -65,7 +65,7 @@
  */
 
 #define MAX_DMA_BUFS 3
-static int alloc_bufs_at_read = 0;
+static int alloc_bufs_at_read;
 module_param(alloc_bufs_at_read, bool, 0444);
 MODULE_PARM_DESC(alloc_bufs_at_read,
 		"Non-zero value causes DMA buffers to be allocated when the "
@@ -99,7 +99,7 @@
 		"will be allowed to allocate.  These buffers are big and live "
 		"in vmalloc space.");
 
-static int flip = 0;
+static int flip;
 module_param(flip, bool, 0444);
 MODULE_PARM_DESC(flip,
 		"If set, the sensor will be instructed to flip the image "
diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c
index 7c630f5..2a81376 100644
--- a/drivers/media/video/cpia.c
+++ b/drivers/media/video/cpia.c
@@ -3792,7 +3792,9 @@
 	.read		= cpia_read,
 	.mmap		= cpia_mmap,
 	.ioctl          = cpia_ioctl,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
+#endif
 	.llseek         = no_llseek,
 };
 
diff --git a/drivers/media/video/cpia.h b/drivers/media/video/cpia.h
index 78392fb..5096058 100644
--- a/drivers/media/video/cpia.h
+++ b/drivers/media/video/cpia.h
@@ -412,11 +412,11 @@
 /* ErrorCode */
 #define ERROR_FLICKER_BELOW_MIN_EXP     0x01 /*flicker exposure got below minimum exposure */
 #define ALOG(fmt,args...) printk(fmt, ##args)
-#define LOG(fmt,args...) ALOG(KERN_INFO __FILE__ ":%s(%d):" fmt, __FUNCTION__ , __LINE__ , ##args)
+#define LOG(fmt,args...) ALOG(KERN_INFO __FILE__ ":%s(%d):" fmt, __func__ , __LINE__ , ##args)
 
 #ifdef _CPIA_DEBUG_
 #define ADBG(fmt,args...) printk(fmt, jiffies, ##args)
-#define DBG(fmt,args...) ADBG(KERN_DEBUG __FILE__" (%ld):%s(%d):" fmt, __FUNCTION__, __LINE__ , ##args)
+#define DBG(fmt,args...) ADBG(KERN_DEBUG __FILE__" (%ld):%s(%d):" fmt, __func__, __LINE__ , ##args)
 #else
 #define DBG(fmn,args...) do {} while(0)
 #endif
diff --git a/drivers/media/video/cpia2/cpia2_core.c b/drivers/media/video/cpia2/cpia2_core.c
index a76bd78..c8b9fdb 100644
--- a/drivers/media/video/cpia2/cpia2_core.c
+++ b/drivers/media/video/cpia2/cpia2_core.c
@@ -34,7 +34,7 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 
-//#define _CPIA2_DEBUG_
+/* #define _CPIA2_DEBUG_ */
 
 #include "cpia2patch.h"
 
@@ -48,7 +48,7 @@
 };
 #endif
 
-static unsigned int debugs_on = 0;//DEBUG_REG;
+static unsigned int debugs_on;	/* default 0 - DEBUG_REG */
 
 
 /******************************************************************************
@@ -570,7 +570,7 @@
 			    block_name[block_index]);
 		break;
 	default:
-		LOG("%s: invalid request mode\n",__FUNCTION__);
+		LOG("%s: invalid request mode\n",__func__);
 		return -EINVAL;
 	}
 
@@ -952,7 +952,7 @@
 			frame_rate = CPIA2_VP_FRAMERATE_30;
 		break;
 	default:
-		LOG("%s: Invalid sensor flag value 0x%0X\n",__FUNCTION__,
+		LOG("%s: Invalid sensor flag value 0x%0X\n",__func__,
 		    cam->params.version.sensor_flags);
 		return -EINVAL;
 	}
@@ -2356,12 +2356,12 @@
 	}
 
 	if (!buf) {
-		ERR("%s: buffer NULL\n",__FUNCTION__);
+		ERR("%s: buffer NULL\n",__func__);
 		return -EINVAL;
 	}
 
 	if (!cam) {
-		ERR("%s: Internal error, camera_data NULL!\n",__FUNCTION__);
+		ERR("%s: Internal error, camera_data NULL!\n",__func__);
 		return -EINVAL;
 	}
 
@@ -2370,7 +2370,7 @@
 		return -ERESTARTSYS;
 
 	if (!cam->present) {
-		LOG("%s: camera removed\n",__FUNCTION__);
+		LOG("%s: camera removed\n",__func__);
 		mutex_unlock(&cam->busy_lock);
 		return 0;	/* EOF */
 	}
@@ -2434,7 +2434,7 @@
 	unsigned int status=0;
 
 	if(!cam) {
-		ERR("%s: Internal error, camera_data not found!\n",__FUNCTION__);
+		ERR("%s: Internal error, camera_data not found!\n",__func__);
 		return POLLERR;
 	}
 
diff --git a/drivers/media/video/cpia2/cpia2_usb.c b/drivers/media/video/cpia2/cpia2_usb.c
index d8e9298..a4574740 100644
--- a/drivers/media/video/cpia2/cpia2_usb.c
+++ b/drivers/media/video/cpia2/cpia2_usb.c
@@ -84,7 +84,7 @@
  *****************************************************************************/
 static void process_frame(struct camera_data *cam)
 {
-	static int frame_count = 0;
+	static int frame_count;
 
 	unsigned char *inbuff = cam->workbuff->data;
 
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c
index e378abe..7ce2789 100644
--- a/drivers/media/video/cpia2/cpia2_v4l.c
+++ b/drivers/media/video/cpia2/cpia2_v4l.c
@@ -1927,7 +1927,9 @@
 	.poll		= cpia2_v4l_poll,
 	.ioctl		= cpia2_ioctl,
 	.llseek		= no_llseek,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
+#endif
 	.mmap		= cpia2_mmap,
 };
 
diff --git a/drivers/media/video/cpia_usb.c b/drivers/media/video/cpia_usb.c
index 9da4726..ef1f893 100644
--- a/drivers/media/video/cpia_usb.c
+++ b/drivers/media/video/cpia_usb.c
@@ -170,7 +170,7 @@
 	/* resubmit */
 	urb->dev = ucpia->dev;
 	if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0)
-		printk(KERN_ERR "%s: usb_submit_urb ret %d\n", __FUNCTION__,  i);
+		printk(KERN_ERR "%s: usb_submit_urb ret %d\n", __func__,  i);
 }
 
 static int cpia_usb_open(void *privdata)
diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig
index 1fd326f..ca5fbce 100644
--- a/drivers/media/video/cx23885/Kconfig
+++ b/drivers/media/video/cx23885/Kconfig
@@ -8,6 +8,7 @@
 	select VIDEO_TVEEPROM
 	select VIDEO_IR
 	select VIDEOBUF_DVB
+	select VIDEO_CX25840
 	select DVB_TUNER_MT2131 if !DVB_FE_CUSTOMISE
 	select DVB_S5H1409 if !DVB_FE_CUSTOMISE
 	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
@@ -16,6 +17,7 @@
 	select TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
 	select DVB_TDA18271 if !DVB_FE_CUSTOMIZE
 	select DVB_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
+	select DVB_TDA10048 if !DVB_FE_CUSTOMIZE
 	---help---
 	  This is a video4linux driver for Conexant 23885 based
 	  TV cards.
diff --git a/drivers/media/video/cx23885/Makefile b/drivers/media/video/cx23885/Makefile
index 32c90be..d7b0721 100644
--- a/drivers/media/video/cx23885/Makefile
+++ b/drivers/media/video/cx23885/Makefile
@@ -1,4 +1,4 @@
-cx23885-objs	:= cx23885-cards.o cx23885-video.o cx23885-vbi.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o
+cx23885-objs	:= cx23885-cards.o cx23885-video.o cx23885-vbi.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o cx23885-417.o
 
 obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
 
diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c
new file mode 100644
index 0000000..acdd3b6
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-417.c
@@ -0,0 +1,1764 @@
+/*
+ *
+ *  Support for a cx23417 mpeg encoder via cx23885 host port.
+ *
+ *    (c) 2004 Jelle Foks <jelle@foks.8m.com>
+ *    (c) 2004 Gerd Knorr <kraxel@bytesex.org>
+ *    (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *      - CX23885/7/8 support
+ *
+ *  Includes parts from the ivtv driver( http://ivtv.sourceforge.net/),
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <media/v4l2-common.h>
+#include <media/cx2341x.h>
+
+#include "cx23885.h"
+#include "media/cx2341x.h"
+
+#define CX23885_FIRM_IMAGE_SIZE 376836
+#define CX23885_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw"
+
+static unsigned int mpegbufs = 32;
+module_param(mpegbufs, int, 0644);
+MODULE_PARM_DESC(mpegbufs, "number of mpeg buffers, range 2-32");
+static unsigned int mpeglines = 32;
+module_param(mpeglines, int, 0644);
+MODULE_PARM_DESC(mpeglines, "number of lines in an MPEG buffer, range 2-32");
+static unsigned int mpeglinesize = 512;
+module_param(mpeglinesize, int, 0644);
+MODULE_PARM_DESC(mpeglinesize,
+	"number of bytes in each line of an MPEG buffer, range 512-1024");
+
+static unsigned int v4l_debug;
+module_param(v4l_debug, int, 0644);
+MODULE_PARM_DESC(v4l_debug, "enable V4L debug messages");
+
+#define dprintk(level, fmt, arg...)\
+	do { if (v4l_debug >= level) \
+		printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg);\
+	} while (0)
+
+static struct cx23885_tvnorm cx23885_tvnorms[] = {
+	{
+		.name      = "NTSC-M",
+		.id        = V4L2_STD_NTSC_M,
+	}, {
+		.name      = "NTSC-JP",
+		.id        = V4L2_STD_NTSC_M_JP,
+	}, {
+		.name      = "PAL-BG",
+		.id        = V4L2_STD_PAL_BG,
+	}, {
+		.name      = "PAL-DK",
+		.id        = V4L2_STD_PAL_DK,
+	}, {
+		.name      = "PAL-I",
+		.id        = V4L2_STD_PAL_I,
+	}, {
+		.name      = "PAL-M",
+		.id        = V4L2_STD_PAL_M,
+	}, {
+		.name      = "PAL-N",
+		.id        = V4L2_STD_PAL_N,
+	}, {
+		.name      = "PAL-Nc",
+		.id        = V4L2_STD_PAL_Nc,
+	}, {
+		.name      = "PAL-60",
+		.id        = V4L2_STD_PAL_60,
+	}, {
+		.name      = "SECAM-L",
+		.id        = V4L2_STD_SECAM_L,
+	}, {
+		.name      = "SECAM-DK",
+		.id        = V4L2_STD_SECAM_DK,
+	}
+};
+
+/* ------------------------------------------------------------------ */
+enum cx23885_capture_type {
+	CX23885_MPEG_CAPTURE,
+	CX23885_RAW_CAPTURE,
+	CX23885_RAW_PASSTHRU_CAPTURE
+};
+enum cx23885_capture_bits {
+	CX23885_RAW_BITS_NONE             = 0x00,
+	CX23885_RAW_BITS_YUV_CAPTURE      = 0x01,
+	CX23885_RAW_BITS_PCM_CAPTURE      = 0x02,
+	CX23885_RAW_BITS_VBI_CAPTURE      = 0x04,
+	CX23885_RAW_BITS_PASSTHRU_CAPTURE = 0x08,
+	CX23885_RAW_BITS_TO_HOST_CAPTURE  = 0x10
+};
+enum cx23885_capture_end {
+	CX23885_END_AT_GOP, /* stop at the end of gop, generate irq */
+	CX23885_END_NOW, /* stop immediately, no irq */
+};
+enum cx23885_framerate {
+	CX23885_FRAMERATE_NTSC_30, /* NTSC: 30fps */
+	CX23885_FRAMERATE_PAL_25   /* PAL: 25fps */
+};
+enum cx23885_stream_port {
+	CX23885_OUTPUT_PORT_MEMORY,
+	CX23885_OUTPUT_PORT_STREAMING,
+	CX23885_OUTPUT_PORT_SERIAL
+};
+enum cx23885_data_xfer_status {
+	CX23885_MORE_BUFFERS_FOLLOW,
+	CX23885_LAST_BUFFER,
+};
+enum cx23885_picture_mask {
+	CX23885_PICTURE_MASK_NONE,
+	CX23885_PICTURE_MASK_I_FRAMES,
+	CX23885_PICTURE_MASK_I_P_FRAMES = 0x3,
+	CX23885_PICTURE_MASK_ALL_FRAMES = 0x7,
+};
+enum cx23885_vbi_mode_bits {
+	CX23885_VBI_BITS_SLICED,
+	CX23885_VBI_BITS_RAW,
+};
+enum cx23885_vbi_insertion_bits {
+	CX23885_VBI_BITS_INSERT_IN_XTENSION_USR_DATA,
+	CX23885_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1,
+	CX23885_VBI_BITS_SEPARATE_STREAM = 0x2 << 1,
+	CX23885_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1,
+	CX23885_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1,
+};
+enum cx23885_dma_unit {
+	CX23885_DMA_BYTES,
+	CX23885_DMA_FRAMES,
+};
+enum cx23885_dma_transfer_status_bits {
+	CX23885_DMA_TRANSFER_BITS_DONE = 0x01,
+	CX23885_DMA_TRANSFER_BITS_ERROR = 0x04,
+	CX23885_DMA_TRANSFER_BITS_LL_ERROR = 0x10,
+};
+enum cx23885_pause {
+	CX23885_PAUSE_ENCODING,
+	CX23885_RESUME_ENCODING,
+};
+enum cx23885_copyright {
+	CX23885_COPYRIGHT_OFF,
+	CX23885_COPYRIGHT_ON,
+};
+enum cx23885_notification_type {
+	CX23885_NOTIFICATION_REFRESH,
+};
+enum cx23885_notification_status {
+	CX23885_NOTIFICATION_OFF,
+	CX23885_NOTIFICATION_ON,
+};
+enum cx23885_notification_mailbox {
+	CX23885_NOTIFICATION_NO_MAILBOX = -1,
+};
+enum cx23885_field1_lines {
+	CX23885_FIELD1_SAA7114 = 0x00EF, /* 239 */
+	CX23885_FIELD1_SAA7115 = 0x00F0, /* 240 */
+	CX23885_FIELD1_MICRONAS = 0x0105, /* 261 */
+};
+enum cx23885_field2_lines {
+	CX23885_FIELD2_SAA7114 = 0x00EF, /* 239 */
+	CX23885_FIELD2_SAA7115 = 0x00F0, /* 240 */
+	CX23885_FIELD2_MICRONAS = 0x0106, /* 262 */
+};
+enum cx23885_custom_data_type {
+	CX23885_CUSTOM_EXTENSION_USR_DATA,
+	CX23885_CUSTOM_PRIVATE_PACKET,
+};
+enum cx23885_mute {
+	CX23885_UNMUTE,
+	CX23885_MUTE,
+};
+enum cx23885_mute_video_mask {
+	CX23885_MUTE_VIDEO_V_MASK = 0x0000FF00,
+	CX23885_MUTE_VIDEO_U_MASK = 0x00FF0000,
+	CX23885_MUTE_VIDEO_Y_MASK = 0xFF000000,
+};
+enum cx23885_mute_video_shift {
+	CX23885_MUTE_VIDEO_V_SHIFT = 8,
+	CX23885_MUTE_VIDEO_U_SHIFT = 16,
+	CX23885_MUTE_VIDEO_Y_SHIFT = 24,
+};
+
+/* defines below are from ivtv-driver.h */
+#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF
+
+/* Firmware API commands */
+#define IVTV_API_STD_TIMEOUT 500
+
+/* Registers */
+/* IVTV_REG_OFFSET */
+#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8)
+#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC)
+#define IVTV_REG_SPU (0x9050)
+#define IVTV_REG_HW_BLOCKS (0x9054)
+#define IVTV_REG_VPU (0x9058)
+#define IVTV_REG_APU (0xA064)
+
+/**** Bit definitions for MC417_RWD and MC417_OEN registers  ***
+  bits 31-16
++-----------+
+| Reserved  |
++-----------+
+  bit 15  bit 14  bit 13 bit 12  bit 11  bit 10  bit 9   bit 8
++-------+-------+-------+-------+-------+-------+-------+-------+
+| MIWR# | MIRD# | MICS# |MIRDY# |MIADDR3|MIADDR2|MIADDR1|MIADDR0|
++-------+-------+-------+-------+-------+-------+-------+-------+
+ bit 7   bit 6   bit 5   bit 4   bit 3   bit 2   bit 1   bit 0
++-------+-------+-------+-------+-------+-------+-------+-------+
+|MIDATA7|MIDATA6|MIDATA5|MIDATA4|MIDATA3|MIDATA2|MIDATA1|MIDATA0|
++-------+-------+-------+-------+-------+-------+-------+-------+
+***/
+#define MC417_MIWR	0x8000
+#define MC417_MIRD	0x4000
+#define MC417_MICS	0x2000
+#define MC417_MIRDY	0x1000
+#define MC417_MIADDR	0x0F00
+#define MC417_MIDATA	0x00FF
+
+/* MIADDR* nibble definitions */
+#define  MCI_MEMORY_DATA_BYTE0          0x000
+#define  MCI_MEMORY_DATA_BYTE1          0x100
+#define  MCI_MEMORY_DATA_BYTE2          0x200
+#define  MCI_MEMORY_DATA_BYTE3          0x300
+#define  MCI_MEMORY_ADDRESS_BYTE2       0x400
+#define  MCI_MEMORY_ADDRESS_BYTE1       0x500
+#define  MCI_MEMORY_ADDRESS_BYTE0       0x600
+#define  MCI_REGISTER_DATA_BYTE0        0x800
+#define  MCI_REGISTER_DATA_BYTE1        0x900
+#define  MCI_REGISTER_DATA_BYTE2        0xA00
+#define  MCI_REGISTER_DATA_BYTE3        0xB00
+#define  MCI_REGISTER_ADDRESS_BYTE0     0xC00
+#define  MCI_REGISTER_ADDRESS_BYTE1     0xD00
+#define  MCI_REGISTER_MODE              0xE00
+
+/* Read and write modes */
+#define  MCI_MODE_REGISTER_READ         0
+#define  MCI_MODE_REGISTER_WRITE        1
+#define  MCI_MODE_MEMORY_READ           0
+#define  MCI_MODE_MEMORY_WRITE          0x40
+
+/*** Bit definitions for MC417_CTL register ****
+ bits 31-6   bits 5-4   bit 3    bits 2-1       Bit 0
++--------+-------------+--------+--------------+------------+
+|Reserved|MC417_SPD_CTL|Reserved|MC417_GPIO_SEL|UART_GPIO_EN|
++--------+-------------+--------+--------------+------------+
+***/
+#define MC417_SPD_CTL(x)	(((x) << 4) & 0x00000030)
+#define MC417_GPIO_SEL(x)	(((x) << 1) & 0x00000006)
+#define MC417_UART_GPIO_EN	0x00000001
+
+/* Values for speed control */
+#define MC417_SPD_CTL_SLOW	0x1
+#define MC417_SPD_CTL_MEDIUM	0x0
+#define MC417_SPD_CTL_FAST	0x3     /* b'1x, but we use b'11 */
+
+/* Values for GPIO select */
+#define MC417_GPIO_SEL_GPIO3	0x3
+#define MC417_GPIO_SEL_GPIO2	0x2
+#define MC417_GPIO_SEL_GPIO1	0x1
+#define MC417_GPIO_SEL_GPIO0	0x0
+
+void cx23885_mc417_init(struct cx23885_dev *dev)
+{
+	u32 regval;
+
+	dprintk(2, "%s()\n", __func__);
+
+	/* Configure MC417_CTL register to defaults. */
+	regval = MC417_SPD_CTL(MC417_SPD_CTL_FAST)	|
+		 MC417_GPIO_SEL(MC417_GPIO_SEL_GPIO3)	|
+		 MC417_UART_GPIO_EN;
+	cx_write(MC417_CTL, regval);
+
+	/* Configure MC417_OEN to defaults. */
+	regval = MC417_MIRDY;
+	cx_write(MC417_OEN, regval);
+
+	/* Configure MC417_RWD to defaults. */
+	regval = MC417_MIWR | MC417_MIRD | MC417_MICS;
+	cx_write(MC417_RWD, regval);
+}
+
+static int mc417_wait_ready(struct cx23885_dev *dev)
+{
+	u32 mi_ready;
+	unsigned long timeout = jiffies + msecs_to_jiffies(1);
+
+	for (;;) {
+		mi_ready = cx_read(MC417_RWD) & MC417_MIRDY;
+		if (mi_ready != 0)
+			return 0;
+		if (time_after(jiffies, timeout))
+			return -1;
+		udelay(1);
+	}
+}
+
+static int mc417_register_write(struct cx23885_dev *dev, u16 address, u32 value)
+{
+	u32 regval;
+
+	/* Enable MC417 GPIO outputs except for MC417_MIRDY,
+	 * which is an input.
+	 */
+	cx_write(MC417_OEN, MC417_MIRDY);
+
+	/* Write data byte 0 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0 |
+		(value & 0x000000FF);
+	cx_write(MC417_RWD, regval);
+
+	/* Transition CS/WR to effect write transaction across bus. */
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Write data byte 1 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1 |
+		((value >> 8) & 0x000000FF);
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Write data byte 2 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2 |
+		((value >> 16) & 0x000000FF);
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Write data byte 3 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3 |
+		((value >> 24) & 0x000000FF);
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Write address byte 0 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE0 |
+		(address & 0xFF);
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Write address byte 1 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE1 |
+		((address >> 8) & 0xFF);
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Indicate that this is a write. */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_MODE |
+		MCI_MODE_REGISTER_WRITE;
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Wait for the trans to complete (MC417_MIRDY asserted). */
+	return mc417_wait_ready(dev);
+}
+
+static int mc417_register_read(struct cx23885_dev *dev, u16 address, u32 *value)
+{
+	int retval;
+	u32 regval;
+	u32 tempval;
+	u32 dataval;
+
+	/* Enable MC417 GPIO outputs except for MC417_MIRDY,
+	 * which is an input.
+	 */
+	cx_write(MC417_OEN, MC417_MIRDY);
+
+	/* Write address byte 0 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE0 |
+		((address & 0x00FF));
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Write address byte 1 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE1 |
+		((address >> 8) & 0xFF);
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Indicate that this is a register read. */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_MODE |
+		MCI_MODE_REGISTER_READ;
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Wait for the trans to complete (MC417_MIRDY asserted). */
+	retval = mc417_wait_ready(dev);
+
+	/* switch the DAT0-7 GPIO[10:3] to input mode */
+	cx_write(MC417_OEN, MC417_MIRDY | MC417_MIDATA);
+
+	/* Read data byte 0 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0;
+	cx_write(MC417_RWD, regval);
+
+	/* Transition RD to effect read transaction across bus.
+	 * Transtion 0x5000 -> 0x9000 correct (RD/RDY -> WR/RDY)?
+	 * Should it be 0x9000 -> 0xF000 (also why is RDY being set, its
+	 * input only...)
+	 */
+	regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0;
+	cx_write(MC417_RWD, regval);
+
+	/* Collect byte */
+	tempval = cx_read(MC417_RWD);
+	dataval = tempval & 0x000000FF;
+
+	/* Bring CS and RD high. */
+	regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+	cx_write(MC417_RWD, regval);
+
+	/* Read data byte 1 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1;
+	cx_write(MC417_RWD, regval);
+	regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1;
+	cx_write(MC417_RWD, regval);
+	tempval = cx_read(MC417_RWD);
+	dataval |= ((tempval & 0x000000FF) << 8);
+	regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+	cx_write(MC417_RWD, regval);
+
+	/* Read data byte 2 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2;
+	cx_write(MC417_RWD, regval);
+	regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2;
+	cx_write(MC417_RWD, regval);
+	tempval = cx_read(MC417_RWD);
+	dataval |= ((tempval & 0x000000FF) << 16);
+	regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+	cx_write(MC417_RWD, regval);
+
+	/* Read data byte 3 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3;
+	cx_write(MC417_RWD, regval);
+	regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3;
+	cx_write(MC417_RWD, regval);
+	tempval = cx_read(MC417_RWD);
+	dataval |= ((tempval & 0x000000FF) << 24);
+	regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+	cx_write(MC417_RWD, regval);
+
+	*value  = dataval;
+
+	return retval;
+}
+
+int mc417_memory_write(struct cx23885_dev *dev, u32 address, u32 value)
+{
+	u32 regval;
+
+	/* Enable MC417 GPIO outputs except for MC417_MIRDY,
+	 * which is an input.
+	 */
+	cx_write(MC417_OEN, MC417_MIRDY);
+
+	/* Write data byte 0 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0 |
+		(value & 0x000000FF);
+	cx_write(MC417_RWD, regval);
+
+	/* Transition CS/WR to effect write transaction across bus. */
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Write data byte 1 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1 |
+		((value >> 8) & 0x000000FF);
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Write data byte 2 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2 |
+		((value >> 16) & 0x000000FF);
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Write data byte 3 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3 |
+		((value >> 24) & 0x000000FF);
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Write address byte 2 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE2 |
+		MCI_MODE_MEMORY_WRITE | ((address >> 16) & 0x3F);
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Write address byte 1 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE1 |
+		((address >> 8) & 0xFF);
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Write address byte 0 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE0 |
+		(address & 0xFF);
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Wait for the trans to complete (MC417_MIRDY asserted). */
+	return mc417_wait_ready(dev);
+}
+
+int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value)
+{
+	int retval;
+	u32 regval;
+	u32 tempval;
+	u32 dataval;
+
+	/* Enable MC417 GPIO outputs except for MC417_MIRDY,
+	 * which is an input.
+	 */
+	cx_write(MC417_OEN, MC417_MIRDY);
+
+	/* Write address byte 2 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE2 |
+		MCI_MODE_MEMORY_READ | ((address >> 16) & 0x3F);
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Write address byte 1 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE1 |
+		((address >> 8) & 0xFF);
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Write address byte 0 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE0 |
+		(address & 0xFF);
+	cx_write(MC417_RWD, regval);
+	regval |= MC417_MICS | MC417_MIWR;
+	cx_write(MC417_RWD, regval);
+
+	/* Wait for the trans to complete (MC417_MIRDY asserted). */
+	retval = mc417_wait_ready(dev);
+
+	/* switch the DAT0-7 GPIO[10:3] to input mode */
+	cx_write(MC417_OEN, MC417_MIRDY | MC417_MIDATA);
+
+	/* Read data byte 3 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3;
+	cx_write(MC417_RWD, regval);
+
+	/* Transition RD to effect read transaction across bus. */
+	regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3;
+	cx_write(MC417_RWD, regval);
+
+	/* Collect byte */
+	tempval = cx_read(MC417_RWD);
+	dataval = ((tempval & 0x000000FF) << 24);
+
+	/* Bring CS and RD high. */
+	regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+	cx_write(MC417_RWD, regval);
+
+	/* Read data byte 2 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2;
+	cx_write(MC417_RWD, regval);
+	regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2;
+	cx_write(MC417_RWD, regval);
+	tempval = cx_read(MC417_RWD);
+	dataval |= ((tempval & 0x000000FF) << 16);
+	regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+	cx_write(MC417_RWD, regval);
+
+	/* Read data byte 1 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1;
+	cx_write(MC417_RWD, regval);
+	regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1;
+	cx_write(MC417_RWD, regval);
+	tempval = cx_read(MC417_RWD);
+	dataval |= ((tempval & 0x000000FF) << 8);
+	regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+	cx_write(MC417_RWD, regval);
+
+	/* Read data byte 0 */
+	regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0;
+	cx_write(MC417_RWD, regval);
+	regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0;
+	cx_write(MC417_RWD, regval);
+	tempval = cx_read(MC417_RWD);
+	dataval |= (tempval & 0x000000FF);
+	regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+	cx_write(MC417_RWD, regval);
+
+	*value  = dataval;
+
+	return retval;
+}
+
+/* ------------------------------------------------------------------ */
+
+/* MPEG encoder API */
+char *cmd_to_str(int cmd)
+{
+	switch (cmd) {
+	case CX2341X_ENC_PING_FW:
+		return  "PING_FW";
+	case CX2341X_ENC_START_CAPTURE:
+		return  "START_CAPTURE";
+	case CX2341X_ENC_STOP_CAPTURE:
+		return  "STOP_CAPTURE";
+	case CX2341X_ENC_SET_AUDIO_ID:
+		return  "SET_AUDIO_ID";
+	case CX2341X_ENC_SET_VIDEO_ID:
+		return  "SET_VIDEO_ID";
+	case CX2341X_ENC_SET_PCR_ID:
+		return  "SET_PCR_PID";
+	case CX2341X_ENC_SET_FRAME_RATE:
+		return  "SET_FRAME_RATE";
+	case CX2341X_ENC_SET_FRAME_SIZE:
+		return  "SET_FRAME_SIZE";
+	case CX2341X_ENC_SET_BIT_RATE:
+		return  "SET_BIT_RATE";
+	case CX2341X_ENC_SET_GOP_PROPERTIES:
+		return  "SET_GOP_PROPERTIES";
+	case CX2341X_ENC_SET_ASPECT_RATIO:
+		return  "SET_ASPECT_RATIO";
+	case CX2341X_ENC_SET_DNR_FILTER_MODE:
+		return  "SET_DNR_FILTER_PROPS";
+	case CX2341X_ENC_SET_DNR_FILTER_PROPS:
+		return  "SET_DNR_FILTER_PROPS";
+	case CX2341X_ENC_SET_CORING_LEVELS:
+		return  "SET_CORING_LEVELS";
+	case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE:
+		return  "SET_SPATIAL_FILTER_TYPE";
+	case CX2341X_ENC_SET_VBI_LINE:
+		return  "SET_VBI_LINE";
+	case CX2341X_ENC_SET_STREAM_TYPE:
+		return  "SET_STREAM_TYPE";
+	case CX2341X_ENC_SET_OUTPUT_PORT:
+		return  "SET_OUTPUT_PORT";
+	case CX2341X_ENC_SET_AUDIO_PROPERTIES:
+		return  "SET_AUDIO_PROPERTIES";
+	case CX2341X_ENC_HALT_FW:
+		return  "HALT_FW";
+	case CX2341X_ENC_GET_VERSION:
+		return  "GET_VERSION";
+	case CX2341X_ENC_SET_GOP_CLOSURE:
+		return  "SET_GOP_CLOSURE";
+	case CX2341X_ENC_GET_SEQ_END:
+		return  "GET_SEQ_END";
+	case CX2341X_ENC_SET_PGM_INDEX_INFO:
+		return  "SET_PGM_INDEX_INFO";
+	case CX2341X_ENC_SET_VBI_CONFIG:
+		return  "SET_VBI_CONFIG";
+	case CX2341X_ENC_SET_DMA_BLOCK_SIZE:
+		return  "SET_DMA_BLOCK_SIZE";
+	case CX2341X_ENC_GET_PREV_DMA_INFO_MB_10:
+		return  "GET_PREV_DMA_INFO_MB_10";
+	case CX2341X_ENC_GET_PREV_DMA_INFO_MB_9:
+		return  "GET_PREV_DMA_INFO_MB_9";
+	case CX2341X_ENC_SCHED_DMA_TO_HOST:
+		return  "SCHED_DMA_TO_HOST";
+	case CX2341X_ENC_INITIALIZE_INPUT:
+		return  "INITIALIZE_INPUT";
+	case CX2341X_ENC_SET_FRAME_DROP_RATE:
+		return  "SET_FRAME_DROP_RATE";
+	case CX2341X_ENC_PAUSE_ENCODER:
+		return  "PAUSE_ENCODER";
+	case CX2341X_ENC_REFRESH_INPUT:
+		return  "REFRESH_INPUT";
+	case CX2341X_ENC_SET_COPYRIGHT:
+		return  "SET_COPYRIGHT";
+	case CX2341X_ENC_SET_EVENT_NOTIFICATION:
+		return  "SET_EVENT_NOTIFICATION";
+	case CX2341X_ENC_SET_NUM_VSYNC_LINES:
+		return  "SET_NUM_VSYNC_LINES";
+	case CX2341X_ENC_SET_PLACEHOLDER:
+		return  "SET_PLACEHOLDER";
+	case CX2341X_ENC_MUTE_VIDEO:
+		return  "MUTE_VIDEO";
+	case CX2341X_ENC_MUTE_AUDIO:
+		return  "MUTE_AUDIO";
+	case CX2341X_ENC_MISC:
+		return  "MISC";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+static int cx23885_mbox_func(void *priv,
+			     u32 command,
+			     int in,
+			     int out,
+			     u32 data[CX2341X_MBOX_MAX_DATA])
+{
+	struct cx23885_dev *dev = priv;
+	unsigned long timeout;
+	u32 value, flag, retval = 0;
+	int i;
+
+	dprintk(3, "%s: command(0x%X) = %s\n", __func__, command,
+		cmd_to_str(command));
+
+	/* this may not be 100% safe if we can't read any memory location
+	   without side effects */
+	mc417_memory_read(dev, dev->cx23417_mailbox - 4, &value);
+	if (value != 0x12345678) {
+		printk(KERN_ERR
+			"Firmware and/or mailbox pointer not initialized "
+			"or corrupted, signature = 0x%x, cmd = %s\n", value,
+			cmd_to_str(command));
+		return -1;
+	}
+
+	/* This read looks at 32 bits, but flag is only 8 bits.
+	 * Seems we also bail if CMD or TIMEOUT bytes are set???
+	 */
+	mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
+	if (flag) {
+		printk(KERN_ERR "ERROR: Mailbox appears to be in use "
+			"(%x), cmd = %s\n", flag, cmd_to_str(command));
+		return -1;
+	}
+
+	flag |= 1; /* tell 'em we're working on it */
+	mc417_memory_write(dev, dev->cx23417_mailbox, flag);
+
+	/* write command + args + fill remaining with zeros */
+	/* command code */
+	mc417_memory_write(dev, dev->cx23417_mailbox + 1, command);
+	mc417_memory_write(dev, dev->cx23417_mailbox + 3,
+		IVTV_API_STD_TIMEOUT); /* timeout */
+	for (i = 0; i < in; i++) {
+		mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, data[i]);
+		dprintk(3, "API Input %d = %d\n", i, data[i]);
+	}
+	for (; i < CX2341X_MBOX_MAX_DATA; i++)
+		mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, 0);
+
+	flag |= 3; /* tell 'em we're done writing */
+	mc417_memory_write(dev, dev->cx23417_mailbox, flag);
+
+	/* wait for firmware to handle the API command */
+	timeout = jiffies + msecs_to_jiffies(10);
+	for (;;) {
+		mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
+		if (0 != (flag & 4))
+			break;
+		if (time_after(jiffies, timeout)) {
+			printk(KERN_ERR "ERROR: API Mailbox timeout\n");
+			return -1;
+		}
+		udelay(10);
+	}
+
+	/* read output values */
+	for (i = 0; i < out; i++) {
+		mc417_memory_read(dev, dev->cx23417_mailbox + 4 + i, data + i);
+		dprintk(3, "API Output %d = %d\n", i, data[i]);
+	}
+
+	mc417_memory_read(dev, dev->cx23417_mailbox + 2, &retval);
+	dprintk(3, "API result = %d\n", retval);
+
+	flag = 0;
+	mc417_memory_write(dev, dev->cx23417_mailbox, flag);
+
+	return retval;
+}
+
+/* We don't need to call the API often, so using just one
+ * mailbox will probably suffice
+ */
+static int cx23885_api_cmd(struct cx23885_dev *dev,
+			   u32 command,
+			   u32 inputcnt,
+			   u32 outputcnt,
+			   ...)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	va_list vargs;
+	int i, err;
+
+	dprintk(3, "%s() cmds = 0x%08x\n", __func__, command);
+
+	va_start(vargs, outputcnt);
+	for (i = 0; i < inputcnt; i++)
+		data[i] = va_arg(vargs, int);
+
+	err = cx23885_mbox_func(dev, command, inputcnt, outputcnt, data);
+	for (i = 0; i < outputcnt; i++) {
+		int *vptr = va_arg(vargs, int *);
+		*vptr = data[i];
+	}
+	va_end(vargs);
+
+	return err;
+}
+
+static int cx23885_find_mailbox(struct cx23885_dev *dev)
+{
+	u32 signature[4] = {
+		0x12345678, 0x34567812, 0x56781234, 0x78123456
+	};
+	int signaturecnt = 0;
+	u32 value;
+	int i;
+
+	dprintk(2, "%s()\n", __func__);
+
+	for (i = 0; i < CX23885_FIRM_IMAGE_SIZE; i++) {
+		mc417_memory_read(dev, i, &value);
+		if (value == signature[signaturecnt])
+			signaturecnt++;
+		else
+			signaturecnt = 0;
+		if (4 == signaturecnt) {
+			dprintk(1, "Mailbox signature found at 0x%x\n", i+1);
+			return i+1;
+		}
+	}
+	printk(KERN_ERR "Mailbox signature values not found!\n");
+	return -1;
+}
+
+static int cx23885_load_firmware(struct cx23885_dev *dev)
+{
+	static const unsigned char magic[8] = {
+		0xa7, 0x0d, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa
+	};
+	const struct firmware *firmware;
+	int i, retval = 0;
+	u32 value = 0;
+	u32 gpio_output = 0;
+	u32 checksum = 0;
+	u32 *dataptr;
+
+	dprintk(2, "%s()\n", __func__);
+
+	/* Save GPIO settings before reset of APU */
+	retval |= mc417_memory_read(dev, 0x9020, &gpio_output);
+	retval |= mc417_memory_read(dev, 0x900C, &value);
+
+	retval  = mc417_register_write(dev,
+		IVTV_REG_VPU, 0xFFFFFFED);
+	retval |= mc417_register_write(dev,
+		IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
+	retval |= mc417_register_write(dev,
+		IVTV_REG_ENC_SDRAM_REFRESH, 0x80000800);
+	retval |= mc417_register_write(dev,
+		IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A);
+	retval |= mc417_register_write(dev,
+		IVTV_REG_APU, 0);
+
+	if (retval != 0) {
+		printk(KERN_ERR "%s: Error with mc417_register_write\n",
+			__func__);
+		return -1;
+	}
+
+	retval = request_firmware(&firmware, CX23885_FIRM_IMAGE_NAME,
+				  &dev->pci->dev);
+
+	if (retval != 0) {
+		printk(KERN_ERR
+			"ERROR: Hotplug firmware request failed (%s).\n",
+			CX2341X_FIRM_ENC_FILENAME);
+		printk(KERN_ERR "Please fix your hotplug setup, the board will "
+			"not work without firmware loaded!\n");
+		return -1;
+	}
+
+	if (firmware->size != CX23885_FIRM_IMAGE_SIZE) {
+		printk(KERN_ERR "ERROR: Firmware size mismatch "
+			"(have %zd, expected %d)\n",
+			firmware->size, CX23885_FIRM_IMAGE_SIZE);
+		release_firmware(firmware);
+		return -1;
+	}
+
+	if (0 != memcmp(firmware->data, magic, 8)) {
+		printk(KERN_ERR
+			"ERROR: Firmware magic mismatch, wrong file?\n");
+		release_firmware(firmware);
+		return -1;
+	}
+
+	/* transfer to the chip */
+	dprintk(2, "Loading firmware ...\n");
+	dataptr = (u32 *)firmware->data;
+	for (i = 0; i < (firmware->size >> 2); i++) {
+		value = *dataptr;
+		checksum += ~value;
+		if (mc417_memory_write(dev, i, value) != 0) {
+			printk(KERN_ERR "ERROR: Loading firmware failed!\n");
+			release_firmware(firmware);
+			return -1;
+		}
+		dataptr++;
+	}
+
+	/* read back to verify with the checksum */
+	dprintk(1, "Verifying firmware ...\n");
+	for (i--; i >= 0; i--) {
+		if (mc417_memory_read(dev, i, &value) != 0) {
+			printk(KERN_ERR "ERROR: Reading firmware failed!\n");
+			release_firmware(firmware);
+			return -1;
+		}
+		checksum -= ~value;
+	}
+	if (checksum) {
+		printk(KERN_ERR
+			"ERROR: Firmware load failed (checksum mismatch).\n");
+		release_firmware(firmware);
+		return -1;
+	}
+	release_firmware(firmware);
+	dprintk(1, "Firmware upload successful.\n");
+
+	retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS,
+		IVTV_CMD_HW_BLOCKS_RST);
+
+	/* Restore GPIO settings, make sure EIO14 is enabled as an output. */
+	dprintk(2, "%s: GPIO output EIO 0-15 was = 0x%x\n",
+		__func__, gpio_output);
+	/* Power-up seems to have GPIOs AFU. This was causing digital side
+	 * to fail at power-up. Seems GPIOs should be set to 0x10ff0411 at
+	 * power-up.
+	 * gpio_output |= (1<<14);
+	 */
+	/* Note: GPIO14 is specific to the HVR1800 here */
+	gpio_output = 0x10ff0411 | (1<<14);
+	retval |= mc417_register_write(dev, 0x9020, gpio_output | (1<<14));
+	dprintk(2, "%s: GPIO output EIO 0-15 now = 0x%x\n",
+		__func__, gpio_output);
+
+	dprintk(1, "%s: GPIO value  EIO 0-15 was = 0x%x\n",
+		__func__, value);
+	value |= (1<<14);
+	dprintk(1, "%s: GPIO value  EIO 0-15 now = 0x%x\n",
+		__func__, value);
+	retval |= mc417_register_write(dev, 0x900C, value);
+
+	retval |= mc417_register_read(dev, IVTV_REG_VPU, &value);
+	retval |= mc417_register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8);
+
+	if (retval < 0)
+		printk(KERN_ERR "%s: Error with mc417_register_write\n",
+			__func__);
+	return 0;
+}
+
+void cx23885_417_check_encoder(struct cx23885_dev *dev)
+{
+	u32 status, seq;
+
+	status = seq = 0;
+	cx23885_api_cmd(dev, CX2341X_ENC_GET_SEQ_END, 0, 2, &status, &seq);
+	dprintk(1, "%s() status = %d, seq = %d\n", __func__, status, seq);
+}
+
+static void cx23885_codec_settings(struct cx23885_dev *dev)
+{
+	dprintk(1, "%s()\n", __func__);
+
+	/* assign frame size */
+	cx23885_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
+				dev->ts1.height, dev->ts1.width);
+
+	dev->mpeg_params.width = dev->ts1.width;
+	dev->mpeg_params.height = dev->ts1.height;
+	dev->mpeg_params.is_50hz =
+		(dev->encodernorm.id & V4L2_STD_625_50) != 0;
+
+	cx2341x_update(dev, cx23885_mbox_func, NULL, &dev->mpeg_params);
+
+	cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1);
+	cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1);
+}
+
+static int cx23885_initialize_codec(struct cx23885_dev *dev)
+{
+	int version;
+	int retval;
+	u32 i, data[7];
+
+	dprintk(1, "%s()\n", __func__);
+
+	retval = cx23885_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
+	if (retval < 0) {
+		dprintk(2, "%s() PING OK\n", __func__);
+		retval = cx23885_load_firmware(dev);
+		if (retval < 0) {
+			printk(KERN_ERR "%s() f/w load failed\n", __func__);
+			return retval;
+		}
+		dev->cx23417_mailbox = cx23885_find_mailbox(dev);
+		if (dev->cx23417_mailbox < 0) {
+			printk(KERN_ERR "%s() mailbox < 0, error\n",
+				__func__);
+			return -1;
+		}
+		retval = cx23885_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0);
+		if (retval < 0) {
+			printk(KERN_ERR
+				"ERROR: cx23417 firmware ping failed!\n");
+			return -1;
+		}
+		retval = cx23885_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1,
+			&version);
+		if (retval < 0) {
+			printk(KERN_ERR "ERROR: cx23417 firmware get encoder :"
+				"version failed!\n");
+			return -1;
+		}
+		dprintk(1, "cx23417 firmware version is 0x%08x\n", version);
+		msleep(200);
+	}
+
+	cx23885_codec_settings(dev);
+	msleep(60);
+
+	cx23885_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0,
+		CX23885_FIELD1_SAA7115, CX23885_FIELD2_SAA7115);
+	cx23885_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0,
+		CX23885_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0);
+
+	/* Setup to capture VBI */
+	data[0] = 0x0001BD00;
+	data[1] = 1;          /* frames per interrupt */
+	data[2] = 4;          /* total bufs */
+	data[3] = 0x91559155; /* start codes */
+	data[4] = 0x206080C0; /* stop codes */
+	data[5] = 6;          /* lines */
+	data[6] = 64;         /* BPL */
+
+	cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_CONFIG, 7, 0, data[0], data[1],
+		data[2], data[3], data[4], data[5], data[6]);
+
+	for (i = 2; i <= 24; i++) {
+		int valid;
+
+		valid = ((i >= 19) && (i <= 21));
+		cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0, i,
+				valid, 0 , 0, 0);
+		cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0,
+				i | 0x80000000, valid, 0, 0, 0);
+	}
+
+	cx23885_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, CX23885_UNMUTE);
+	msleep(60);
+
+	/* initialize the video input */
+	cx23885_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
+	msleep(60);
+
+	/* Enable VIP style pixel invalidation so we work with scaled mode */
+	mc417_memory_write(dev, 2120, 0x00000080);
+
+	/* start capturing to the host interface */
+	cx23885_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
+		CX23885_MPEG_CAPTURE, CX23885_RAW_BITS_NONE);
+	msleep(10);
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int bb_buf_setup(struct videobuf_queue *q,
+	unsigned int *count, unsigned int *size)
+{
+	struct cx23885_fh *fh = q->priv_data;
+
+	fh->dev->ts1.ts_packet_size  = mpeglinesize;
+	fh->dev->ts1.ts_packet_count = mpeglines;
+
+	*size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count;
+	*count = mpegbufs;
+
+	return 0;
+}
+
+static int bb_buf_prepare(struct videobuf_queue *q,
+	struct videobuf_buffer *vb, enum v4l2_field field)
+{
+	struct cx23885_fh *fh = q->priv_data;
+	return cx23885_buf_prepare(q, &fh->dev->ts1,
+		(struct cx23885_buffer *)vb,
+		field);
+}
+
+static void bb_buf_queue(struct videobuf_queue *q,
+	struct videobuf_buffer *vb)
+{
+	struct cx23885_fh *fh = q->priv_data;
+	cx23885_buf_queue(&fh->dev->ts1, (struct cx23885_buffer *)vb);
+}
+
+static void bb_buf_release(struct videobuf_queue *q,
+	struct videobuf_buffer *vb)
+{
+	cx23885_free_buffer(q, (struct cx23885_buffer *)vb);
+}
+
+static struct videobuf_queue_ops cx23885_qops = {
+	.buf_setup    = bb_buf_setup,
+	.buf_prepare  = bb_buf_prepare,
+	.buf_queue    = bb_buf_queue,
+	.buf_release  = bb_buf_release,
+};
+
+/* ------------------------------------------------------------------ */
+
+static const u32 *ctrl_classes[] = {
+	cx2341x_mpeg_ctrls,
+	NULL
+};
+
+static int cx23885_queryctrl(struct cx23885_dev *dev,
+	struct v4l2_queryctrl *qctrl)
+{
+	qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
+	if (qctrl->id == 0)
+		return -EINVAL;
+
+	/* MPEG V4L2 controls */
+	if (cx2341x_ctrl_query(&dev->mpeg_params, qctrl))
+		qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+
+	return 0;
+}
+
+static int cx23885_querymenu(struct cx23885_dev *dev,
+	struct v4l2_querymenu *qmenu)
+{
+	struct v4l2_queryctrl qctrl;
+
+	qctrl.id = qmenu->id;
+	cx23885_queryctrl(dev, &qctrl);
+	return v4l2_ctrl_query_menu(qmenu, &qctrl,
+		cx2341x_ctrl_get_menu(qmenu->id));
+}
+
+int cx23885_do_ioctl(struct inode *inode, struct file *file, int radio,
+	struct cx23885_dev *dev, unsigned int cmd, void *arg,
+	v4l2_kioctl driver_ioctl)
+{
+	int err;
+
+	switch (cmd) {
+	/* ---------- tv norms ---------- */
+	case VIDIOC_ENUMSTD:
+	{
+		struct v4l2_standard *e = arg;
+		unsigned int i;
+
+		i = e->index;
+		if (i >= ARRAY_SIZE(cx23885_tvnorms))
+			return -EINVAL;
+		err = v4l2_video_std_construct(e,
+			cx23885_tvnorms[e->index].id,
+			cx23885_tvnorms[e->index].name);
+		e->index = i;
+		if (err < 0)
+			return err;
+		return 0;
+	}
+	case VIDIOC_G_STD:
+	{
+		v4l2_std_id *id = arg;
+
+		*id = dev->encodernorm.id;
+		return 0;
+	}
+	case VIDIOC_S_STD:
+	{
+		v4l2_std_id *id = arg;
+		unsigned int i;
+
+		for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++)
+			if (*id & cx23885_tvnorms[i].id)
+				break;
+		if (i == ARRAY_SIZE(cx23885_tvnorms))
+			return -EINVAL;
+		dev->encodernorm = cx23885_tvnorms[i];
+
+		return 0;
+	}
+
+	/* ------ input switching ---------- */
+	case VIDIOC_ENUMINPUT:
+	{
+		struct cx23885_input *input;
+		struct v4l2_input *i = arg;
+		unsigned int n;
+
+		n = i->index;
+		if (n >= 4)
+			return -EINVAL;
+		input = &cx23885_boards[dev->board].input[n];
+		if (input->type == 0)
+			return -EINVAL;
+		memset(i, 0, sizeof(*i));
+		i->index = n;
+		/* FIXME
+		 * strcpy(i->name, input->name); */
+		strcpy(i->name, "unset");
+		if (input->type == CX23885_VMUX_TELEVISION ||
+		    input->type == CX23885_VMUX_CABLE)
+			i->type = V4L2_INPUT_TYPE_TUNER;
+		else
+			i->type  = V4L2_INPUT_TYPE_CAMERA;
+
+		for (n = 0; n < ARRAY_SIZE(cx23885_tvnorms); n++)
+			i->std |= cx23885_tvnorms[n].id;
+		return 0;
+	}
+	case VIDIOC_G_INPUT:
+	{
+		unsigned int *i = arg;
+
+		*i = dev->input;
+		return 0;
+	}
+	case VIDIOC_S_INPUT:
+	{
+		unsigned int *i = arg;
+
+		if (*i >= 4)
+			return -EINVAL;
+
+		return 0;
+	}
+
+	/* --- tuner ioctls ------------------------------------------ */
+	case VIDIOC_G_TUNER:
+	{
+		struct v4l2_tuner *t = arg;
+
+		if (UNSET == dev->tuner_type)
+			return -EINVAL;
+		if (0 != t->index)
+			return -EINVAL;
+		memset(t, 0, sizeof(*t));
+		strcpy(t->name, "Television");
+		cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_TUNER, t);
+		cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_TUNER, t);
+
+		dprintk(1, "VIDIOC_G_TUNER: tuner type %d\n", t->type);
+
+		return 0;
+	}
+	case VIDIOC_S_TUNER:
+	{
+		struct v4l2_tuner *t = arg;
+
+		if (UNSET == dev->tuner_type)
+			return -EINVAL;
+
+		/* Update the A/V core */
+		cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_TUNER, t);
+
+		return 0;
+	}
+	case VIDIOC_G_FREQUENCY:
+	{
+		struct v4l2_frequency *f = arg;
+
+		memset(f, 0, sizeof(*f));
+		if (UNSET == dev->tuner_type)
+			return -EINVAL;
+		f->type = V4L2_TUNER_ANALOG_TV;
+		f->frequency = dev->freq;
+
+		/* Assumption that tuner is always on bus 1 */
+		cx23885_call_i2c_clients(&dev->i2c_bus[1],
+			VIDIOC_G_FREQUENCY, f);
+
+		return 0;
+	}
+	case VIDIOC_S_FREQUENCY:
+	{
+		struct v4l2_frequency *f = arg;
+
+		dprintk(1, "VIDIOC_S_FREQUENCY: dev type %d, f\n",
+			dev->tuner_type);
+		dprintk(1, "VIDIOC_S_FREQUENCY: f tuner %d, f type %d\n",
+			f->tuner, f->type);
+		if (UNSET == dev->tuner_type)
+			return -EINVAL;
+		if (f->tuner != 0)
+			return -EINVAL;
+		if (f->type != V4L2_TUNER_ANALOG_TV)
+			return -EINVAL;
+		dev->freq = f->frequency;
+
+		/* Assumption that tuner is always on bus 1 */
+		cx23885_call_i2c_clients(&dev->i2c_bus[1],
+			VIDIOC_S_FREQUENCY, f);
+		return 0;
+	}
+	case VIDIOC_S_CTRL:
+	{
+		/* Update the A/V core */
+		cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_CTRL, arg);
+		return 0;
+	}
+	default:
+		/* Convert V4L ioctl to V4L2 and call mpeg_do_ioctl
+		 * (driver_ioctl) */
+		return v4l_compat_translate_ioctl(inode, file, cmd, arg,
+						  driver_ioctl);
+	}
+
+	return 0;
+}
+
+static int mpeg_do_ioctl(struct inode *inode, struct file *file,
+			 unsigned int cmd, void *arg)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
+	struct cx23885_tsport  *tsport = &dev->ts1;
+
+	if (v4l_debug > 1)
+		v4l_print_ioctl(dev->name, cmd);
+
+	switch (cmd) {
+
+	/* --- capabilities ------------------------------------------ */
+	case VIDIOC_QUERYCAP:
+	{
+		struct v4l2_capability *cap = arg;
+
+		memset(cap, 0, sizeof(*cap));
+		strcpy(cap->driver, dev->name);
+		strlcpy(cap->card, cx23885_boards[tsport->dev->board].name,
+			sizeof(cap->card));
+		sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+		cap->version = CX23885_VERSION_CODE;
+		cap->capabilities =
+			V4L2_CAP_VIDEO_CAPTURE |
+			V4L2_CAP_READWRITE     |
+			V4L2_CAP_STREAMING     |
+			0;
+		if (UNSET != dev->tuner_type)
+			cap->capabilities |= V4L2_CAP_TUNER;
+
+		return 0;
+	}
+
+	/* --- capture ioctls ---------------------------------------- */
+	case VIDIOC_ENUM_FMT:
+	{
+		struct v4l2_fmtdesc *f = arg;
+		int index;
+
+		index = f->index;
+		if (index != 0)
+			return -EINVAL;
+
+		memset(f, 0, sizeof(*f));
+		f->index = index;
+		strlcpy(f->description, "MPEG", sizeof(f->description));
+		f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		f->pixelformat = V4L2_PIX_FMT_MPEG;
+		return 0;
+	}
+	case VIDIOC_G_FMT:
+	{
+		struct v4l2_format *f = arg;
+
+		memset(f, 0, sizeof(*f));
+		f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+		f->fmt.pix.bytesperline = 0;
+		f->fmt.pix.sizeimage    =
+			dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
+		f->fmt.pix.colorspace   = 0;
+		f->fmt.pix.width        = dev->ts1.width;
+		f->fmt.pix.height       = dev->ts1.height;
+		f->fmt.pix.field        = fh->mpegq.field;
+		dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
+			dev->ts1.width, dev->ts1.height, fh->mpegq.field);
+		return 0;
+	}
+	case VIDIOC_TRY_FMT:
+	{
+		struct v4l2_format *f = arg;
+
+		f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+		f->fmt.pix.bytesperline = 0;
+		f->fmt.pix.sizeimage    =
+			dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
+		f->fmt.pix.sizeimage    =
+		f->fmt.pix.colorspace   = 0;
+		dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
+			dev->ts1.width, dev->ts1.height, fh->mpegq.field);
+		return 0;
+	}
+	case VIDIOC_S_FMT:
+	{
+		struct v4l2_format *f = arg;
+
+		f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+		f->fmt.pix.bytesperline = 0;
+		f->fmt.pix.sizeimage    =
+			dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
+		f->fmt.pix.colorspace   = 0;
+		dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
+			f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
+		return 0;
+	}
+
+	/* --- streaming capture ------------------------------------- */
+	case VIDIOC_REQBUFS:
+		return videobuf_reqbufs(&fh->mpegq, arg);
+
+	case VIDIOC_QUERYBUF:
+		return videobuf_querybuf(&fh->mpegq, arg);
+
+	case VIDIOC_QBUF:
+		return videobuf_qbuf(&fh->mpegq, arg);
+
+	case VIDIOC_DQBUF:
+		return videobuf_dqbuf(&fh->mpegq, arg,
+				      file->f_flags & O_NONBLOCK);
+
+	case VIDIOC_STREAMON:
+		return videobuf_streamon(&fh->mpegq);
+
+	case VIDIOC_STREAMOFF:
+		return videobuf_streamoff(&fh->mpegq);
+
+	case VIDIOC_G_EXT_CTRLS:
+	{
+		struct v4l2_ext_controls *f = arg;
+
+		if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+			return -EINVAL;
+		return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, cmd);
+	}
+	case VIDIOC_S_EXT_CTRLS:
+	case VIDIOC_TRY_EXT_CTRLS:
+	{
+		struct v4l2_ext_controls *f = arg;
+		struct cx2341x_mpeg_params p;
+		int err;
+
+		if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+			return -EINVAL;
+		p = dev->mpeg_params;
+		err = cx2341x_ext_ctrls(&p, 0, f, cmd);
+		if (err == 0 && cmd == VIDIOC_S_EXT_CTRLS) {
+			err = cx2341x_update(dev, cx23885_mbox_func,
+				&dev->mpeg_params, &p);
+			dev->mpeg_params = p;
+		}
+		return err;
+	}
+	case VIDIOC_S_FREQUENCY:
+	{
+		cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+			CX23885_END_NOW, CX23885_MPEG_CAPTURE,
+			CX23885_RAW_BITS_NONE);
+		cx23885_do_ioctl(inode, file, 0, dev, cmd, arg,
+			mpeg_do_ioctl);
+		cx23885_initialize_codec(dev);
+
+		return 0;
+	}
+	case VIDIOC_LOG_STATUS:
+	{
+		char name[32 + 2];
+
+		snprintf(name, sizeof(name), "%s/2", dev->name);
+		printk(KERN_INFO
+			"%s/2: ============  START LOG STATUS  ============\n",
+		       dev->name);
+		cx23885_call_i2c_clients(&dev->i2c_bus[0], VIDIOC_LOG_STATUS,
+			NULL);
+		cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_LOG_STATUS,
+			NULL);
+		cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_LOG_STATUS,
+			NULL);
+		cx2341x_log_status(&dev->mpeg_params, name);
+		printk(KERN_INFO
+			"%s/2: =============  END LOG STATUS  =============\n",
+		       dev->name);
+		return 0;
+	}
+	case VIDIOC_QUERYMENU:
+		return cx23885_querymenu(dev, arg);
+	case VIDIOC_QUERYCTRL:
+	{
+		struct v4l2_queryctrl *c = arg;
+
+		return cx23885_queryctrl(dev, c);
+	}
+
+	default:
+		return cx23885_do_ioctl(inode, file, 0, dev, cmd, arg,
+				mpeg_do_ioctl);
+	}
+	return 0;
+}
+
+static int mpeg_ioctl(struct inode *inode, struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	return video_usercopy(inode, file, cmd, arg, mpeg_do_ioctl);
+}
+
+static int mpeg_open(struct inode *inode, struct file *file)
+{
+	int minor = iminor(inode);
+	struct cx23885_dev *h, *dev = NULL;
+	struct list_head *list;
+	struct cx23885_fh *fh;
+
+	dprintk(2, "%s()\n", __func__);
+
+	list_for_each(list, &cx23885_devlist) {
+		h = list_entry(list, struct cx23885_dev, devlist);
+		if (h->v4l_device->minor == minor) {
+			dev = h;
+			break;
+		}
+	}
+
+	if (dev == NULL)
+		return -ENODEV;
+
+	/* allocate + initialize per filehandle data */
+	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+	if (NULL == fh)
+		return -ENOMEM;
+
+	file->private_data = fh;
+	fh->dev      = dev;
+
+	videobuf_queue_sg_init(&fh->mpegq, &cx23885_qops,
+			    &dev->pci->dev, &dev->ts1.slock,
+			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			    V4L2_FIELD_INTERLACED,
+			    sizeof(struct cx23885_buffer),
+			    fh);
+
+	return 0;
+}
+
+static int mpeg_release(struct inode *inode, struct file *file)
+{
+	struct cx23885_fh  *fh  = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
+
+	dprintk(2, "%s()\n", __func__);
+
+	/* FIXME: Review this crap */
+	/* Shut device down on last close */
+	if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) {
+		if (atomic_dec_return(&dev->v4l_reader_count) == 0) {
+			/* stop mpeg capture */
+			cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+				CX23885_END_NOW, CX23885_MPEG_CAPTURE,
+				CX23885_RAW_BITS_NONE);
+
+			msleep(500);
+			cx23885_417_check_encoder(dev);
+
+			cx23885_cancel_buffers(&fh->dev->ts1);
+		}
+	}
+
+	if (fh->mpegq.streaming)
+		videobuf_streamoff(&fh->mpegq);
+	if (fh->mpegq.reading)
+		videobuf_read_stop(&fh->mpegq);
+
+	videobuf_mmap_free(&fh->mpegq);
+	file->private_data = NULL;
+	kfree(fh);
+
+	return 0;
+}
+
+static ssize_t mpeg_read(struct file *file, char __user *data,
+	size_t count, loff_t *ppos)
+{
+	struct cx23885_fh *fh = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
+
+	dprintk(2, "%s()\n", __func__);
+
+	/* Deal w/ A/V decoder * and mpeg encoder sync issues. */
+	/* Start mpeg encoder on first read. */
+	if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
+		if (atomic_inc_return(&dev->v4l_reader_count) == 1) {
+			if (cx23885_initialize_codec(dev) < 0)
+				return -EINVAL;
+		}
+	}
+
+	return videobuf_read_stream(&fh->mpegq, data, count, ppos, 0,
+				    file->f_flags & O_NONBLOCK);
+}
+
+static unsigned int mpeg_poll(struct file *file,
+	struct poll_table_struct *wait)
+{
+	struct cx23885_fh *fh = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
+
+	dprintk(2, "%s\n", __func__);
+
+	return videobuf_poll_stream(file, &fh->mpegq, wait);
+}
+
+static int mpeg_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct cx23885_fh *fh = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
+
+	dprintk(2, "%s()\n", __func__);
+
+	return videobuf_mmap_mapper(&fh->mpegq, vma);
+}
+
+static struct file_operations mpeg_fops = {
+	.owner	       = THIS_MODULE,
+	.open	       = mpeg_open,
+	.release       = mpeg_release,
+	.read	       = mpeg_read,
+	.poll          = mpeg_poll,
+	.mmap	       = mpeg_mmap,
+	.ioctl	       = mpeg_ioctl,
+	.llseek        = no_llseek,
+};
+
+static struct video_device cx23885_mpeg_template = {
+	.name          = "cx23885",
+	.type          = VID_TYPE_CAPTURE |
+				VID_TYPE_TUNER |
+				VID_TYPE_SCALES |
+				VID_TYPE_MPEG_ENCODER,
+	.fops          = &mpeg_fops,
+	.minor         = -1,
+};
+
+void cx23885_417_unregister(struct cx23885_dev *dev)
+{
+	dprintk(1, "%s()\n", __func__);
+
+	if (dev->v4l_device) {
+		if (-1 != dev->v4l_device->minor)
+			video_unregister_device(dev->v4l_device);
+		else
+			video_device_release(dev->v4l_device);
+		dev->v4l_device = NULL;
+	}
+}
+
+static struct video_device *cx23885_video_dev_alloc(
+	struct cx23885_tsport *tsport,
+	struct pci_dev *pci,
+	struct video_device *template,
+	char *type)
+{
+	struct video_device *vfd;
+	struct cx23885_dev *dev = tsport->dev;
+
+	dprintk(1, "%s()\n", __func__);
+
+	vfd = video_device_alloc();
+	if (NULL == vfd)
+		return NULL;
+	*vfd = *template;
+	vfd->minor   = -1;
+	snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
+		type, cx23885_boards[tsport->dev->board].name);
+	vfd->dev     = &pci->dev;
+	vfd->release = video_device_release;
+	return vfd;
+}
+
+int cx23885_417_register(struct cx23885_dev *dev)
+{
+	/* FIXME: Port1 hardcoded here */
+	int err = -ENODEV;
+	struct cx23885_tsport *tsport = &dev->ts1;
+
+	dprintk(1, "%s()\n", __func__);
+
+	if (cx23885_boards[dev->board].portb != CX23885_MPEG_ENCODER)
+		return err;
+
+	/* Set default TV standard */
+	dev->encodernorm = cx23885_tvnorms[0];
+
+	if (dev->encodernorm.id & V4L2_STD_525_60)
+		tsport->height = 480;
+	else
+		tsport->height = 576;
+
+	tsport->width = 720;
+	cx2341x_fill_defaults(&dev->mpeg_params);
+
+	dev->mpeg_params.port = CX2341X_PORT_SERIAL;
+
+	/* Allocate and initialize V4L video device */
+	dev->v4l_device = cx23885_video_dev_alloc(tsport,
+		dev->pci, &cx23885_mpeg_template, "mpeg");
+	err = video_register_device(dev->v4l_device,
+		VFL_TYPE_GRABBER, -1);
+	if (err < 0) {
+		printk(KERN_INFO "%s: can't register mpeg device\n", dev->name);
+		return err;
+	}
+
+	/* Initialize MC417 registers */
+	cx23885_mc417_init(dev);
+
+	printk(KERN_INFO "%s: registered device video%d [mpeg]\n",
+	       dev->name, dev->v4l_device->minor & 0x1f);
+
+	return 0;
+}
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
index dfa2698..6ebf587 100644
--- a/drivers/media/video/cx23885/cx23885-cards.c
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -73,6 +73,7 @@
 	[CX23885_BOARD_HAUPPAUGE_HVR1800] = {
 		.name		= "Hauppauge WinTV-HVR1800",
 		.porta		= CX23885_ANALOG_VIDEO,
+		.portb		= CX23885_MPEG_ENCODER,
 		.portc		= CX23885_MPEG_DVB,
 		.tuner_type	= TUNER_PHILIPS_TDA8290,
 		.tuner_addr	= 0x42, /* 0x84 >> 1 */
@@ -130,6 +131,18 @@
 		.name		= "Hauppauge WinTV-HVR1500",
 		.portc		= CX23885_MPEG_DVB,
 	},
+	[CX23885_BOARD_HAUPPAUGE_HVR1200] = {
+		.name		= "Hauppauge WinTV-HVR1200",
+		.portc		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_HAUPPAUGE_HVR1700] = {
+		.name		= "Hauppauge WinTV-HVR1700",
+		.portc		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_HAUPPAUGE_HVR1400] = {
+		.name		= "Hauppauge WinTV-HVR1400",
+		.portc		= CX23885_MPEG_DVB,
+	},
 };
 const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
 
@@ -181,6 +194,18 @@
 		.subvendor = 0x0070,
 		.subdevice = 0x7717,
 		.card      = CX23885_BOARD_HAUPPAUGE_HVR1500,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x71d1,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1200,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x8101,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1700,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x8010,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1400,
 	},
 };
 const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -235,6 +260,12 @@
 	case 79561: /* WinTV-HVR1250 (PCIe, OEM, No IR, half height, ATSC and Basic analog */
 	case 79571: /* WinTV-HVR1250 (PCIe, OEM, No IR, full height, ATSC and Basic analog */
 	case 79671: /* WinTV-HVR1250 (PCIe, OEM, No IR, half height, ATSC and Basic analog */
+	case 80019:
+		/* WinTV-HVR1400 (Express Card, Retail, IR,
+		 * DVB-T and Basic analog */
+	case 81519:
+		/* WinTV-HVR1700 (PCIe, Retail, No IR, half height,
+		 * DVB-T and MPEG2 HW Encoder */
 		break;
 	default:
 		printk("%s: warning: unknown hauppauge model #%d\n", dev->name, tv.model);
@@ -264,7 +295,7 @@
 		}
 		else {
 			printk(KERN_ERR
-				"%s(): Unknow command.\n", __FUNCTION__);
+				"%s(): Unknow command.\n", __func__);
 			return -EINVAL;
 		}
 		break;
@@ -306,6 +337,10 @@
 		/* GPIO-15-18 cx23417 READY, CS, RD, WR */
 		/* GPIO-19 IR_RX */
 
+		/* CX23417 GPIO's */
+		/* EIO15 Zilog Reset */
+		/* EIO14 S5H1409/CX24227 Reset */
+
 		/* Force the TDA8295A into reset and back */
 		cx_set(GP0_IO, 0x00040004);
 		mdelay(20);
@@ -314,6 +349,50 @@
 		cx_set(GP0_IO, 0x00040004);
 		mdelay(20);
 		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1200:
+		/* GPIO-0 tda10048 demodulator reset */
+		/* GPIO-2 tda18271 tuner reset */
+
+		/* Put the parts into reset and back */
+		cx_set(GP0_IO, 0x00050000);
+		mdelay(20);
+		cx_clear(GP0_IO, 0x00000005);
+		mdelay(20);
+		cx_set(GP0_IO, 0x00050005);
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1700:
+		/* GPIO-0 TDA10048 demodulator reset */
+		/* GPIO-2 TDA8295A Reset */
+		/* GPIO-3-10 cx23417 data0-7 */
+		/* GPIO-11-14 cx23417 addr0-3 */
+		/* GPIO-15-18 cx23417 READY, CS, RD, WR */
+
+		/* The following GPIO's are on the interna AVCore (cx25840) */
+		/* GPIO-19 IR_RX */
+		/* GPIO-20 IR_TX 416/DVBT Select */
+		/* GPIO-21 IIS DAT */
+		/* GPIO-22 IIS WCLK */
+		/* GPIO-23 IIS BCLK */
+
+		/* Put the parts into reset and back */
+		cx_set(GP0_IO, 0x00050000);
+		mdelay(20);
+		cx_clear(GP0_IO, 0x00000005);
+		mdelay(20);
+		cx_set(GP0_IO, 0x00050005);
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1400:
+		/* GPIO-0  Dibcom7000p demodulator reset */
+		/* GPIO-2  xc3028L tuner reset */
+		/* GPIO-13 LED */
+
+		/* Put the parts into reset and back */
+		cx_set(GP0_IO, 0x00050000);
+		mdelay(20);
+		cx_clear(GP0_IO, 0x00000005);
+		mdelay(20);
+		cx_set(GP0_IO, 0x00050005);
+		break;
 	}
 }
 
@@ -324,6 +403,8 @@
 	case CX23885_BOARD_HAUPPAUGE_HVR1500:
 	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
 	case CX23885_BOARD_HAUPPAUGE_HVR1800:
+	case CX23885_BOARD_HAUPPAUGE_HVR1200:
+	case CX23885_BOARD_HAUPPAUGE_HVR1400:
 		/* FIXME: Implement me */
 		break;
 	}
@@ -348,11 +429,14 @@
 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
 	case CX23885_BOARD_HAUPPAUGE_HVR1500:
 	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
+	case CX23885_BOARD_HAUPPAUGE_HVR1400:
 		if (dev->i2c_bus[0].i2c_rc == 0)
 			hauppauge_eeprom(dev, eeprom+0x80);
 		break;
 	case CX23885_BOARD_HAUPPAUGE_HVR1800:
 	case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+	case CX23885_BOARD_HAUPPAUGE_HVR1200:
+	case CX23885_BOARD_HAUPPAUGE_HVR1700:
 		if (dev->i2c_bus[0].i2c_rc == 0)
 			hauppauge_eeprom(dev, eeprom+0xc0);
 		break;
@@ -364,17 +448,45 @@
 		ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
 		ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
 		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1800:
+		/* Defaults for VID B - Analog encoder */
+		/* DREQ_POL, SMODE, PUNC_CLK, MCLK_POL Serial bus + punc clk */
+		ts1->gen_ctrl_val    = 0x10e;
+		ts1->ts_clk_en_val   = 0x1; /* Enable TS_CLK */
+		ts1->src_sel_val     = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+
+		/* APB_TSVALERR_POL (active low)*/
+		ts1->vld_misc_val    = 0x2000;
+		ts1->hw_sop_ctrl_val = (0x47 << 16 | 188 << 4 | 0xc);
+
+		/* Defaults for VID C */
+		ts2->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
+		ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+		ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+		break;
 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
 	case CX23885_BOARD_HAUPPAUGE_HVR1500:
 	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
-	case CX23885_BOARD_HAUPPAUGE_HVR1800:
 	case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+	case CX23885_BOARD_HAUPPAUGE_HVR1200:
+	case CX23885_BOARD_HAUPPAUGE_HVR1700:
+	case CX23885_BOARD_HAUPPAUGE_HVR1400:
 	default:
 		ts2->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
 		ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
 		ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
 	}
 
+	/* Certain boards support analog, or require the avcore to be
+	 * loaded, ensure this happens.
+	 */
+	switch (dev->board) {
+	case CX23885_BOARD_HAUPPAUGE_HVR1800:
+	case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+	case CX23885_BOARD_HAUPPAUGE_HVR1700:
+		request_module("cx25840");
+		break;
+	}
 }
 
 /* ------------------------------------------------------------------ */
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
index 7f10b27..f24abcd 100644
--- a/drivers/media/video/cx23885/cx23885-core.c
+++ b/drivers/media/video/cx23885/cx23885-core.c
@@ -190,25 +190,25 @@
 static int cx23885_risc_decode(u32 risc)
 {
 	static char *instr[16] = {
-		[ RISC_SYNC    >> 28 ] = "sync",
-		[ RISC_WRITE   >> 28 ] = "write",
-		[ RISC_WRITEC  >> 28 ] = "writec",
-		[ RISC_READ    >> 28 ] = "read",
-		[ RISC_READC   >> 28 ] = "readc",
-		[ RISC_JUMP    >> 28 ] = "jump",
-		[ RISC_SKIP    >> 28 ] = "skip",
-		[ RISC_WRITERM >> 28 ] = "writerm",
-		[ RISC_WRITECM >> 28 ] = "writecm",
-		[ RISC_WRITECR >> 28 ] = "writecr",
+		[RISC_SYNC    >> 28] = "sync",
+		[RISC_WRITE   >> 28] = "write",
+		[RISC_WRITEC  >> 28] = "writec",
+		[RISC_READ    >> 28] = "read",
+		[RISC_READC   >> 28] = "readc",
+		[RISC_JUMP    >> 28] = "jump",
+		[RISC_SKIP    >> 28] = "skip",
+		[RISC_WRITERM >> 28] = "writerm",
+		[RISC_WRITECM >> 28] = "writecm",
+		[RISC_WRITECR >> 28] = "writecr",
 	};
 	static int incr[16] = {
-		[ RISC_WRITE   >> 28 ] = 3,
-		[ RISC_JUMP    >> 28 ] = 3,
-		[ RISC_SKIP    >> 28 ] = 1,
-		[ RISC_SYNC    >> 28 ] = 1,
-		[ RISC_WRITERM >> 28 ] = 3,
-		[ RISC_WRITECM >> 28 ] = 3,
-		[ RISC_WRITECR >> 28 ] = 4,
+		[RISC_WRITE   >> 28] = 3,
+		[RISC_JUMP    >> 28] = 3,
+		[RISC_SKIP    >> 28] = 1,
+		[RISC_SYNC    >> 28] = 1,
+		[RISC_WRITERM >> 28] = 3,
+		[RISC_WRITECM >> 28] = 3,
+		[RISC_WRITECR >> 28] = 4,
 	};
 	static char *bits[] = {
 		"12",   "13",   "14",   "resync",
@@ -260,7 +260,7 @@
 	}
 	if (bc != 1)
 		printk("%s: %d buffers handled (should be 1)\n",
-		       __FUNCTION__, bc);
+		       __func__, bc);
 }
 
 int cx23885_sram_channel_setup(struct cx23885_dev *dev,
@@ -272,7 +272,7 @@
 
 	if (ch->cmds_start == 0)
 	{
-		dprintk(1, "%s() Erasing channel [%s]\n", __FUNCTION__,
+		dprintk(1, "%s() Erasing channel [%s]\n", __func__,
 			ch->name);
 		cx_write(ch->ptr1_reg, 0);
 		cx_write(ch->ptr2_reg, 0);
@@ -280,7 +280,7 @@
 		cx_write(ch->cnt1_reg, 0);
 		return 0;
 	} else {
-		dprintk(1, "%s() Configuring channel [%s]\n", __FUNCTION__,
+		dprintk(1, "%s() Configuring channel [%s]\n", __func__,
 			ch->name);
 	}
 
@@ -297,7 +297,7 @@
 
 	/* write CDT */
 	for (i = 0; i < lines; i++) {
-		dprintk(2, "%s() 0x%08x <- 0x%08x\n", __FUNCTION__, cdt + 16*i,
+		dprintk(2, "%s() 0x%08x <- 0x%08x\n", __func__, cdt + 16*i,
 			ch->fifo_start + bpl*i);
 		cx_write(cdt + 16*i, ch->fifo_start + bpl*i);
 		cx_write(cdt + 16*i +  4, 0);
@@ -449,7 +449,7 @@
 
 static void cx23885_reset(struct cx23885_dev *dev)
 {
-	dprintk(1, "%s()\n", __FUNCTION__);
+	dprintk(1, "%s()\n", __func__);
 
 	cx23885_shutdown(dev);
 
@@ -482,7 +482,7 @@
 
 static int cx23885_pci_quirks(struct cx23885_dev *dev)
 {
-	dprintk(1, "%s()\n", __FUNCTION__);
+	dprintk(1, "%s()\n", __func__);
 
 	/* The cx23885 bridge has a weird bug which causes NMI to be asserted
 	 * when DMA begins if RDR_TLCTL0 bit4 is not cleared. It does not
@@ -513,11 +513,13 @@
 
 static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *port, int portno)
 {
-	dprintk(1, "%s(portno=%d)\n", __FUNCTION__, portno);
+	dprintk(1, "%s(portno=%d)\n", __func__, portno);
 
 	/* Transport bus init dma queue  - Common settings */
 	port->dma_ctl_val        = 0x11; /* Enable RISC controller and Fifo */
 	port->ts_int_msk_val     = 0x1111; /* TS port bits for RISC */
+	port->vld_misc_val       = 0x0;
+	port->hw_sop_ctrl_val    = (0x47 << 16 | 188 << 4);
 
 	spin_lock_init(&port->slock);
 	port->dev = dev;
@@ -544,7 +546,7 @@
 		port->reg_ts_clk_en      = VID_B_TS_CLK_EN;
 		port->reg_src_sel        = VID_B_SRC_SEL;
 		port->reg_ts_int_msk     = VID_B_INT_MSK;
-		port->reg_ts_int_stat   = VID_B_INT_STAT;
+		port->reg_ts_int_stat    = VID_B_INT_STAT;
 		port->sram_chno          = SRAM_CH03; /* VID_B */
 		port->pci_irqmask        = 0x02; /* VID_B bit1 */
 		break;
@@ -604,14 +606,14 @@
 		break;
 	default:
 		printk(KERN_ERR "%s() New hardware revision found 0x%x\n",
-			__FUNCTION__, dev->hwrevision);
+			__func__, dev->hwrevision);
 	}
 	if (dev->hwrevision)
 		printk(KERN_INFO "%s() Hardware revision = 0x%02x\n",
-			__FUNCTION__, dev->hwrevision);
+			__func__, dev->hwrevision);
 	else
 		printk(KERN_ERR "%s() Hardware revision unknown 0x%x\n",
-			__FUNCTION__, dev->hwrevision);
+			__func__, dev->hwrevision);
 }
 
 static int cx23885_dev_setup(struct cx23885_dev *dev)
@@ -644,7 +646,7 @@
 		BUG();
 
 	dprintk(1, "%s() Memory configured for PCIe bridge type %d\n",
-		__FUNCTION__, dev->bridge);
+		__func__, dev->bridge);
 
 	/* board config */
 	dev->board = UNSET;
@@ -697,10 +699,12 @@
 	dev->i2c_bus[2].reg_wdata = I2C3_WDATA;
 	dev->i2c_bus[2].i2c_period = (0x07 << 24); /* 1.95MHz */
 
-	if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
+	if ((cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) ||
+		(cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER))
 		cx23885_init_tsport(dev, &dev->ts1, 1);
 
-	if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB)
+	if ((cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) ||
+		(cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER))
 		cx23885_init_tsport(dev, &dev->ts2, 2);
 
 	if (get_resources(dev) < 0) {
@@ -734,9 +738,9 @@
 	dev->radio_addr = cx23885_boards[dev->board].radio_addr;
 
 	dprintk(1, "%s() tuner_type = 0x%x tuner_addr = 0x%x\n",
-		__FUNCTION__, dev->tuner_type, dev->tuner_addr);
+		__func__, dev->tuner_type, dev->tuner_addr);
 	dprintk(1, "%s() radio_type = 0x%x radio_addr = 0x%x\n",
-		__FUNCTION__, dev->radio_type, dev->radio_addr);
+		__func__, dev->radio_type, dev->radio_addr);
 
 	/* init hardware */
 	cx23885_reset(dev);
@@ -744,28 +748,43 @@
 	cx23885_i2c_register(&dev->i2c_bus[0]);
 	cx23885_i2c_register(&dev->i2c_bus[1]);
 	cx23885_i2c_register(&dev->i2c_bus[2]);
-	cx23885_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL);
 	cx23885_card_setup(dev);
+	cx23885_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL);
 	cx23885_ir_init(dev);
 
 	if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) {
 		if (cx23885_video_register(dev) < 0) {
 			printk(KERN_ERR "%s() Failed to register analog "
-				"video adapters on VID_A\n", __FUNCTION__);
+				"video adapters on VID_A\n", __func__);
 		}
 	}
 
 	if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) {
 		if (cx23885_dvb_register(&dev->ts1) < 0) {
 			printk(KERN_ERR "%s() Failed to register dvb adapters on VID_B\n",
-			       __FUNCTION__);
+			       __func__);
+		}
+	} else
+	if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) {
+		if (cx23885_417_register(dev) < 0) {
+			printk(KERN_ERR
+				"%s() Failed to register 417 on VID_B\n",
+			       __func__);
 		}
 	}
 
 	if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) {
 		if (cx23885_dvb_register(&dev->ts2) < 0) {
-			printk(KERN_ERR "%s() Failed to register dvb adapters on VID_C\n",
-			       __FUNCTION__);
+			printk(KERN_ERR
+				"%s() Failed to register dvb on VID_C\n",
+			       __func__);
+		}
+	} else
+	if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER) {
+		if (cx23885_417_register(dev) < 0) {
+			printk(KERN_ERR
+				"%s() Failed to register 417 on VID_C\n",
+			       __func__);
 		}
 	}
 
@@ -785,12 +804,18 @@
 	if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO)
 		cx23885_video_unregister(dev);
 
-	if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
+	if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
 		cx23885_dvb_unregister(&dev->ts1);
 
-	if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB)
+	if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
+		cx23885_417_unregister(dev);
+
+	if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB)
 		cx23885_dvb_unregister(&dev->ts2);
 
+	if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER)
+		cx23885_417_unregister(dev);
+
 	cx23885_i2c_unregister(&dev->i2c_bus[2]);
 	cx23885_i2c_unregister(&dev->i2c_bus[1]);
 	cx23885_i2c_unregister(&dev->i2c_bus[0]);
@@ -952,7 +977,7 @@
 	videobuf_waiton(&buf->vb, 0, 0);
 	videobuf_dma_unmap(q, dma);
 	videobuf_dma_free(dma);
-	btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc);
+	btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
 	buf->vb.state = VIDEOBUF_NEEDS_INIT;
 }
 
@@ -960,50 +985,50 @@
 {
 	struct cx23885_dev *dev = port->dev;
 
-	dprintk(1, "%s() Register Dump\n", __FUNCTION__);
-	dprintk(1, "%s() DEV_CNTRL2               0x%08X\n", __FUNCTION__,
+	dprintk(1, "%s() Register Dump\n", __func__);
+	dprintk(1, "%s() DEV_CNTRL2               0x%08X\n", __func__,
 		cx_read(DEV_CNTRL2));
-	dprintk(1, "%s() PCI_INT_MSK              0x%08X\n", __FUNCTION__,
+	dprintk(1, "%s() PCI_INT_MSK              0x%08X\n", __func__,
 		cx_read(PCI_INT_MSK));
-	dprintk(1, "%s() AUD_INT_INT_MSK          0x%08X\n", __FUNCTION__,
+	dprintk(1, "%s() AUD_INT_INT_MSK          0x%08X\n", __func__,
 		cx_read(AUDIO_INT_INT_MSK));
-	dprintk(1, "%s() AUD_INT_DMA_CTL          0x%08X\n", __FUNCTION__,
+	dprintk(1, "%s() AUD_INT_DMA_CTL          0x%08X\n", __func__,
 		cx_read(AUD_INT_DMA_CTL));
-	dprintk(1, "%s() AUD_EXT_INT_MSK          0x%08X\n", __FUNCTION__,
+	dprintk(1, "%s() AUD_EXT_INT_MSK          0x%08X\n", __func__,
 		cx_read(AUDIO_EXT_INT_MSK));
-	dprintk(1, "%s() AUD_EXT_DMA_CTL          0x%08X\n", __FUNCTION__,
+	dprintk(1, "%s() AUD_EXT_DMA_CTL          0x%08X\n", __func__,
 		cx_read(AUD_EXT_DMA_CTL));
-	dprintk(1, "%s() PAD_CTRL                 0x%08X\n", __FUNCTION__,
+	dprintk(1, "%s() PAD_CTRL                 0x%08X\n", __func__,
 		cx_read(PAD_CTRL));
-	dprintk(1, "%s() ALT_PIN_OUT_SEL          0x%08X\n", __FUNCTION__,
+	dprintk(1, "%s() ALT_PIN_OUT_SEL          0x%08X\n", __func__,
 		cx_read(ALT_PIN_OUT_SEL));
-	dprintk(1, "%s() GPIO2                    0x%08X\n", __FUNCTION__,
+	dprintk(1, "%s() GPIO2                    0x%08X\n", __func__,
 		cx_read(GPIO2));
-	dprintk(1, "%s() gpcnt(0x%08X)          0x%08X\n", __FUNCTION__,
+	dprintk(1, "%s() gpcnt(0x%08X)          0x%08X\n", __func__,
 		port->reg_gpcnt, cx_read(port->reg_gpcnt));
-	dprintk(1, "%s() gpcnt_ctl(0x%08X)      0x%08x\n", __FUNCTION__,
+	dprintk(1, "%s() gpcnt_ctl(0x%08X)      0x%08x\n", __func__,
 		port->reg_gpcnt_ctl, cx_read(port->reg_gpcnt_ctl));
-	dprintk(1, "%s() dma_ctl(0x%08X)        0x%08x\n", __FUNCTION__,
+	dprintk(1, "%s() dma_ctl(0x%08X)        0x%08x\n", __func__,
 		port->reg_dma_ctl, cx_read(port->reg_dma_ctl));
-	dprintk(1, "%s() src_sel(0x%08X)        0x%08x\n", __FUNCTION__,
+	dprintk(1, "%s() src_sel(0x%08X)        0x%08x\n", __func__,
 		port->reg_src_sel, cx_read(port->reg_src_sel));
-	dprintk(1, "%s() lngth(0x%08X)          0x%08x\n", __FUNCTION__,
+	dprintk(1, "%s() lngth(0x%08X)          0x%08x\n", __func__,
 		port->reg_lngth, cx_read(port->reg_lngth));
-	dprintk(1, "%s() hw_sop_ctrl(0x%08X)    0x%08x\n", __FUNCTION__,
+	dprintk(1, "%s() hw_sop_ctrl(0x%08X)    0x%08x\n", __func__,
 		port->reg_hw_sop_ctrl, cx_read(port->reg_hw_sop_ctrl));
-	dprintk(1, "%s() gen_ctrl(0x%08X)       0x%08x\n", __FUNCTION__,
+	dprintk(1, "%s() gen_ctrl(0x%08X)       0x%08x\n", __func__,
 		port->reg_gen_ctrl, cx_read(port->reg_gen_ctrl));
-	dprintk(1, "%s() bd_pkt_status(0x%08X)  0x%08x\n", __FUNCTION__,
+	dprintk(1, "%s() bd_pkt_status(0x%08X)  0x%08x\n", __func__,
 		port->reg_bd_pkt_status, cx_read(port->reg_bd_pkt_status));
-	dprintk(1, "%s() sop_status(0x%08X)     0x%08x\n", __FUNCTION__,
+	dprintk(1, "%s() sop_status(0x%08X)     0x%08x\n", __func__,
 		port->reg_sop_status, cx_read(port->reg_sop_status));
-	dprintk(1, "%s() fifo_ovfl_stat(0x%08X) 0x%08x\n", __FUNCTION__,
+	dprintk(1, "%s() fifo_ovfl_stat(0x%08X) 0x%08x\n", __func__,
 		port->reg_fifo_ovfl_stat, cx_read(port->reg_fifo_ovfl_stat));
-	dprintk(1, "%s() vld_misc(0x%08X)       0x%08x\n", __FUNCTION__,
+	dprintk(1, "%s() vld_misc(0x%08X)       0x%08x\n", __func__,
 		port->reg_vld_misc, cx_read(port->reg_vld_misc));
-	dprintk(1, "%s() ts_clk_en(0x%08X)      0x%08x\n", __FUNCTION__,
+	dprintk(1, "%s() ts_clk_en(0x%08X)      0x%08x\n", __func__,
 		port->reg_ts_clk_en, cx_read(port->reg_ts_clk_en));
-	dprintk(1, "%s() ts_int_msk(0x%08X)     0x%08x\n", __FUNCTION__,
+	dprintk(1, "%s() ts_int_msk(0x%08X)     0x%08x\n", __func__,
 		port->reg_ts_int_msk, cx_read(port->reg_ts_int_msk));
 }
 
@@ -1012,8 +1037,9 @@
 			     struct cx23885_buffer   *buf)
 {
 	struct cx23885_dev *dev = port->dev;
+	u32 reg;
 
-	dprintk(1, "%s() w: %d, h: %d, f: %d\n", __FUNCTION__,
+	dprintk(1, "%s() w: %d, h: %d, f: %d\n", __func__,
 		buf->vb.width, buf->vb.height, buf->vb.field);
 
 	/* setup fifo + format */
@@ -1031,21 +1057,24 @@
 	if ( (!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) &&
 		(!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB)) ) {
 		printk( "%s() Failed. Unsupported value in .portb/c (0x%08x)/(0x%08x)\n",
-			__FUNCTION__,
+			__func__,
 			cx23885_boards[dev->board].portb,
 			cx23885_boards[dev->board].portc );
 		return -EINVAL;
 	}
 
+	if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
+		cx23885_av_clk(dev, 0);
+
 	udelay(100);
 
 	/* If the port supports SRC SELECT, configure it */
 	if(port->reg_src_sel)
 		cx_write(port->reg_src_sel, port->src_sel_val);
 
-	cx_write(port->reg_hw_sop_ctrl, 0x47 << 16 | 188 << 4);
+	cx_write(port->reg_hw_sop_ctrl, port->hw_sop_ctrl_val);
 	cx_write(port->reg_ts_clk_en, port->ts_clk_en_val);
-	cx_write(port->reg_vld_misc, 0x00);
+	cx_write(port->reg_vld_misc, port->vld_misc_val);
 	cx_write(port->reg_gen_ctrl, port->gen_ctrl_val);
 	udelay(100);
 
@@ -1054,11 +1083,26 @@
 	cx_write(port->reg_gpcnt_ctl, 3);
 	q->count = 1;
 
+	if (cx23885_boards[dev->board].portb & CX23885_MPEG_ENCODER) {
+
+		reg = cx_read(PAD_CTRL);
+		reg = reg & ~0x1;    /* Clear TS1_OE */
+
+		/* FIXME, bit 2 writing here is questionable */
+		/* set TS1_SOP_OE and TS1_OE_HI */
+		reg = reg | 0xa;
+		cx_write(PAD_CTRL, reg);
+
+		/* FIXME and these two registers should be documented. */
+		cx_write(CLK_DELAY, cx_read(CLK_DELAY) | 0x80000011);
+		cx_write(ALT_PIN_OUT_SEL, 0x10100045);
+	}
+
 	switch(dev->bridge) {
 	case CX23885_BRIDGE_885:
 	case CX23885_BRIDGE_887:
 		/* enable irqs */
-		dprintk(1, "%s() enabling TS int's and DMA\n", __FUNCTION__ );
+		dprintk(1, "%s() enabling TS int's and DMA\n", __func__ );
 		cx_set(port->reg_ts_int_msk,  port->ts_int_msk_val);
 		cx_set(port->reg_dma_ctl, port->dma_ctl_val);
 		cx_set(PCI_INT_MSK, dev->pci_irqmask | port->pci_irqmask);
@@ -1069,6 +1113,9 @@
 
 	cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */
 
+	if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
+		cx23885_av_clk(dev, 1);
+
 	if (debug > 4)
 		cx23885_tsport_reg_dump(port);
 
@@ -1078,12 +1125,32 @@
 static int cx23885_stop_dma(struct cx23885_tsport *port)
 {
 	struct cx23885_dev *dev = port->dev;
-	dprintk(1, "%s()\n", __FUNCTION__);
+	u32 reg;
+
+	dprintk(1, "%s()\n", __func__);
 
 	/* Stop interrupts and DMA */
 	cx_clear(port->reg_ts_int_msk, port->ts_int_msk_val);
 	cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
 
+	if (cx23885_boards[dev->board].portb & CX23885_MPEG_ENCODER) {
+
+		reg = cx_read(PAD_CTRL);
+
+		/* Set TS1_OE */
+		reg = reg | 0x1;
+
+		/* clear TS1_SOP_OE and TS1_OE_HI */
+		reg = reg & ~0xa;
+		cx_write(PAD_CTRL, reg);
+		cx_write(port->reg_src_sel, 0);
+		cx_write(port->reg_gen_ctrl, 8);
+
+	}
+
+	if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
+		cx23885_av_clk(dev, 0);
+
 	return 0;
 }
 
@@ -1093,13 +1160,13 @@
 	struct cx23885_dev *dev = port->dev;
 	struct cx23885_buffer *buf;
 
-	dprintk(5, "%s()\n", __FUNCTION__);
+	dprintk(5, "%s()\n", __func__);
 	if (list_empty(&q->active))
 	{
 		struct cx23885_buffer *prev;
 		prev = NULL;
 
-		dprintk(5, "%s() queue is empty\n", __FUNCTION__);
+		dprintk(5, "%s() queue is empty\n", __func__);
 
 		for (;;) {
 			if (list_empty(&q->queued))
@@ -1154,7 +1221,7 @@
 	int size = port->ts_packet_size * port->ts_packet_count;
 	int rc;
 
-	dprintk(1, "%s: %p\n", __FUNCTION__, buf);
+	dprintk(1, "%s: %p\n", __func__, buf);
 	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
 		return -EINVAL;
 
@@ -1197,7 +1264,7 @@
 		buf->count    = cx88q->count++;
 		mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT);
 		dprintk(1, "[%p/%d] %s - first active\n",
-			buf, buf->vb.i, __FUNCTION__);
+			buf, buf->vb.i, __func__);
 	} else {
 		dprintk( 1, "queue is not empty - append to active\n" );
 		prev = list_entry(cx88q->active.prev, struct cx23885_buffer,
@@ -1208,7 +1275,7 @@
 		prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
 		prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */
 		dprintk( 1, "[%p/%d] %s - append to active\n",
-			 buf, buf->vb.i, __FUNCTION__);
+			 buf, buf->vb.i, __func__);
 	}
 }
 
@@ -1239,13 +1306,23 @@
 	spin_unlock_irqrestore(&port->slock, flags);
 }
 
+void cx23885_cancel_buffers(struct cx23885_tsport *port)
+{
+	struct cx23885_dev *dev = port->dev;
+	struct cx23885_dmaqueue *q = &port->mpegq;
+
+	dprintk(1, "%s()\n", __FUNCTION__);
+	del_timer_sync(&q->timeout);
+	cx23885_stop_dma(port);
+	do_cancel_buffers(port, "cancel", 0);
+}
 
 static void cx23885_timeout(unsigned long data)
 {
 	struct cx23885_tsport *port = (struct cx23885_tsport *)data;
 	struct cx23885_dev *dev = port->dev;
 
-	dprintk(1, "%s()\n",__FUNCTION__);
+	dprintk(1, "%s()\n",__func__);
 
 	if (debug > 5)
 		cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]);
@@ -1254,16 +1331,77 @@
 	do_cancel_buffers(port, "timeout", 1);
 }
 
+int cx23885_irq_417(struct cx23885_dev *dev, u32 status)
+{
+	/* FIXME: port1 assumption here. */
+	struct cx23885_tsport *port = &dev->ts1;
+	int count = 0;
+	int handled = 0;
+
+	if (status == 0)
+		return handled;
+
+	count = cx_read(port->reg_gpcnt);
+	dprintk(7, "status: 0x%08x  mask: 0x%08x count: 0x%x\n",
+		status, cx_read(port->reg_ts_int_msk), count);
+
+	if ((status & VID_B_MSK_BAD_PKT)         ||
+		(status & VID_B_MSK_OPC_ERR)     ||
+		(status & VID_B_MSK_VBI_OPC_ERR) ||
+		(status & VID_B_MSK_SYNC)        ||
+		(status & VID_B_MSK_VBI_SYNC)    ||
+		(status & VID_B_MSK_OF)          ||
+		(status & VID_B_MSK_VBI_OF)) {
+		printk(KERN_ERR "%s: V4L mpeg risc op code error, status "
+			"= 0x%x\n", dev->name, status);
+		if (status & VID_B_MSK_BAD_PKT)
+			dprintk(1, "        VID_B_MSK_BAD_PKT\n");
+		if (status & VID_B_MSK_OPC_ERR)
+			dprintk(1, "        VID_B_MSK_OPC_ERR\n");
+		if (status & VID_B_MSK_VBI_OPC_ERR)
+			dprintk(1, "        VID_B_MSK_VBI_OPC_ERR\n");
+		if (status & VID_B_MSK_SYNC)
+			dprintk(1, "        VID_B_MSK_SYNC\n");
+		if (status & VID_B_MSK_VBI_SYNC)
+			dprintk(1, "        VID_B_MSK_VBI_SYNC\n");
+		if (status & VID_B_MSK_OF)
+			dprintk(1, "        VID_B_MSK_OF\n");
+		if (status & VID_B_MSK_VBI_OF)
+			dprintk(1, "        VID_B_MSK_VBI_OF\n");
+
+		cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
+		cx23885_sram_channel_dump(dev,
+			&dev->sram_channels[port->sram_chno]);
+		cx23885_417_check_encoder(dev);
+	} else if (status & VID_B_MSK_RISCI1) {
+		dprintk(7, "        VID_B_MSK_RISCI1\n");
+		spin_lock(&port->slock);
+		cx23885_wakeup(port, &port->mpegq, count);
+		spin_unlock(&port->slock);
+	} else if (status & VID_B_MSK_RISCI2) {
+		dprintk(7, "        VID_B_MSK_RISCI2\n");
+		spin_lock(&port->slock);
+		cx23885_restart_queue(port, &port->mpegq);
+		spin_unlock(&port->slock);
+	}
+	if (status) {
+		cx_write(port->reg_ts_int_stat, status);
+		handled = 1;
+	}
+
+	return handled;
+}
+
 static int cx23885_irq_ts(struct cx23885_tsport *port, u32 status)
 {
 	struct cx23885_dev *dev = port->dev;
 	int handled = 0;
 	u32 count;
 
-	if ( (status & VID_BC_MSK_OPC_ERR) ||
-	     (status & VID_BC_MSK_BAD_PKT) ||
-	     (status & VID_BC_MSK_SYNC) ||
-	     (status & VID_BC_MSK_OF))
+	if ((status & VID_BC_MSK_OPC_ERR) ||
+		(status & VID_BC_MSK_BAD_PKT) ||
+		(status & VID_BC_MSK_SYNC) ||
+		(status & VID_BC_MSK_OF))
 	{
 		if (status & VID_BC_MSK_OPC_ERR)
 			dprintk(7, " (VID_BC_MSK_OPC_ERR 0x%08x)\n", VID_BC_MSK_OPC_ERR);
@@ -1277,7 +1415,8 @@
 		printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name);
 
 		cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
-		cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]);
+		cx23885_sram_channel_dump(dev,
+			&dev->sram_channels[port->sram_chno]);
 
 	} else if (status & VID_BC_MSK_RISCI1) {
 
@@ -1378,11 +1517,17 @@
 	if (ts1_status) {
 		if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
 			handled += cx23885_irq_ts(ts1, ts1_status);
+		else
+		if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
+			handled += cx23885_irq_417(dev, ts1_status);
 	}
 
 	if (ts2_status) {
 		if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB)
 			handled += cx23885_irq_ts(ts2, ts2_status);
+		else
+		if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER)
+			handled += cx23885_irq_417(dev, ts2_status);
 	}
 
 	if (vida_status)
@@ -1422,7 +1567,8 @@
 	printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
 	       "latency: %d, mmio: 0x%llx\n", dev->name,
 	       pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
-	       dev->pci_lat, (unsigned long long)pci_resource_start(pci_dev,0));
+	       dev->pci_lat,
+		(unsigned long long)pci_resource_start(pci_dev, 0));
 
 	pci_set_master(pci_dev);
 	if (!pci_dma_supported(pci_dev, 0xffffffff)) {
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
index ed465c0..870d6e1 100644
--- a/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -36,9 +36,12 @@
 #include "tda18271.h"
 #include "lgdt330x.h"
 #include "xc5000.h"
+#include "tda10048.h"
 #include "dvb-pll.h"
 #include "tuner-xc2028.h"
-#include "tuner-xc2028-types.h"
+#include "tuner-simple.h"
+#include "dib7000p.h"
+#include "dibx000_common.h"
 
 static unsigned int debug;
 
@@ -53,6 +56,8 @@
 module_param(alt_tuner, int, 0644);
 MODULE_PARM_DESC(alt_tuner, "Enable alternate tuner configuration");
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 /* ------------------------------------------------------------------ */
 
 static int dvb_buf_setup(struct videobuf_queue *q,
@@ -104,6 +109,13 @@
 	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
 };
 
+static struct tda10048_config hauppauge_hvr1200_config = {
+	.demod_address    = 0x10 >> 1,
+	.output_mode      = TDA10048_SERIAL_OUTPUT,
+	.fwbulkwritelen   = TDA10048_BULKWRITE_200,
+	.inversion        = TDA10048_INVERSION_ON
+};
+
 static struct s5h1409_config hauppauge_ezqam_config = {
 	.demod_address = 0x32 >> 1,
 	.output_mode   = S5H1409_SERIAL_OUTPUT,
@@ -164,8 +176,10 @@
 };
 
 static struct tda18271_std_map hauppauge_tda18271_std_map = {
-	.atsc_6   = { .if_freq = 5380, .std_bits = 0x1b },
-	.qam_6    = { .if_freq = 4000, .std_bits = 0x18 },
+	.atsc_6   = { .if_freq = 5380, .agc_mode = 3, .std = 3,
+		      .if_lvl = 6, .rfagc_top = 0x37 },
+	.qam_6    = { .if_freq = 4000, .agc_mode = 3, .std = 0,
+		      .if_lvl = 6, .rfagc_top = 0x37 },
 };
 
 static struct tda18271_config hauppauge_tda18271_config = {
@@ -173,6 +187,96 @@
 	.gate    = TDA18271_GATE_ANALOG,
 };
 
+static struct tda18271_config hauppauge_hvr1200_tuner_config = {
+	.gate    = TDA18271_GATE_ANALOG,
+};
+
+struct dibx000_agc_config xc3028_agc_config = {
+	BAND_VHF | BAND_UHF,	/* band_caps */
+
+	/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=0,
+	 * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
+	 * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0,
+	 * P_agc_nb_est=2, P_agc_write=0
+	 */
+	(0 << 15) | (0 << 14) | (0 << 11) | (0 << 10) | (0 << 9) | (0 << 8) |
+		(3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), /* setup */
+
+	712,	/* inv_gain */
+	21,	/* time_stabiliz */
+
+	0,	/* alpha_level */
+	118,	/* thlock */
+
+	0,	/* wbd_inv */
+	2867,	/* wbd_ref */
+	0,	/* wbd_sel */
+	2,	/* wbd_alpha */
+
+	0,	/* agc1_max */
+	0,	/* agc1_min */
+	39718,	/* agc2_max */
+	9930,	/* agc2_min */
+	0,	/* agc1_pt1 */
+	0,	/* agc1_pt2 */
+	0,	/* agc1_pt3 */
+	0,	/* agc1_slope1 */
+	0,	/* agc1_slope2 */
+	0,	/* agc2_pt1 */
+	128,	/* agc2_pt2 */
+	29,	/* agc2_slope1 */
+	29,	/* agc2_slope2 */
+
+	17,	/* alpha_mant */
+	27,	/* alpha_exp */
+	23,	/* beta_mant */
+	51,	/* beta_exp */
+
+	1,	/* perform_agc_softsplit */
+};
+
+/* PLL Configuration for COFDM BW_MHz = 8.000000
+ * With external clock = 30.000000 */
+struct dibx000_bandwidth_config xc3028_bw_config = {
+	60000,	/* internal */
+	30000,	/* sampling */
+	1,	/* pll_cfg: prediv */
+	8,	/* pll_cfg: ratio */
+	3,	/* pll_cfg: range */
+	1,	/* pll_cfg: reset */
+	0,	/* pll_cfg: bypass */
+	0,	/* misc: refdiv */
+	0,	/* misc: bypclk_div */
+	1,	/* misc: IO_CLK_en_core */
+	1,	/* misc: ADClkSrc */
+	0,	/* misc: modulo */
+	(3 << 14) | (1 << 12) | (524 << 0), /* sad_cfg: refsel, sel, freq_15k */
+	(1 << 25) | 5816102, /* ifreq = 5.200000 MHz */
+	20452225, /* timf */
+	30000000  /* xtal_hz */
+};
+
+static struct dib7000p_config hauppauge_hvr1400_dib7000_config = {
+	.output_mpeg2_in_188_bytes = 1,
+	.hostbus_diversity = 1,
+	.tuner_is_baseband = 0,
+	.update_lna  = NULL,
+
+	.agc_config_count = 1,
+	.agc = &xc3028_agc_config,
+	.bw  = &xc3028_bw_config,
+
+	.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+	.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+	.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+	.pwm_freq_div = 0,
+	.agc_control  = NULL,
+	.spur_protect = 0,
+
+	.output_mode = OUTMODE_MPEG2_SERIAL,
+};
+
 static int cx23885_hvr1500_xc3028_callback(void *ptr, int command, int arg)
 {
 	struct cx23885_tsport *port = ptr;
@@ -182,7 +286,7 @@
 	case XC2028_TUNER_RESET:
 		/* Send the tuner in then out of reset */
 		/* GPIO-2 xc3028 tuner */
-		dprintk(1, "%s: XC2028_TUNER_RESET %d\n", __FUNCTION__, arg);
+		dprintk(1, "%s: XC2028_TUNER_RESET %d\n", __func__, arg);
 
 		cx_set(GP0_IO, 0x00040000);
 		cx_clear(GP0_IO, 0x00000004);
@@ -192,10 +296,10 @@
 		msleep(5);
 		break;
 	case XC2028_RESET_CLK:
-		dprintk(1, "%s: XC2028_RESET_CLK %d\n", __FUNCTION__, arg);
+		dprintk(1, "%s: XC2028_RESET_CLK %d\n", __func__, arg);
 		break;
 	default:
-		dprintk(1, "%s: unknown command %d, arg %d\n", __FUNCTION__,
+		dprintk(1, "%s: unknown command %d, arg %d\n", __func__,
 			command, arg);
 		return -EINVAL;
 	}
@@ -271,8 +375,9 @@
 						&fusionhdtv_5_express,
 						&i2c_bus->i2c_adap);
 		if (port->dvb.frontend != NULL) {
-			dvb_attach(dvb_pll_attach, port->dvb.frontend, 0x61,
-				   &i2c_bus->i2c_adap, DVB_PLL_LG_TDVS_H06XF);
+			dvb_attach(simple_tuner_attach, port->dvb.frontend,
+				   &i2c_bus->i2c_adap, 0x61,
+				   TUNER_LG_TDVS_H06XF);
 		}
 		break;
 	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
@@ -297,13 +402,52 @@
 			struct xc2028_config cfg = {
 				.i2c_adap  = &i2c_bus->i2c_adap,
 				.i2c_addr  = 0x61,
-				.video_dev = port,
 				.callback  = cx23885_hvr1500_xc3028_callback,
 			};
 			static struct xc2028_ctrl ctl = {
 				.fname       = "xc3028-v27.fw",
 				.max_len     = 64,
-				.scode_table = OREN538,
+				.scode_table = XC3028_FE_OREN538,
+			};
+
+			fe = dvb_attach(xc2028_attach,
+					port->dvb.frontend, &cfg);
+			if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+				fe->ops.tuner_ops.set_config(fe, &ctl);
+		}
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1200:
+	case CX23885_BOARD_HAUPPAUGE_HVR1700:
+		i2c_bus = &dev->i2c_bus[0];
+		port->dvb.frontend = dvb_attach(tda10048_attach,
+			&hauppauge_hvr1200_config,
+			&i2c_bus->i2c_adap);
+		if (port->dvb.frontend != NULL) {
+			dvb_attach(tda829x_attach, port->dvb.frontend,
+				&dev->i2c_bus[1].i2c_adap, 0x42,
+				&tda829x_no_probe);
+			dvb_attach(tda18271_attach, port->dvb.frontend,
+				0x60, &dev->i2c_bus[1].i2c_adap,
+				&hauppauge_hvr1200_tuner_config);
+		}
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1400:
+		i2c_bus = &dev->i2c_bus[0];
+		port->dvb.frontend = dvb_attach(dib7000p_attach,
+			&i2c_bus->i2c_adap,
+			0x12, &hauppauge_hvr1400_dib7000_config);
+		if (port->dvb.frontend != NULL) {
+			struct dvb_frontend *fe;
+			struct xc2028_config cfg = {
+				.i2c_adap  = &dev->i2c_bus[1].i2c_adap,
+				.i2c_addr  = 0x64,
+				.callback  = cx23885_hvr1500_xc3028_callback,
+			};
+			static struct xc2028_ctrl ctl = {
+				.fname   = "xc3028L-v36.fw",
+				.max_len = 64,
+				.demod   = 5000,
+				.d2633   = 1
 			};
 
 			fe = dvb_attach(xc2028_attach,
@@ -330,7 +474,7 @@
 
 	/* register everything */
 	return videobuf_dvb_register(&port->dvb, THIS_MODULE, port,
-				     &dev->pci->dev);
+				     &dev->pci->dev, adapter_nr);
 }
 
 int cx23885_dvb_register(struct cx23885_tsport *port)
@@ -338,7 +482,7 @@
 	struct cx23885_dev *dev = port->dev;
 	int err;
 
-	dprintk(1, "%s\n", __FUNCTION__);
+	dprintk(1, "%s\n", __func__);
 	dprintk(1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
 		dev->board,
 		dev->name,
@@ -349,12 +493,12 @@
 
 	/* dvb stuff */
 	printk("%s: cx23885 based dvb card\n", dev->name);
-	videobuf_queue_pci_init(&port->dvb.dvbq, &dvb_qops, dev->pci, &port->slock,
+	videobuf_queue_sg_init(&port->dvb.dvbq, &dvb_qops, &dev->pci->dev, &port->slock,
 			    V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP,
 			    sizeof(struct cx23885_buffer), port);
 	err = dvb_register(port);
 	if (err != 0)
-		printk("%s() dvb_register failed err = %d\n", __FUNCTION__, err);
+		printk("%s() dvb_register failed err = %d\n", __func__, err);
 
 	return err;
 }
diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c
index 92fe0bd..c6bb0a0 100644
--- a/drivers/media/video/cx23885/cx23885-i2c.c
+++ b/drivers/media/video/cx23885/cx23885-i2c.c
@@ -33,7 +33,7 @@
 module_param(i2c_debug, int, 0644);
 MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
 
-static unsigned int i2c_scan = 0;
+static unsigned int i2c_scan;
 module_param(i2c_scan, int, 0444);
 MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
 
@@ -87,10 +87,10 @@
 	int retval, cnt;
 
 	if (joined_rlen)
-		dprintk(1, "%s(msg->wlen=%d, nextmsg->rlen=%d)\n", __FUNCTION__,
+		dprintk(1, "%s(msg->wlen=%d, nextmsg->rlen=%d)\n", __func__,
 			msg->len, joined_rlen);
 	else
-		dprintk(1, "%s(msg->len=%d)\n", __FUNCTION__, msg->len);
+		dprintk(1, "%s(msg->len=%d)\n", __func__, msg->len);
 
 	/* Deal with i2c probe functions with zero payload */
 	if (msg->len == 0) {
@@ -101,7 +101,7 @@
 		if (!i2c_slave_did_ack(i2c_adap))
 			return -EIO;
 
-		dprintk(1, "%s() returns 0\n", __FUNCTION__);
+		dprintk(1, "%s() returns 0\n", __func__);
 		return 0;
 	}
 
@@ -176,7 +176,7 @@
 
 
 	if (i2c_debug && !joined)
-		dprintk(1, "%s(msg->len=%d)\n", __FUNCTION__, msg->len);
+		dprintk(1, "%s(msg->len=%d)\n", __func__, msg->len);
 
 	/* Deal with i2c probe functions with zero payload */
 	if (msg->len == 0) {
@@ -188,7 +188,7 @@
 			return -EIO;
 
 
-		dprintk(1, "%s() returns 0\n", __FUNCTION__);
+		dprintk(1, "%s() returns 0\n", __func__);
 		return 0;
 	}
 
@@ -238,11 +238,11 @@
 	struct cx23885_dev *dev = bus->dev;
 	int i, retval = 0;
 
-	dprintk(1, "%s(num = %d)\n", __FUNCTION__, num);
+	dprintk(1, "%s(num = %d)\n", __func__, num);
 
 	for (i = 0 ; i < num; i++) {
 		dprintk(1, "%s(num = %d) addr = 0x%02x  len = 0x%x\n",
-			__FUNCTION__, num, msgs[i].addr, msgs[i].len);
+			__func__, num, msgs[i].addr, msgs[i].len);
 		if (msgs[i].flags & I2C_M_RD) {
 			/* read */
 			retval = i2c_readbytes(i2c_adap, &msgs[i], 0);
@@ -353,6 +353,8 @@
 };
 
 static char *i2c_devs[128] = {
+	[0x10 >> 1]   = "tda10048",
+	[0x12 >> 1]   = "dib7000pc",
 	[ 0x1c >> 1 ] = "lgdt3303",
 	[ 0x86 >> 1 ] = "tda9887",
 	[ 0x32 >> 1 ] = "cx24227",
@@ -360,7 +362,8 @@
 	[ 0x84 >> 1 ] = "tda8295",
 	[ 0xa0 >> 1 ] = "eeprom",
 	[ 0xc0 >> 1 ] = "tuner/mt2131/tda8275",
-	[ 0xc2 >> 1 ] = "tuner/mt2131/tda8275/xc5000",
+	[0xc2 >> 1] = "tuner/mt2131/tda8275/xc5000/xc3028",
+	[0xc8 >> 1]   = "tuner/xc3028L",
 };
 
 static void do_i2c_scan(char *name, struct i2c_client *c)
@@ -383,7 +386,7 @@
 {
 	struct cx23885_dev *dev = bus->dev;
 
-	dprintk(1, "%s(bus = %d)\n", __FUNCTION__, bus->nr);
+	dprintk(1, "%s(bus = %d)\n", __func__, bus->nr);
 
 	memcpy(&bus->i2c_adap, &cx23885_i2c_adap_template,
 	       sizeof(bus->i2c_adap));
@@ -420,6 +423,29 @@
 	return 0;
 }
 
+void cx23885_av_clk(struct cx23885_dev *dev, int enable)
+{
+	/* write 0 to bus 2 addr 0x144 via i2x_xfer() */
+	char buffer[3];
+	struct i2c_msg msg;
+	dprintk(1, "%s(enabled = %d)\n", __func__, enable);
+
+	/* Register 0x144 */
+	buffer[0] = 0x01;
+	buffer[1] = 0x44;
+	if (enable == 1)
+		buffer[2] = 0x05;
+	else
+		buffer[2] = 0x00;
+
+	msg.addr = 0x44;
+	msg.flags = I2C_M_TEN;
+	msg.len = 3;
+	msg.buf = buffer;
+
+	i2c_xfer(&dev->i2c_bus[2].i2c_adap, &msg, 1);
+}
+
 /* ----------------------------------------------------------------------- */
 
 /*
diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c
index d3c4d2c..8465221 100644
--- a/drivers/media/video/cx23885/cx23885-video.c
+++ b/drivers/media/video/cx23885/cx23885-video.c
@@ -141,7 +141,7 @@
 		if (formats[i].fourcc == fourcc)
 			return formats+i;
 
-	printk(KERN_ERR "%s(0x%08x) NOT FOUND\n", __FUNCTION__, fourcc);
+	printk(KERN_ERR "%s(0x%08x) NOT FOUND\n", __func__, fourcc);
 	return NULL;
 }
 
@@ -292,13 +292,13 @@
 	}
 	if (bc != 1)
 		printk(KERN_ERR "%s: %d buffers handled (should be 1)\n",
-			__FUNCTION__, bc);
+			__func__, bc);
 }
 
 int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
 {
 	dprintk(1, "%s(norm = 0x%08x) name: [%s]\n",
-		__FUNCTION__,
+		__func__,
 		(unsigned int)norm,
 		v4l2_norm_to_name(norm));
 
@@ -319,7 +319,7 @@
 				    char *type)
 {
 	struct video_device *vfd;
-	dprintk(1, "%s()\n", __FUNCTION__);
+	dprintk(1, "%s()\n", __func__);
 
 	vfd = video_device_alloc();
 	if (NULL == vfd)
@@ -358,7 +358,7 @@
 static int res_get(struct cx23885_dev *dev, struct cx23885_fh *fh,
 	unsigned int bit)
 {
-	dprintk(1, "%s()\n", __FUNCTION__);
+	dprintk(1, "%s()\n", __func__);
 	if (fh->resources & bit)
 		/* have it already allocated */
 		return 1;
@@ -392,7 +392,7 @@
 	unsigned int bits)
 {
 	BUG_ON((fh->resources & bits) != bits);
-	dprintk(1, "%s()\n", __FUNCTION__);
+	dprintk(1, "%s()\n", __func__);
 
 	mutex_lock(&dev->lock);
 	fh->resources  &= ~bits;
@@ -407,7 +407,7 @@
 	memset(&route, 0, sizeof(route));
 
 	dprintk(1, "%s() video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n",
-		__FUNCTION__,
+		__func__,
 		input, INPUT(input)->vmux,
 		INPUT(input)->gpio0, INPUT(input)->gpio1,
 		INPUT(input)->gpio2, INPUT(input)->gpio3);
@@ -427,7 +427,7 @@
 int cx23885_set_scale(struct cx23885_dev *dev, unsigned int width,
 	unsigned int height, enum v4l2_field field)
 {
-	dprintk(1, "%s()\n", __FUNCTION__);
+	dprintk(1, "%s()\n", __func__);
 	return 0;
 }
 
@@ -435,7 +435,7 @@
 			   struct cx23885_dmaqueue *q,
 			   struct cx23885_buffer *buf)
 {
-	dprintk(1, "%s()\n", __FUNCTION__);
+	dprintk(1, "%s()\n", __func__);
 
 	/* setup fifo + format */
 	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01],
@@ -463,7 +463,7 @@
 {
 	struct cx23885_buffer *buf, *prev;
 	struct list_head *item;
-	dprintk(1, "%s()\n", __FUNCTION__);
+	dprintk(1, "%s()\n", __func__);
 
 	if (!list_empty(&q->active)) {
 		buf = list_entry(q->active.next, struct cx23885_buffer,
@@ -579,13 +579,13 @@
 			if (dev->tvnorm & V4L2_STD_NTSC) {
 				/* cx25840 transmits NTSC bottom field first */
 				dprintk(1, "%s() Creating NTSC risc\n",
-					__FUNCTION__);
+					__func__);
 				line0_offset = buf->bpl;
 				line1_offset = 0;
 			} else {
 				/* All other formats are top field first */
 				dprintk(1, "%s() Creating PAL/SECAM risc\n",
-					__FUNCTION__);
+					__func__);
 				line0_offset = 0;
 				line1_offset = buf->bpl;
 			}
@@ -765,8 +765,8 @@
 	fh->height   = 240;
 	fh->fmt      = format_by_fourcc(V4L2_PIX_FMT_BGR24);
 
-	videobuf_queue_pci_init(&fh->vidq, &cx23885_video_qops,
-			    dev->pci, &dev->slock,
+	videobuf_queue_sg_init(&fh->vidq, &cx23885_video_qops,
+			    &dev->pci->dev, &dev->slock,
 			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
 			    V4L2_FIELD_INTERLACED,
 			    sizeof(struct cx23885_buffer),
@@ -885,7 +885,7 @@
 
 int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl)
 {
-	dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __FUNCTION__);
+	dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __func__);
 	cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_CTRL, ctl);
 	return 0;
 }
@@ -894,7 +894,7 @@
 int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl)
 {
 	dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)"
-		" (disabled - no action)\n", __FUNCTION__);
+		" (disabled - no action)\n", __func__);
 	return 0;
 }
 EXPORT_SYMBOL(cx23885_set_control);
@@ -990,7 +990,7 @@
 	struct cx23885_dev *dev  = ((struct cx23885_fh *)priv)->dev;
 	int err;
 
-	dprintk(2, "%s()\n", __FUNCTION__);
+	dprintk(2, "%s()\n", __func__);
 	err = vidioc_try_fmt_cap(file, priv, f);
 
 	if (0 != err)
@@ -999,7 +999,7 @@
 	fh->width      = f->fmt.pix.width;
 	fh->height     = f->fmt.pix.height;
 	fh->vidq.field = f->fmt.pix.field;
-	dprintk(2, "%s() width=%d height=%d field=%d\n", __FUNCTION__,
+	dprintk(2, "%s() width=%d height=%d field=%d\n", __func__,
 		fh->width, fh->height, fh->vidq.field);
 	cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_FMT, f);
 	return 0;
@@ -1101,7 +1101,7 @@
 {
 	struct cx23885_fh *fh = priv;
 	struct cx23885_dev *dev = fh->dev;
-	dprintk(1, "%s()\n", __FUNCTION__);
+	dprintk(1, "%s()\n", __func__);
 
 	if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE))
 		return -EINVAL;
@@ -1118,7 +1118,7 @@
 	struct cx23885_fh *fh = priv;
 	struct cx23885_dev *dev = fh->dev;
 	int err, res;
-	dprintk(1, "%s()\n", __FUNCTION__);
+	dprintk(1, "%s()\n", __func__);
 
 	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
@@ -1136,7 +1136,7 @@
 static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms)
 {
 	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
-	dprintk(1, "%s()\n", __FUNCTION__);
+	dprintk(1, "%s()\n", __func__);
 
 	mutex_lock(&dev->lock);
 	cx23885_set_tvnorm(dev, *tvnorms);
@@ -1159,7 +1159,7 @@
 		[CX23885_VMUX_DEBUG]      = "for debug only",
 	};
 	unsigned int n;
-	dprintk(1, "%s()\n", __FUNCTION__);
+	dprintk(1, "%s()\n", __func__);
 
 	n = i->index;
 	if (n >= 4)
@@ -1184,7 +1184,7 @@
 				struct v4l2_input *i)
 {
 	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
-	dprintk(1, "%s()\n", __FUNCTION__);
+	dprintk(1, "%s()\n", __func__);
 	return cx23885_enum_input(dev, i);
 }
 
@@ -1193,7 +1193,7 @@
 	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
 
 	*i = dev->input;
-	dprintk(1, "%s() returns %d\n", __FUNCTION__, *i);
+	dprintk(1, "%s() returns %d\n", __func__, *i);
 	return 0;
 }
 
@@ -1201,10 +1201,10 @@
 {
 	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
 
-	dprintk(1, "%s(%d)\n", __FUNCTION__, i);
+	dprintk(1, "%s(%d)\n", __func__, i);
 
 	if (i >= 4) {
-		dprintk(1, "%s() -EINVAL\n", __FUNCTION__);
+		dprintk(1, "%s() -EINVAL\n", __func__);
 		return -EINVAL;
 	}
 
@@ -1389,7 +1389,7 @@
 		return handled;
 	cx_write(VID_A_INT_STAT, status);
 
-	dprintk(2, "%s() status = 0x%08x\n", __FUNCTION__, status);
+	dprintk(2, "%s() status = 0x%08x\n", __func__, status);
 	/* risc op code error */
 	if (status & (1 << 16)) {
 		printk(KERN_WARNING "%s/0: video risc op code error\n",
@@ -1487,7 +1487,7 @@
 
 void cx23885_video_unregister(struct cx23885_dev *dev)
 {
-	dprintk(1, "%s()\n", __FUNCTION__);
+	dprintk(1, "%s()\n", __func__);
 	cx_clear(PCI_INT_MSK, 1);
 
 	if (dev->video_dev) {
@@ -1505,7 +1505,7 @@
 {
 	int err;
 
-	dprintk(1, "%s()\n", __FUNCTION__);
+	dprintk(1, "%s()\n", __func__);
 	spin_lock_init(&dev->slock);
 
 	/* Initialize VBI template */
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h
index 7cb2179..32af87f 100644
--- a/drivers/media/video/cx23885/cx23885.h
+++ b/drivers/media/video/cx23885/cx23885.h
@@ -32,6 +32,7 @@
 
 #include "btcx-risc.h"
 #include "cx23885-reg.h"
+#include "media/cx2341x.h"
 
 #include <linux/version.h>
 #include <linux/mutex.h>
@@ -59,6 +60,9 @@
 #define CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP   4
 #define CX23885_BOARD_HAUPPAUGE_HVR1500Q       5
 #define CX23885_BOARD_HAUPPAUGE_HVR1500        6
+#define CX23885_BOARD_HAUPPAUGE_HVR1200        7
+#define CX23885_BOARD_HAUPPAUGE_HVR1700        8
+#define CX23885_BOARD_HAUPPAUGE_HVR1400        9
 
 /* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
 #define CX23885_NORMS (\
@@ -154,6 +158,7 @@
 	CX23885_MPEG_UNDEFINED = 0,
 	CX23885_MPEG_DVB,
 	CX23885_ANALOG_VIDEO,
+	CX23885_MPEG_ENCODER,
 } port_t;
 
 struct cx23885_board {
@@ -252,6 +257,8 @@
 	u32                        gen_ctrl_val;
 	u32                        ts_clk_en_val;
 	u32                        src_sel_val;
+	u32                        vld_misc_val;
+	u32                        hw_sop_ctrl_val;
 };
 
 struct cx23885_dev {
@@ -312,6 +319,14 @@
 	struct cx23885_dmaqueue    vidq;
 	struct cx23885_dmaqueue    vbiq;
 	spinlock_t                 slock;
+
+	/* MPEG Encoder ONLY settings */
+	u32                        cx23417_mailbox;
+	struct cx2341x_mpeg_params mpeg_params;
+	struct video_device        *v4l_device;
+	atomic_t                   v4l_reader_count;
+	struct cx23885_tvnorm      encodernorm;
+
 };
 
 extern struct list_head cx23885_devlist;
@@ -431,6 +446,18 @@
 extern int cx23885_i2c_unregister(struct cx23885_i2c *bus);
 extern void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd,
 				     void *arg);
+extern void cx23885_av_clk(struct cx23885_dev *dev, int enable);
+
+/* ----------------------------------------------------------- */
+/* cx23885-417.c                                               */
+extern int cx23885_417_register(struct cx23885_dev *dev);
+extern void cx23885_417_unregister(struct cx23885_dev *dev);
+extern int cx23885_irq_417(struct cx23885_dev *dev, u32 status);
+extern void cx23885_417_check_encoder(struct cx23885_dev *dev);
+extern void cx23885_mc417_init(struct cx23885_dev *dev);
+extern int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value);
+extern int mc417_memory_write(struct cx23885_dev *dev, u32 address, u32 value);
+
 
 /* ----------------------------------------------------------- */
 /* tv norms                                                    */
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 756a1ee..7fde678 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -352,7 +352,7 @@
 static void input_change(struct i2c_client *client)
 {
 	struct cx25840_state *state = i2c_get_clientdata(client);
-	v4l2_std_id std = cx25840_get_v4lstd(client);
+	v4l2_std_id std = state->std;
 
 	/* Follow step 8c and 8d of section 3.16 in the cx25840 datasheet */
 	if (std & V4L2_STD_SECAM) {
@@ -523,32 +523,34 @@
 
 /* ----------------------------------------------------------------------- */
 
-static int set_v4lstd(struct i2c_client *client, v4l2_std_id std)
+static int set_v4lstd(struct i2c_client *client)
 {
-	u8 fmt=0; 	/* zero is autodetect */
+	struct cx25840_state *state = i2c_get_clientdata(client);
+	u8 fmt = 0; 	/* zero is autodetect */
+	u8 pal_m = 0;
 
 	/* First tests should be against specific std */
-	if (std == V4L2_STD_NTSC_M_JP) {
-		fmt=0x2;
-	} else if (std == V4L2_STD_NTSC_443) {
-		fmt=0x3;
-	} else if (std == V4L2_STD_PAL_M) {
-		fmt=0x5;
-	} else if (std == V4L2_STD_PAL_N) {
-		fmt=0x6;
-	} else if (std == V4L2_STD_PAL_Nc) {
-		fmt=0x7;
-	} else if (std == V4L2_STD_PAL_60) {
-		fmt=0x8;
+	if (state->std == V4L2_STD_NTSC_M_JP) {
+		fmt = 0x2;
+	} else if (state->std == V4L2_STD_NTSC_443) {
+		fmt = 0x3;
+	} else if (state->std == V4L2_STD_PAL_M) {
+		pal_m = 1;
+		fmt = 0x5;
+	} else if (state->std == V4L2_STD_PAL_N) {
+		fmt = 0x6;
+	} else if (state->std == V4L2_STD_PAL_Nc) {
+		fmt = 0x7;
+	} else if (state->std == V4L2_STD_PAL_60) {
+		fmt = 0x8;
 	} else {
 		/* Then, test against generic ones */
-		if (std & V4L2_STD_NTSC) {
-			fmt=0x1;
-		} else if (std & V4L2_STD_PAL) {
-			fmt=0x4;
-		} else if (std & V4L2_STD_SECAM) {
-			fmt=0xc;
-		}
+		if (state->std & V4L2_STD_NTSC)
+			fmt = 0x1;
+		else if (state->std & V4L2_STD_PAL)
+			fmt = 0x4;
+		else if (state->std & V4L2_STD_SECAM)
+			fmt = 0xc;
 	}
 
 	v4l_dbg(1, cx25840_debug, client, "changing video std to fmt %i\n",fmt);
@@ -563,42 +565,13 @@
 		cx25840_and_or(client, 0x47b, ~6, 0);
 	}
 	cx25840_and_or(client, 0x400, ~0xf, fmt);
+	cx25840_and_or(client, 0x403, ~0x3, pal_m);
 	cx25840_vbi_setup(client);
+	if (!state->is_cx25836)
+		input_change(client);
 	return 0;
 }
 
-v4l2_std_id cx25840_get_v4lstd(struct i2c_client * client)
-{
-	struct cx25840_state *state = i2c_get_clientdata(client);
-	/* check VID_FMT_SEL first */
-	u8 fmt = cx25840_read(client, 0x400) & 0xf;
-
-	if (!fmt) {
-		/* check AFD_FMT_STAT if set to autodetect */
-		fmt = cx25840_read(client, 0x40d) & 0xf;
-	}
-
-	switch (fmt) {
-	case 0x1:
-	{
-		/* if the audio std is A2-M, then this is the South Korean
-		   NTSC standard */
-		if (!state->is_cx25836 && cx25840_read(client, 0x805) == 2)
-			return V4L2_STD_NTSC_M_KR;
-		return V4L2_STD_NTSC_M;
-	}
-	case 0x2: return V4L2_STD_NTSC_M_JP;
-	case 0x3: return V4L2_STD_NTSC_443;
-	case 0x4: return V4L2_STD_PAL;
-	case 0x5: return V4L2_STD_PAL_M;
-	case 0x6: return V4L2_STD_PAL_N;
-	case 0x7: return V4L2_STD_PAL_Nc;
-	case 0x8: return V4L2_STD_PAL_60;
-	case 0xc: return V4L2_STD_SECAM;
-	default: return V4L2_STD_UNKNOWN;
-	}
-}
-
 /* ----------------------------------------------------------------------- */
 
 static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
@@ -718,9 +691,10 @@
 
 static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
 {
+	struct cx25840_state *state = i2c_get_clientdata(client);
 	struct v4l2_pix_format *pix;
 	int HSC, VSC, Vsrc, Hsrc, filter, Vlines;
-	int is_50Hz = !(cx25840_get_v4lstd(client) & V4L2_STD_525_60);
+	int is_50Hz = !(state->std & V4L2_STD_525_60);
 
 	switch (fmt->type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
@@ -1096,12 +1070,15 @@
 	}
 
 	case VIDIOC_G_STD:
-		*(v4l2_std_id *)arg = cx25840_get_v4lstd(client);
+		*(v4l2_std_id *)arg = state->std;
 		break;
 
 	case VIDIOC_S_STD:
+		if (state->radio == 0 && state->std == *(v4l2_std_id *)arg)
+			return 0;
 		state->radio = 0;
-		return set_v4lstd(client, *(v4l2_std_id *)arg);
+		state->std = *(v4l2_std_id *)arg;
+		return set_v4lstd(client);
 
 	case AUDC_SET_RADIO:
 		state->radio = 1;
@@ -1291,6 +1268,12 @@
 	state->id = id;
 	state->rev = device_id;
 
+	if (state->is_cx23885) {
+		/* Drive GPIO2 direction and values */
+		cx25840_write(client, 0x160, 0x1d);
+		cx25840_write(client, 0x164, 0x00);
+	}
+
 	return 0;
 }
 
diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h
index 95093ed..8bf797f 100644
--- a/drivers/media/video/cx25840/cx25840-core.h
+++ b/drivers/media/video/cx25840/cx25840-core.h
@@ -38,6 +38,7 @@
 	struct i2c_client *c;
 	int pvr150_workaround;
 	int radio;
+	v4l2_std_id std;
 	enum cx25840_video_input vid_input;
 	enum cx25840_audio_input aud_input;
 	u32 audclk_freq;
@@ -60,7 +61,6 @@
 u8 cx25840_read(struct i2c_client *client, u16 addr);
 u32 cx25840_read4(struct i2c_client *client, u16 addr);
 int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned mask, u8 value);
-v4l2_std_id cx25840_get_v4lstd(struct i2c_client *client);
 
 /* ----------------------------------------------------------------------- */
 /* cx25850-firmware.c                                                      */
diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c
index 1ddf724..620d295 100644
--- a/drivers/media/video/cx25840/cx25840-firmware.c
+++ b/drivers/media/video/cx25840/cx25840-firmware.c
@@ -79,11 +79,9 @@
 	return 0;
 }
 
-static int fw_write(struct i2c_client *client, u8 * data, int size)
+static int fw_write(struct i2c_client *client, u8 *data, int size)
 {
-	int sent;
-
-	if ((sent = i2c_master_send(client, data, size)) < size) {
+	if (i2c_master_send(client, data, size) < size) {
 		v4l_err(client, "firmware load i2c failure\n");
 		return -ENOSYS;
 	}
@@ -96,7 +94,7 @@
 	struct cx25840_state *state = i2c_get_clientdata(client);
 	const struct firmware *fw = NULL;
 	u8 buffer[4], *ptr;
-	int size, send, retval;
+	int size, retval;
 
 	if (state->is_cx23885)
 		firmware = FWFILE_CX23885;
@@ -124,8 +122,7 @@
 	while (size > 0) {
 		ptr[0] = 0x08;
 		ptr[1] = 0x02;
-		send = size > (FWSEND - 2) ? FWSEND : size + 2;
-		retval = fw_write(client, ptr, send);
+		retval = fw_write(client, ptr, min(FWSEND, size + 2));
 
 		if (retval < 0) {
 			release_firmware(fw);
diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c
index 6828f59..c754b9d 100644
--- a/drivers/media/video/cx25840/cx25840-vbi.c
+++ b/drivers/media/video/cx25840/cx25840-vbi.c
@@ -85,7 +85,7 @@
 void cx25840_vbi_setup(struct i2c_client *client)
 {
 	struct cx25840_state *state = i2c_get_clientdata(client);
-	v4l2_std_id std = cx25840_get_v4lstd(client);
+	v4l2_std_id std = state->std;
 	int hblank,hactive,burst,vblank,vactive,sc,vblank656,src_decimation;
 	int luma_lpf,uv_lpf, comb;
 	u32 pll_int,pll_frac,pll_post;
@@ -242,7 +242,7 @@
 			0, 0, V4L2_SLICED_VPS, 0, 0,	/* 9 */
 			0, 0, 0, 0
 		};
-		int is_pal = !(cx25840_get_v4lstd(client) & V4L2_STD_525_60);
+		int is_pal = !(state->std & V4L2_STD_525_60);
 		int i;
 
 		fmt = arg;
@@ -279,7 +279,7 @@
 
 	case VIDIOC_S_FMT:
 	{
-		int is_pal = !(cx25840_get_v4lstd(client) & V4L2_STD_525_60);
+		int is_pal = !(state->std & V4L2_STD_525_60);
 		int vbi_offset = is_pal ? 1 : 0;
 		int i, x;
 		u8 lcr[24];
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index 49d3813..bcf6d9b 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -57,6 +57,7 @@
 	select DVB_NXT200X if !DVB_FE_CUSTOMISE
 	select DVB_CX24123 if !DVB_FE_CUSTOMISE
 	select DVB_ISL6421 if !DVB_FE_CUSTOMISE
+	select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
 	---help---
 	  This adds support for DVB/ATSC cards based on the
 	  Conexant 2388x chip.
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
index 316b106..e976fc6 100644
--- a/drivers/media/video/cx88/cx88-alsa.c
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -283,7 +283,7 @@
 	BUG_ON(!chip->dma_size);
 
 	dprintk(2,"Freeing buffer\n");
-	videobuf_pci_dma_unmap(chip->pci, chip->dma_risc);
+	videobuf_sg_dma_unmap(&chip->pci->dev, chip->dma_risc);
 	videobuf_dma_free(chip->dma_risc);
 	btcx_riscmem_free(chip->pci,&chip->buf->risc);
 	kfree(chip->buf);
@@ -385,7 +385,7 @@
 	BUG_ON(!chip->dma_size);
 	BUG_ON(chip->num_periods & (chip->num_periods-1));
 
-	buf = videobuf_pci_alloc(sizeof(*buf));
+	buf = videobuf_sg_alloc(sizeof(*buf));
 	if (NULL == buf)
 		return -ENOMEM;
 
@@ -396,14 +396,14 @@
 	buf->vb.height = chip->num_periods;
 	buf->vb.size   = chip->dma_size;
 
-	dma=videobuf_to_dma(&buf->vb);
+	dma = videobuf_to_dma(&buf->vb);
 	videobuf_dma_init(dma);
 	ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE,
 			(PAGE_ALIGN(buf->vb.size) >> PAGE_SHIFT));
 	if (ret < 0)
 		goto error;
 
-	ret = videobuf_pci_dma_map(chip->pci,dma);
+	ret = videobuf_sg_dma_map(&chip->pci->dev, dma);
 	if (ret < 0)
 		goto error;
 
@@ -494,7 +494,7 @@
 
 	count = atomic_read(&chip->count);
 
-//	dprintk(2, "%s - count %d (+%u), period %d, frame %lu\n", __FUNCTION__,
+//	dprintk(2, "%s - count %d (+%u), period %d, frame %lu\n", __func__,
 //		count, new, count & (runtime->periods-1),
 //		runtime->period_size * (count & (runtime->periods-1)));
 	return runtime->period_size * (count & (runtime->periods-1));
@@ -690,10 +690,8 @@
 static int snd_cx88_free(snd_cx88_card_t *chip)
 {
 
-	if (chip->irq >= 0){
-		synchronize_irq(chip->irq);
+	if (chip->irq >= 0)
 		free_irq(chip->irq, chip);
-	}
 
 	cx88_core_put(chip->core,chip->pci);
 
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index a99e9d5..61c4f72 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -45,7 +45,7 @@
 module_param(mpegbufs,int,0644);
 MODULE_PARM_DESC(mpegbufs,"number of mpeg buffers, range 2-32");
 
-static unsigned int debug = 0;
+static unsigned int debug;
 module_param(debug,int,0644);
 MODULE_PARM_DESC(debug,"enable debug messages [blackbird]");
 
@@ -314,7 +314,7 @@
 	u32 value, flag, retval;
 	int i;
 
-	dprintk(1,"%s: 0x%X\n", __FUNCTION__, command);
+	dprintk(1,"%s: 0x%X\n", __func__, command);
 
 	/* this may not be 100% safe if we can't read any memory location
 	   without side effects */
@@ -693,7 +693,7 @@
 		return -EINVAL;
 
 	/* Standard V4L2 controls */
-	if (cx8800_ctrl_query(qctrl) == 0)
+	if (cx8800_ctrl_query(dev->core, qctrl) == 0)
 		return 0;
 
 	/* MPEG V4L2 controls */
@@ -933,7 +933,7 @@
 	qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
 	if (unlikely(qctrl->id == 0))
 		return -EINVAL;
-	return cx8800_ctrl_query(qctrl);
+	return cx8800_ctrl_query(dev->core, qctrl);
 }
 
 static int vidioc_enum_input (struct file *file, void *priv,
@@ -1055,7 +1055,7 @@
 
 	dev = cx8802_get_device(inode);
 
-	dprintk( 1, "%s\n", __FUNCTION__);
+	dprintk( 1, "%s\n", __func__);
 
 	if (dev == NULL)
 		return -ENODEV;
@@ -1065,7 +1065,7 @@
 	if (drv) {
 		err = drv->request_acquire(drv);
 		if(err != 0) {
-			dprintk(1,"%s: Unable to acquire hardware, %d\n", __FUNCTION__, err);
+			dprintk(1,"%s: Unable to acquire hardware, %d\n", __func__, err);
 			return err;
 		}
 	}
@@ -1087,8 +1087,8 @@
 	file->private_data = fh;
 	fh->dev      = dev;
 
-	videobuf_queue_pci_init(&fh->mpegq, &blackbird_qops,
-			    dev->pci, &dev->slock,
+	videobuf_queue_sg_init(&fh->mpegq, &blackbird_qops,
+			    &dev->pci->dev, &dev->slock,
 			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
 			    V4L2_FIELD_INTERLACED,
 			    sizeof(struct cx88_buffer),
@@ -1284,7 +1284,7 @@
 	struct cx8802_dev *dev = core->dvbdev;
 	int err;
 
-	dprintk( 1, "%s\n", __FUNCTION__);
+	dprintk( 1, "%s\n", __func__);
 	dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
 		core->boardnr,
 		core->name,
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 8c9a8ad..620159d 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -44,6 +44,16 @@
 module_param(latency,int,0444);
 MODULE_PARM_DESC(latency,"pci latency timer");
 
+#define info_printk(core, fmt, arg...) \
+	printk(KERN_INFO "%s: " fmt, core->name , ## arg)
+
+#define warn_printk(core, fmt, arg...) \
+	printk(KERN_WARNING "%s: " fmt, core->name , ## arg)
+
+#define err_printk(core, fmt, arg...) \
+	printk(KERN_ERR "%s: " fmt, core->name , ## arg)
+
+
 /* ------------------------------------------------------------------ */
 /* board config info                                                  */
 
@@ -1354,6 +1364,10 @@
 		}},
 		/* fixme: Add radio support */
 		.mpeg           = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD,
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0	= 0xe780,
+		},
 	},
 	[CX88_BOARD_ADSTECH_PTV_390] = {
 		.name           = "ADS Tech Instant Video PCI",
@@ -1401,6 +1415,245 @@
 		}},
 		.mpeg           = CX88_MPEG_DVB,
 	},
+	[CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO] = {
+		.name           = "DViCO FusionHDTV 5 PCI nano",
+		/* xc3008 tuner, digital only for now */
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x000027df, /* Unconfirmed */
+		}, {
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x000027df, /* Unconfirmed */
+			.audioroute = 1,
+		}, {
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x000027df, /* Unconfirmed */
+			.audioroute = 1,
+		} },
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_PINNACLE_HYBRID_PCTV] = {
+		.name           = "Pinnacle Hybrid PCTV",
+		.tuner_type     = TUNER_XC2028,
+		.tuner_addr     = 0x61,
+		.input          = { {
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+		}, {
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+		}, {
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+		} },
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0  = 0x004ff,
+			.gpio1  = 0x010ff,
+			.gpio2  = 0x0ff,
+		},
+	},
+	[CX88_BOARD_WINFAST_TV2000_XP_GLOBAL] = {
+		.name           = "Winfast TV2000 XP Global",
+		.tuner_type     = TUNER_XC2028,
+		.tuner_addr     = 0x61,
+		.input          = { {
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x0400, /* pin 2:mute = 0 (off?) */
+			.gpio1  = 0x0000,
+			.gpio2  = 0x0800, /* pin 19:audio = 0 (tv) */
+
+		}, {
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x0400, /* probably?  or 0x0404 to turn mute on */
+			.gpio1  = 0x0000,
+			.gpio2  = 0x0808, /* pin 19:audio = 1 (line) */
+
+		}, {
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+		} },
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0  = 0x004ff,
+			.gpio1  = 0x010ff,
+			.gpio2  = 0x0ff,
+		},
+	},
+	[CX88_BOARD_POWERCOLOR_REAL_ANGEL] = {
+		.name           = "PowerColor Real Angel 330",
+		.tuner_type     = TUNER_XC2028,
+		.tuner_addr     = 0x61,
+		.input          = { {
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0 = 0x00ff,
+			.gpio1 = 0xf35d,
+			.gpio3 = 0x0000,
+		}, {
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0 = 0x00ff,
+			.gpio1 = 0xf37d,
+			.gpio3 = 0x0000,
+		}, {
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x000ff,
+			.gpio1  = 0x0f37d,
+			.gpio3  = 0x00000,
+		} },
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0  = 0x000ff,
+			.gpio1  = 0x0f35d,
+			.gpio3  = 0x00000,
+		},
+	},
+	[CX88_BOARD_GENIATECH_X8000_MT] = {
+		/* Also PowerColor Real Angel 330 and Geniatech X800 OEM */
+		.name           = "Geniatech X8000-MT DVBT",
+		.tuner_type     = TUNER_XC2028,
+		.tuner_addr     = 0x61,
+		.input          = { {
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x00000000,
+			.gpio1  = 0x00e3e341,
+			.gpio2  = 0x00000000,
+			.gpio3  = 0x00000000,
+		}, {
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x00000000,
+			.gpio1  = 0x00e3e361,
+			.gpio2  = 0x00000000,
+			.gpio3  = 0x00000000,
+		}, {
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x00000000,
+			.gpio1  = 0x00e3e361,
+			.gpio2  = 0x00000000,
+			.gpio3  = 0x00000000,
+		} },
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0  = 0x00000000,
+			.gpio1  = 0x00e3e341,
+			.gpio2  = 0x00000000,
+			.gpio3  = 0x00000000,
+		},
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO] = {
+		.name           = "DViCO FusionHDTV DVB-T PRO",
+		.tuner_type     = TUNER_ABSENT, /* XXX: Has XC3028 */
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = { {
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x000067df,
+		}, {
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x000067df,
+		} },
+		.mpeg           = CX88_MPEG_DVB,
+	},
+	[CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD] = {
+		.name           = "DViCO FusionHDTV 7 Gold",
+		.tuner_type     = TUNER_XC5000,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x10df,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x16d9,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x16d9,
+		}},
+	},
+	[CX88_BOARD_PROLINK_PV_8000GT] = {
+		.name           = "Prolink Pixelview MPEG 8000GT",
+		.tuner_type     = TUNER_XC2028,
+		.tuner_addr     = 0x61,
+		.input          = { {
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0 = 0x0ff,
+			.gpio2 = 0x0cfb,
+		}, {
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio2 = 0x0cfb,
+		}, {
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio2 = 0x0cfb,
+		} },
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio2 = 0x0cfb,
+		},
+	},
+	/* Both radio, analog and ATSC work with this board.
+	   However, for analog to work, s5h1409 gate should be open,
+	   otherwise, tuner-xc3028 won't be detected.
+	   A proper fix require using the newer i2c methods to add
+	   tuner-xc3028 without doing an i2c probe.
+	 */
+	[CX88_BOARD_KWORLD_ATSC_120] = {
+		.name           = "Kworld PlusTV HD PCI 120 (ATSC 120)",
+		.tuner_type     = TUNER_XC2028,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = { {
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x000000ff,
+			.gpio1  = 0x0000f35d,
+			.gpio2  = 0x00000000,
+		}, {
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x000000ff,
+			.gpio1  = 0x0000f37e,
+			.gpio2  = 0x00000000,
+		}, {
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x000000ff,
+			.gpio1  = 0x0000f37e,
+			.gpio2  = 0x00000000,
+		} },
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0  = 0x000000ff,
+			.gpio1  = 0x0000f35d,
+			.gpio2  = 0x00000000,
+		},
+		.mpeg           = CX88_MPEG_DVB,
+	},
 };
 
 /* ------------------------------------------------------------------ */
@@ -1605,7 +1858,11 @@
 		.subdevice = 0xdb11,
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS,
 		/* Re-branded DViCO: UltraView DVB-T Plus */
-	},{
+	}, {
+		.subvendor = 0x18ac,
+		.subdevice = 0xdb30,
+		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO,
+	}, {
 		.subvendor = 0x17de,
 		.subdevice = 0x0840,
 		.card      = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT,
@@ -1714,6 +1971,38 @@
 		.subvendor = 0x11bd,
 		.subdevice = 0x0051,
 		.card      = CX88_BOARD_PINNACLE_PCTV_HD_800i,
+	}, {
+		.subvendor = 0x18ac,
+		.subdevice = 0xd530,
+		.card      = CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO,
+	}, {
+		.subvendor = 0x12ab,
+		.subdevice = 0x1788,
+		.card      = CX88_BOARD_PINNACLE_HYBRID_PCTV,
+	}, {
+		.subvendor = 0x14f1,
+		.subdevice = 0xea3d,
+		.card      = CX88_BOARD_POWERCOLOR_REAL_ANGEL,
+	}, {
+		.subvendor = 0x107d,
+		.subdevice = 0x6f18,
+		.card      = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL,
+	}, {
+		.subvendor = 0x14f1,
+		.subdevice = 0x8852,
+		.card      = CX88_BOARD_GENIATECH_X8000_MT,
+	}, {
+		.subvendor = 0x18ac,
+		.subdevice = 0xd610,
+		.card      = CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD,
+	}, {
+		.subvendor = 0x1554,
+		.subdevice = 0x4935,
+		.card      = CX88_BOARD_PROLINK_PV_8000GT,
+	}, {
+		.subvendor = 0x17de,
+		.subdevice = 0x08c1,
+		.card      = CX88_BOARD_KWORLD_ATSC_120,
 	},
 };
 
@@ -1731,17 +2020,16 @@
 	if (eeprom_data[4] != 0x7d ||
 	    eeprom_data[5] != 0x10 ||
 	    eeprom_data[7] != 0x66) {
-		printk(KERN_WARNING "%s: Leadtek eeprom invalid.\n",
-		       core->name);
+		warn_printk(core, "Leadtek eeprom invalid.\n");
 		return;
 	}
 
 	core->board.tuner_type = (eeprom_data[6] == 0x13) ?
 		TUNER_PHILIPS_FM1236_MK3 : TUNER_PHILIPS_FM1216ME_MK3;
 
-	printk(KERN_INFO "%s: Leadtek Winfast 2000XP Expert config: "
-	       "tuner=%d, eeprom[0]=0x%02x\n",
-	       core->name, core->board.tuner_type, eeprom_data[0]);
+	info_printk(core, "Leadtek Winfast 2000XP Expert config: "
+		    "tuner=%d, eeprom[0]=0x%02x\n",
+		    core->board.tuner_type, eeprom_data[0]);
 }
 
 static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
@@ -1785,13 +2073,12 @@
 		/* known */
 		break;
 	default:
-		printk("%s: warning: unknown hauppauge model #%d\n",
-		       core->name, tv.model);
+		warn_printk(core, "warning: unknown hauppauge model #%d\n",
+			    tv.model);
 		break;
 	}
 
-	printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n",
-			core->name, tv.model);
+	info_printk(core, "hauppauge eeprom: model=%d\n", tv.model);
 }
 
 /* ----------------------------------------------------------------------- */
@@ -1837,8 +2124,7 @@
 	char *name = (eeprom_data[0x0d] < ARRAY_SIZE(gdi_tuner))
 		? gdi_tuner[eeprom_data[0x0d]].name : NULL;
 
-	printk(KERN_INFO "%s: GDI: tuner=%s\n", core->name,
-	       name ? name : "unknown");
+	info_printk(core, "GDI: tuner=%s\n", name ? name : "unknown");
 	if (NULL == name)
 		return;
 	core->board.tuner_type = gdi_tuner[eeprom_data[0x0d]].id;
@@ -1846,6 +2132,75 @@
 		CX88_RADIO : 0;
 }
 
+/* ------------------------------------------------------------------- */
+/* some Divco specific stuff                                           */
+static int cx88_dvico_xc2028_callback(struct cx88_core *core,
+				      int command, int arg)
+{
+	switch (command) {
+	case XC2028_TUNER_RESET:
+		cx_write(MO_GP0_IO, 0x101000);
+		mdelay(5);
+		cx_set(MO_GP0_IO, 0x101010);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+
+/* ----------------------------------------------------------------------- */
+/* some Geniatech specific stuff                                           */
+
+static int cx88_xc3028_geniatech_tuner_callback(struct cx88_core *core,
+						int command, int mode)
+{
+	switch (command) {
+	case XC2028_TUNER_RESET:
+		switch (INPUT(core->input).type) {
+		case CX88_RADIO:
+			break;
+		case CX88_VMUX_DVB:
+			cx_write(MO_GP1_IO, 0x030302);
+			mdelay(50);
+			break;
+		default:
+			cx_write(MO_GP1_IO, 0x030301);
+			mdelay(50);
+		}
+		cx_write(MO_GP1_IO, 0x101010);
+		mdelay(50);
+		cx_write(MO_GP1_IO, 0x101000);
+		mdelay(50);
+		cx_write(MO_GP1_IO, 0x101010);
+		mdelay(50);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+/* ------------------------------------------------------------------- */
+/* some Divco specific stuff                                           */
+static int cx88_pv_8000gt_callback(struct cx88_core *core,
+				   int command, int arg)
+{
+	switch (command) {
+	case XC2028_TUNER_RESET:
+		cx_write(MO_GP2_IO, 0xcf7);
+		mdelay(50);
+		cx_write(MO_GP2_IO, 0xef5);
+		mdelay(50);
+		cx_write(MO_GP2_IO, 0xcf7);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 /* ----------------------------------------------------------------------- */
 /* some DViCO specific stuff                                               */
 
@@ -1874,32 +2229,85 @@
 		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);
+			warn_printk(core, "dvico_fusionhdtv_hybrid_init buf %d "
+					  "failed (err = %d)!\n", i, err);
 			return;
 		}
 	}
 }
 
+static int cx88_xc2028_tuner_callback(struct cx88_core *core,
+				      int command, int arg)
+{
+	/* Board-specific callbacks */
+	switch (core->boardnr) {
+	case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
+	case CX88_BOARD_POWERCOLOR_REAL_ANGEL:
+	case CX88_BOARD_GENIATECH_X8000_MT:
+	case CX88_BOARD_KWORLD_ATSC_120:
+		return cx88_xc3028_geniatech_tuner_callback(core,
+							command, arg);
+	case CX88_BOARD_PROLINK_PV_8000GT:
+		return cx88_pv_8000gt_callback(core, command, arg);
+	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
+		return cx88_dvico_xc2028_callback(core, command, arg);
+	}
+
+	switch (command) {
+	case XC2028_TUNER_RESET:
+		switch (INPUT(core->input).type) {
+		case CX88_RADIO:
+			info_printk(core, "setting GPIO to radio!\n");
+			cx_write(MO_GP0_IO, 0x4ff);
+			mdelay(250);
+			cx_write(MO_GP2_IO, 0xff);
+			mdelay(250);
+			break;
+		case CX88_VMUX_DVB:	/* Digital TV*/
+		default:		/* Analog TV */
+			info_printk(core, "setting GPIO to TV!\n");
+			break;
+		}
+		cx_write(MO_GP1_IO, 0x101010);
+		mdelay(250);
+		cx_write(MO_GP1_IO, 0x101000);
+		mdelay(250);
+		cx_write(MO_GP1_IO, 0x101010);
+		mdelay(250);
+		return 0;
+	}
+	return -EINVAL;
+}
+
 /* ----------------------------------------------------------------------- */
 /* Tuner callback function. Currently only needed for the Pinnacle 	   *
  * PCTV HD 800i with an xc5000 sillicon tuner. This is used for both	   *
  * analog tuner attach (tuner-core.c) and dvb tuner attach (cx88-dvb.c)    */
 
-int cx88_tuner_callback(void *priv, int command, int arg)
+static int cx88_xc5000_tuner_callback(struct cx88_core *core,
+				      int command, int arg)
 {
-	struct i2c_algo_bit_data *i2c_algo = priv;
-	struct cx88_core *core = i2c_algo->data;
-
-	switch(core->boardnr) {
+	switch (core->boardnr) {
 	case CX88_BOARD_PINNACLE_PCTV_HD_800i:
-		if(command == 0) { /* This is the reset command from xc5000 */
+		if (command == 0) { /* This is the reset command from xc5000 */
 			/* Reset XC5000 tuner via SYS_RSTO_pin */
 			cx_write(MO_SRST_IO, 0);
 			msleep(10);
 			cx_write(MO_SRST_IO, 1);
 			return 0;
+		} else {
+			err_printk(core, "xc5000: unknown tuner "
+				   "callback command.\n");
+			return -EINVAL;
 		}
-		else {
+		break;
+	case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
+		if (command == 0) { /* This is the reset command from xc5000 */
+			cx_clear(MO_GP0_IO, 0x00000010);
+			msleep(10);
+			cx_set(MO_GP0_IO, 0x00000010);
+			return 0;
+		} else {
 			printk(KERN_ERR
 				"xc5000: unknown tuner callback command.\n");
 			return -EINVAL;
@@ -1908,6 +2316,36 @@
 	}
 	return 0; /* Should never be here */
 }
+
+int cx88_tuner_callback(void *priv, int command, int arg)
+{
+	struct i2c_algo_bit_data *i2c_algo = priv;
+	struct cx88_core *core;
+
+	if (!i2c_algo) {
+		printk(KERN_ERR "cx88: Error - i2c private data undefined.\n");
+		return -EINVAL;
+	}
+
+	core = i2c_algo->data;
+
+	if (!core) {
+		printk(KERN_ERR "cx88: Error - device struct undefined.\n");
+		return -EINVAL;
+	}
+
+	switch (core->board.tuner_type) {
+		case TUNER_XC2028:
+			info_printk(core, "Calling XC2028/3028 callback\n");
+			return cx88_xc2028_tuner_callback(core, command, arg);
+		case TUNER_XC5000:
+			info_printk(core, "Calling XC5000 callback\n");
+			return cx88_xc5000_tuner_callback(core, command, arg);
+	}
+	err_printk(core, "Error: Calling callback for tuner %d\n",
+		   core->board.tuner_type);
+	return -EINVAL;
+}
 EXPORT_SYMBOL(cx88_tuner_callback);
 
 /* ----------------------------------------------------------------------- */
@@ -1918,23 +2356,25 @@
 
 	if (0 == pci->subsystem_vendor &&
 	    0 == pci->subsystem_device) {
-		printk("%s: Your board has no valid PCI Subsystem ID and thus can't\n"
+		printk(KERN_ERR
+		       "%s: Your board has no valid PCI Subsystem ID and thus can't\n"
 		       "%s: be autodetected.  Please pass card=<n> insmod option to\n"
 		       "%s: workaround that.  Redirect complaints to the vendor of\n"
 		       "%s: the TV card.  Best regards,\n"
 		       "%s:         -- tux\n",
 		       core->name,core->name,core->name,core->name,core->name);
 	} else {
-		printk("%s: Your board isn't known (yet) to the driver.  You can\n"
+		printk(KERN_ERR
+		       "%s: Your board isn't known (yet) to the driver.  You can\n"
 		       "%s: try to pick one of the existing card configs via\n"
 		       "%s: card=<n> insmod option.  Updating to the latest\n"
 		       "%s: version might help as well.\n",
 		       core->name,core->name,core->name,core->name);
 	}
-	printk("%s: Here is a list of valid choices for the card=<n> insmod option:\n",
-	       core->name);
+	err_printk(core, "Here is a list of valid choices for the card=<n> "
+		   "insmod option:\n");
 	for (i = 0; i < ARRAY_SIZE(cx88_boards); i++)
-		printk("%s:    card=%d -> %s\n",
+		printk(KERN_ERR "%s:    card=%d -> %s\n",
 		       core->name, i, cx88_boards[i].name);
 }
 
@@ -1951,9 +2391,57 @@
 		cx_set(MO_GP0_IO, 0x00000080); /* 702 out of reset */
 		udelay(1000);
 		break;
+
+	case CX88_BOARD_PROLINK_PV_8000GT:
+		cx_write(MO_GP2_IO, 0xcf7);
+		mdelay(50);
+		cx_write(MO_GP2_IO, 0xef5);
+		mdelay(50);
+		cx_write(MO_GP2_IO, 0xcf7);
+		msleep(10);
+		break;
+
+	 case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
+		/* Enable the xc5000 tuner */
+		cx_set(MO_GP0_IO, 0x00001010);
+		break;
 	}
 }
 
+/*
+ * Sets board-dependent xc3028 configuration
+ */
+void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl)
+{
+	memset(ctl, 0, sizeof(*ctl));
+
+	ctl->fname   = XC2028_DEFAULT_FIRMWARE;
+	ctl->max_len = 64;
+
+	switch (core->boardnr) {
+	case CX88_BOARD_POWERCOLOR_REAL_ANGEL:
+		/* Doesn't work with firmware version 2.7 */
+		ctl->fname = "xc3028-v25.fw";
+		break;
+	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
+		ctl->scode_table = XC3028_FE_ZARLINK456;
+		break;
+	case CX88_BOARD_KWORLD_ATSC_120:
+	case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
+		ctl->demod = XC3028_FE_OREN538;
+		break;
+	case CX88_BOARD_PROLINK_PV_8000GT:
+		/*
+		 * This board uses non-MTS firmware
+		 */
+		break;
+	default:
+		ctl->demod = XC3028_FE_OREN538;
+		ctl->mts = 1;
+	}
+}
+EXPORT_SYMBOL_GPL(cx88_setup_xc3028);
+
 static void cx88_card_setup(struct cx88_core *core)
 {
 	static u8 eeprom[256];
@@ -1991,6 +2479,13 @@
 		cx_write(MO_GP0_IO, 0x000007f8);
 		cx_write(MO_GP1_IO, 0x00000001);
 		break;
+	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
+		/* GPIO0:0 is hooked to demod reset */
+		/* GPIO0:4 is hooked to xc3028 reset */
+		cx_write(MO_GP0_IO, 0x00111100);
+		msleep(1);
+		cx_write(MO_GP0_IO, 0x00111111);
+		break;
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
 		/* GPIO0:6 is hooked to FX2 reset pin */
 		cx_set(MO_GP0_IO, 0x00004040);
@@ -2038,10 +2533,8 @@
 			for (i = 0; i < ARRAY_SIZE(buffer); i++)
 				if (2 != i2c_master_send(&core->i2c_client,
 							buffer[i],2))
-					printk(KERN_WARNING
-						"%s: Unable to enable "
-						"tuner(%i).\n",
-						core->name, i);
+					warn_printk(core, "Unable to enable "
+						    "tuner(%i).\n", i);
 		}
 		break;
 	case CX88_BOARD_MSI_TVANYWHERE_MASTER:
@@ -2062,6 +2555,22 @@
 		cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tea5767_cfg);
 	}
 	}
+
+	if (core->board.tuner_type == TUNER_XC2028) {
+		struct v4l2_priv_tun_config  xc2028_cfg;
+		struct xc2028_ctrl           ctl;
+
+		/* Fills device-dependent initialization parameters */
+		cx88_setup_xc3028(core, &ctl);
+
+		/* Sends parameters to xc2028/3028 tuner */
+		memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
+		xc2028_cfg.tuner = TUNER_XC2028;
+		xc2028_cfg.priv  = &ctl;
+		info_printk(core, "Asking xc2028/3028 to load firmware %s\n",
+			    ctl.fname);
+		cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &xc2028_cfg);
+	}
 }
 
 /* ------------------------------------------------------------------ */
@@ -2178,9 +2687,8 @@
 
 	memcpy(&core->board, &cx88_boards[core->boardnr], sizeof(core->board));
 
-	printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
-		core->name,pci->subsystem_vendor,
-		pci->subsystem_device, core->board.name,
+	info_printk(core, "subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
+		pci->subsystem_vendor, pci->subsystem_device, core->board.name,
 		core->boardnr, card[core->nr] == core->boardnr ?
 		"insmod option" : "autodetected");
 
@@ -2189,8 +2697,8 @@
 	if (radio[core->nr] != UNSET)
 		core->board.radio_type = radio[core->nr];
 
-	printk(KERN_INFO "%s: TV tuner type %d, Radio tuner type %d\n",
-	       core->name, core->board.tuner_type, core->board.radio_type);
+	info_printk(core, "TV tuner type %d, Radio tuner type %d\n",
+		    core->board.tuner_type, core->board.radio_type);
 
 	/* init hardware */
 	cx88_reset(core);
@@ -2207,12 +2715,3 @@
 
 	return core;
 }
-
-/* ------------------------------------------------------------------ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
- */
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index 01e2ac9..c4d1aff 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -47,15 +47,15 @@
 
 /* ------------------------------------------------------------------ */
 
-static unsigned int core_debug = 0;
+static unsigned int core_debug;
 module_param(core_debug,int,0644);
 MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
 
-static unsigned int nicam = 0;
+static unsigned int nicam;
 module_param(nicam,int,0644);
 MODULE_PARM_DESC(nicam,"tv audio is nicam");
 
-static unsigned int nocomb = 0;
+static unsigned int nocomb;
 module_param(nocomb,int,0644);
 MODULE_PARM_DESC(nocomb,"disable comb filter");
 
@@ -219,7 +219,7 @@
 	videobuf_waiton(&buf->vb,0,0);
 	videobuf_dma_unmap(q, dma);
 	videobuf_dma_free(dma);
-	btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc);
+	btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
 	buf->vb.state = VIDEOBUF_NEEDS_INIT;
 }
 
@@ -548,7 +548,7 @@
 		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
 	}
 	if (bc != 1)
-		printk("%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc);
+		printk("%s: %d buffers handled (should be 1)\n",__func__,bc);
 }
 
 void cx88_shutdown(struct cx88_core *core)
@@ -577,7 +577,7 @@
 
 int cx88_reset(struct cx88_core *core)
 {
-	dprintk(1,"%s\n",__FUNCTION__);
+	dprintk(1,"%s\n",__func__);
 	cx88_shutdown(core);
 
 	/* clear irq status */
@@ -929,7 +929,10 @@
 
 	dprintk(1,"set_tvnorm: MO_INPUT_FORMAT  0x%08x [old=0x%08x]\n",
 		cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);
-	cx_andor(MO_INPUT_FORMAT, 0xf, cxiformat);
+	/* Chroma AGC must be disabled if SECAM is used, we enable it
+	   by default on PAL and NTSC */
+	cx_andor(MO_INPUT_FORMAT, 0x40f,
+		 norm & V4L2_STD_SECAM ? cxiformat : cxiformat | 0x400);
 
 	// FIXME: as-is from DScaler
 	dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n",
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index f7b41eb..f1251b8 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -45,16 +45,20 @@
 #include "nxt200x.h"
 #include "cx24123.h"
 #include "isl6421.h"
+#include "tuner-simple.h"
+#include "tda9887.h"
 
 MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
 MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
 
-static unsigned int debug = 0;
+static unsigned int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug,"enable debug messages [dvb]");
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 #define dprintk(level,fmt, arg...)	if (debug >= level) \
 	printk(KERN_DEBUG "%s/2-dvb: " fmt, core->name, ## arg)
 
@@ -235,6 +239,19 @@
 	.no_tuner      = 1,
 };
 
+static struct zl10353_config dvico_fusionhdtv_xc3028 = {
+	.demod_address = 0x0f,
+	.if2           = 45600,
+	.no_tuner      = 1,
+};
+
+static struct mt352_config dvico_fusionhdtv_mt352_xc3028 = {
+	.demod_address = 0x0f,
+	.if2 = 4560,
+	.no_tuner = 1,
+	.demod_init = dvico_fusionhdtv_demod_init,
+};
+
 static struct zl10353_config dvico_fusionhdtv_plus_v1_1 = {
 	.demod_address = 0x0f,
 };
@@ -266,7 +283,7 @@
 	struct cx8802_dev *dev= fe->dvb->priv;
 	struct cx88_core *core = dev->core;
 
-	dprintk(1, "%s: index = %d\n", __FUNCTION__, index);
+	dprintk(1, "%s: index = %d\n", __func__, index);
 	if (index == 0)
 		cx_clear(MO_GP0_IO, 8);
 	else
@@ -357,6 +374,40 @@
 	return 0;
 }
 
+static int cx88_pci_nano_callback(void *ptr, int command, int arg)
+{
+	struct cx88_core *core = ptr;
+
+	switch (command) {
+	case XC2028_TUNER_RESET:
+		/* Send the tuner in then out of reset */
+		dprintk(1, "%s: XC2028_TUNER_RESET %d\n", __func__, arg);
+
+		switch (core->boardnr) {
+		case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
+			/* GPIO-4 xc3028 tuner */
+
+			cx_set(MO_GP0_IO, 0x00001000);
+			cx_clear(MO_GP0_IO, 0x00000010);
+			msleep(100);
+			cx_set(MO_GP0_IO, 0x00000010);
+			msleep(100);
+			break;
+		}
+
+		break;
+	case XC2028_RESET_CLK:
+		dprintk(1, "%s: XC2028_RESET_CLK %d\n", __func__, arg);
+		break;
+	default:
+		dprintk(1, "%s: unknown command %d, arg %d\n", __func__,
+			command, arg);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static struct cx24123_config geniatech_dvbs_config = {
 	.demod_address = 0x55,
 	.set_ts_params = cx24123_set_ts_param,
@@ -383,12 +434,76 @@
 	.mpeg_timing   = S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK,
 };
 
+static struct s5h1409_config dvico_hdtv5_pci_nano_config = {
+	.demod_address = 0x32 >> 1,
+	.output_mode   = S5H1409_SERIAL_OUTPUT,
+	.gpio          = S5H1409_GPIO_OFF,
+	.inversion     = S5H1409_INVERSION_OFF,
+	.status_mode   = S5H1409_DEMODLOCKING,
+	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct s5h1409_config kworld_atsc_120_config = {
+	.demod_address = 0x32 >> 1,
+	.output_mode   = S5H1409_SERIAL_OUTPUT,
+	.gpio	       = S5H1409_GPIO_OFF,
+	.inversion     = S5H1409_INVERSION_OFF,
+	.status_mode   = S5H1409_DEMODLOCKING,
+	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
 static struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = {
 	.i2c_address	= 0x64,
 	.if_khz		= 5380,
 	.tuner_callback	= cx88_tuner_callback,
 };
 
+static struct zl10353_config cx88_geniatech_x8000_mt = {
+       .demod_address = (0x1e >> 1),
+       .no_tuner = 1,
+};
+
+static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
+{
+	struct dvb_frontend *fe;
+	struct xc2028_ctrl ctl;
+	struct xc2028_config cfg = {
+		.i2c_adap  = &dev->core->i2c_adap,
+		.i2c_addr  = addr,
+		.ctrl      = &ctl,
+		.callback  = cx88_tuner_callback,
+	};
+
+	if (!dev->dvb.frontend) {
+		printk(KERN_ERR "%s/2: dvb frontend not attached. "
+				"Can't attach xc3028\n",
+		       dev->core->name);
+		return -EINVAL;
+	}
+
+	/*
+	 * Some xc3028 devices may be hidden by an I2C gate. This is known
+	 * to happen with some s5h1409-based devices.
+	 * Now that I2C gate is open, sets up xc3028 configuration
+	 */
+	cx88_setup_xc3028(dev->core, &ctl);
+
+	fe = dvb_attach(xc2028_attach, dev->dvb.frontend, &cfg);
+	if (!fe) {
+		printk(KERN_ERR "%s/2: xc3028 attach failed\n",
+		       dev->core->name);
+		dvb_frontend_detach(dev->dvb.frontend);
+		dvb_unregister_frontend(dev->dvb.frontend);
+		dev->dvb.frontend = NULL;
+		return -EINVAL;
+	}
+
+	printk(KERN_INFO "%s/2: xc3028 attached\n",
+	       dev->core->name);
+
+	return 0;
+}
+
 static int dvb_register(struct cx8802_dev *dev)
 {
 	/* init struct videobuf_dvb */
@@ -429,8 +544,9 @@
 					       &hauppauge_hvr_config,
 					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-				   &dev->core->i2c_adap, DVB_PLL_FMD1216ME);
+			dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+				   &dev->core->i2c_adap, 0x61,
+				   TUNER_PHILIPS_FMD1216ME_MK3);
 		}
 		break;
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
@@ -497,8 +613,9 @@
 		dev->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
 					       &dev->vp3054->adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-				   &dev->core->i2c_adap, DVB_PLL_FMD1216ME);
+			dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+				   &dev->core->i2c_adap, 0x61,
+				   TUNER_PHILIPS_FMD1216ME_MK3);
 		}
 #else
 		printk(KERN_ERR "%s/2: built without vp3054 support\n", dev->core->name);
@@ -509,18 +626,36 @@
 					       &dvico_fusionhdtv_hybrid,
 					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-				   &dev->core->i2c_adap,
-				   DVB_PLL_THOMSON_FE6600);
+			dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+				   &dev->core->i2c_adap, 0x61,
+				   TUNER_THOMSON_FE6600);
 		}
 		break;
+	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
+		dev->dvb.frontend = dvb_attach(zl10353_attach,
+					       &dvico_fusionhdtv_xc3028,
+					       &dev->core->i2c_adap);
+		if (dev->dvb.frontend == NULL)
+			dev->dvb.frontend = dvb_attach(mt352_attach,
+						&dvico_fusionhdtv_mt352_xc3028,
+						&dev->core->i2c_adap);
+		/*
+		 * On this board, the demod provides the I2C bus pullup.
+		 * We must not permit gate_ctrl to be performed, or
+		 * the xc3028 cannot communicate on the bus.
+		 */
+		if (dev->dvb.frontend)
+			dev->dvb.frontend->ops.i2c_gate_ctrl = NULL;
+		if (attach_xc3028(0x61, dev) < 0)
+			return -EINVAL;
+		break;
 	case CX88_BOARD_PCHDTV_HD3000:
 		dev->dvb.frontend = dvb_attach(or51132_attach, &pchdtv_hd3000,
 					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-				   &dev->core->i2c_adap,
-				   DVB_PLL_THOMSON_DTT761X);
+			dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+				   &dev->core->i2c_adap, 0x61,
+				   TUNER_THOMSON_DTT761X);
 		}
 		break;
 	case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
@@ -540,9 +675,9 @@
 					       &fusionhdtv_3_gold,
 					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-				   &dev->core->i2c_adap,
-				   DVB_PLL_MICROTUNE_4042);
+			dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+				   &dev->core->i2c_adap, 0x61,
+				   TUNER_MICROTUNE_4042FI5);
 		}
 		}
 		break;
@@ -560,9 +695,9 @@
 					       &fusionhdtv_3_gold,
 					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-				   &dev->core->i2c_adap,
-				   DVB_PLL_THOMSON_DTT761X);
+			dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+				   &dev->core->i2c_adap, 0x61,
+				   TUNER_THOMSON_DTT761X);
 		}
 		}
 		break;
@@ -580,9 +715,11 @@
 					       &fusionhdtv_5_gold,
 					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-				   &dev->core->i2c_adap,
-				   DVB_PLL_LG_TDVS_H06XF);
+			dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+				   &dev->core->i2c_adap, 0x61,
+				   TUNER_LG_TDVS_H06XF);
+			dvb_attach(tda9887_attach, dev->dvb.frontend,
+				   &dev->core->i2c_adap, 0x43);
 		}
 		}
 		break;
@@ -600,9 +737,11 @@
 					       &pchdtv_hd5500,
 					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-				   &dev->core->i2c_adap,
-				   DVB_PLL_LG_TDVS_H06XF);
+			dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+				   &dev->core->i2c_adap, 0x61,
+				   TUNER_LG_TDVS_H06XF);
+			dvb_attach(tda9887_attach, dev->dvb.frontend,
+				   &dev->core->i2c_adap, 0x43);
 		}
 		}
 		break;
@@ -611,8 +750,9 @@
 					       &ati_hdtvwonder,
 					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-				   NULL, DVB_PLL_TUV1236D);
+			dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+				   &dev->core->i2c_adap, 0x61,
+				   TUNER_PHILIPS_TUV1236D);
 		}
 		break;
 	case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
@@ -658,14 +798,62 @@
 				   &pinnacle_pctv_hd_800i_tuner_config);
 		}
 		break;
+	case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
+		dev->dvb.frontend = dvb_attach(s5h1409_attach,
+						&dvico_hdtv5_pci_nano_config,
+						&dev->core->i2c_adap);
+		if (dev->dvb.frontend != NULL) {
+			struct dvb_frontend *fe;
+			struct xc2028_config cfg = {
+				.i2c_adap  = &dev->core->i2c_adap,
+				.i2c_addr  = 0x61,
+				.callback  = cx88_pci_nano_callback,
+			};
+			static struct xc2028_ctrl ctl = {
+				.fname       = "xc3028-v27.fw",
+				.max_len     = 64,
+				.scode_table = XC3028_FE_OREN538,
+			};
+
+			fe = dvb_attach(xc2028_attach,
+					dev->dvb.frontend, &cfg);
+			if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+				fe->ops.tuner_ops.set_config(fe, &ctl);
+		}
+		break;
+	 case CX88_BOARD_PINNACLE_HYBRID_PCTV:
+		dev->dvb.frontend = dvb_attach(zl10353_attach,
+					       &cx88_geniatech_x8000_mt,
+					       &dev->core->i2c_adap);
+		if (attach_xc3028(0x61, dev) < 0)
+			return -EINVAL;
+		break;
+	 case CX88_BOARD_GENIATECH_X8000_MT:
+		dev->ts_gen_cntrl = 0x00;
+
+		dev->dvb.frontend = dvb_attach(zl10353_attach,
+					       &cx88_geniatech_x8000_mt,
+					       &dev->core->i2c_adap);
+		if (attach_xc3028(0x61, dev) < 0)
+			return -EINVAL;
+		break;
+	 case CX88_BOARD_KWORLD_ATSC_120:
+		dev->dvb.frontend = dvb_attach(s5h1409_attach,
+					       &kworld_atsc_120_config,
+					       &dev->core->i2c_adap);
+		if (attach_xc3028(0x61, dev) < 0)
+			return -EINVAL;
+		break;
 	default:
 		printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
 		       dev->core->name);
 		break;
 	}
 	if (NULL == dev->dvb.frontend) {
-		printk(KERN_ERR "%s/2: frontend initialization failed\n", dev->core->name);
-		return -1;
+		printk(KERN_ERR
+		       "%s/2: frontend initialization failed\n",
+		       dev->core->name);
+		return -EINVAL;
 	}
 
 	/* Ensure all frontends negotiate bus access */
@@ -675,7 +863,8 @@
 	cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
 
 	/* register everything */
-	return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev);
+	return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev,
+				     &dev->pci->dev, adapter_nr);
 }
 
 /* ----------------------------------------------------------- */
@@ -685,7 +874,7 @@
 {
 	struct cx88_core *core = drv->core;
 	int err = 0;
-	dprintk( 1, "%s\n", __FUNCTION__);
+	dprintk( 1, "%s\n", __func__);
 
 	switch (core->boardnr) {
 	case CX88_BOARD_HAUPPAUGE_HVR1300:
@@ -708,7 +897,7 @@
 {
 	struct cx88_core *core = drv->core;
 	int err = 0;
-	dprintk( 1, "%s\n", __FUNCTION__);
+	dprintk( 1, "%s\n", __func__);
 
 	switch (core->boardnr) {
 	case CX88_BOARD_HAUPPAUGE_HVR1300:
@@ -726,7 +915,7 @@
 	struct cx8802_dev *dev = drv->core->dvbdev;
 	int err;
 
-	dprintk( 1, "%s\n", __FUNCTION__);
+	dprintk( 1, "%s\n", __func__);
 	dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
 		core->boardnr,
 		core->name,
@@ -744,8 +933,8 @@
 
 	/* dvb stuff */
 	printk(KERN_INFO "%s/2: cx2388x based DVB/ATSC card\n", core->name);
-	videobuf_queue_pci_init(&dev->dvb.dvbq, &dvb_qops,
-			    dev->pci, &dev->slock,
+	videobuf_queue_sg_init(&dev->dvb.dvbq, &dvb_qops,
+			    &dev->pci->dev, &dev->slock,
 			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
 			    V4L2_FIELD_TOP,
 			    sizeof(struct cx88_buffer),
@@ -764,7 +953,8 @@
 	struct cx8802_dev *dev = drv->core->dvbdev;
 
 	/* dvb */
-	videobuf_dvb_unregister(&dev->dvb);
+	if (dev->dvb.frontend)
+		videobuf_dvb_unregister(&dev->dvb);
 
 	vp3054_i2c_remove(dev);
 
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index 566b26a..c6b4473 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -35,11 +35,11 @@
 #include "cx88.h"
 #include <media/v4l2-common.h>
 
-static unsigned int i2c_debug = 0;
+static unsigned int i2c_debug;
 module_param(i2c_debug, int, 0644);
 MODULE_PARM_DESC(i2c_debug,"enable debug messages [i2c]");
 
-static unsigned int i2c_scan = 0;
+static unsigned int i2c_scan;
 module_param(i2c_scan, int, 0444);
 MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time");
 
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index bb0911b..53526d9 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -57,7 +57,7 @@
 	u32 mask_keyup;
 };
 
-static int ir_debug = 0;
+static int ir_debug;
 module_param(ir_debug, int, 0644);	/* debug level [IR] */
 MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
 
@@ -258,6 +258,13 @@
 		ir->mask_keyup = 0x80;
 		ir->polling = 1; /* ms */
 		break;
+	case CX88_BOARD_PROLINK_PV_8000GT:
+		ir_codes = ir_codes_pixelview_new;
+		ir->gpio_addr = MO_GP1_IO;
+		ir->mask_keycode = 0x3f;
+		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;
@@ -310,6 +317,12 @@
 		ir_type = IR_TYPE_RC5;
 		ir->sampling = 1;
 		break;
+	case CX88_BOARD_POWERCOLOR_REAL_ANGEL:
+		ir_codes = ir_codes_powercolor_real_angel;
+		ir->gpio_addr = MO_GP2_IO;
+		ir->mask_keycode = 0x7e;
+		ir->polling = 100; /* ms */
+		break;
 	}
 
 	if (NULL == ir_codes) {
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index e357f41..a6b061c 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -39,7 +39,7 @@
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
 
-static unsigned int debug = 0;
+static unsigned int debug;
 module_param(debug,int,0644);
 MODULE_PARM_DESC(debug,"enable debug messages [mpeg]");
 
@@ -146,7 +146,7 @@
 		cx_write(TS_GEN_CNTRL, 0x06); /* punctured clock TS & posedge driven */
 		udelay(100);
 	} else {
-		printk( "%s() Failed. Unsupported value in .mpeg (0x%08x)\n", __FUNCTION__,
+		printk( "%s() Failed. Unsupported value in .mpeg (0x%08x)\n", __func__,
 			core->board.mpeg );
 		return -EINVAL;
 	}
@@ -247,7 +247,7 @@
 	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
 	int rc;
 
-	dprintk(1, "%s: %p\n", __FUNCTION__, buf);
+	dprintk(1, "%s: %p\n", __func__, buf);
 	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
 		return -EINVAL;
 
@@ -289,7 +289,7 @@
 		buf->count    = cx88q->count++;
 		mod_timer(&cx88q->timeout, jiffies+BUFFER_TIMEOUT);
 		dprintk(1,"[%p/%d] %s - first active\n",
-			buf, buf->vb.i, __FUNCTION__);
+			buf, buf->vb.i, __func__);
 
 	} else {
 		dprintk( 1, "queue is not empty - append to active\n" );
@@ -299,7 +299,7 @@
 		buf->count    = cx88q->count++;
 		prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
 		dprintk( 1, "[%p/%d] %s - append to active\n",
-			buf, buf->vb.i, __FUNCTION__);
+			buf, buf->vb.i, __func__);
 	}
 }
 
@@ -342,7 +342,7 @@
 {
 	struct cx8802_dev *dev = (struct cx8802_dev*)data;
 
-	dprintk(1, "%s\n",__FUNCTION__);
+	dprintk(1, "%s\n",__func__);
 
 	if (debug)
 		cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH28]);
@@ -613,6 +613,8 @@
 	    core->active_type_id != drv->type_id)
 		return -EBUSY;
 
+	core->input = CX88_VMUX_DVB;
+
 	if (drv->advise_acquire)
 	{
 		mutex_lock(&drv->core->lock);
@@ -623,7 +625,7 @@
 		}
 		mutex_unlock(&drv->core->lock);
 
-		mpeg_dbg(1,"%s() Post acquire GPIO=%x\n", __FUNCTION__, cx_read(MO_GP0_IO));
+		mpeg_dbg(1,"%s() Post acquire GPIO=%x\n", __func__, cx_read(MO_GP0_IO));
 	}
 
 	return 0;
@@ -639,7 +641,7 @@
 	{
 		drv->advise_release(drv);
 		core->active_type_id = CX88_BOARD_NONE;
-		mpeg_dbg(1,"%s() Post release GPIO=%x\n", __FUNCTION__, cx_read(MO_GP0_IO));
+		mpeg_dbg(1,"%s() Post release GPIO=%x\n", __func__, cx_read(MO_GP0_IO));
 	}
 	mutex_unlock(&drv->core->lock);
 
@@ -813,7 +815,7 @@
 
 	dev = pci_get_drvdata(pci_dev);
 
-	dprintk( 1, "%s\n", __FUNCTION__);
+	dprintk( 1, "%s\n", __func__);
 
 	if (!list_empty(&dev->drvlist)) {
 		struct cx8802_driver *drv, *tmp;
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
index 76e5c78..3a1977f 100644
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/video/cx88/cx88-tvaudio.c
@@ -53,15 +53,15 @@
 
 #include "cx88.h"
 
-static unsigned int audio_debug = 0;
+static unsigned int audio_debug;
 module_param(audio_debug, int, 0644);
 MODULE_PARM_DESC(audio_debug, "enable debug messages [audio]");
 
-static unsigned int always_analog = 0;
+static unsigned int always_analog;
 module_param(always_analog,int,0644);
 MODULE_PARM_DESC(always_analog,"force analog audio out");
 
-static unsigned int radio_deemphasis = 0;
+static unsigned int radio_deemphasis;
 module_param(radio_deemphasis,int,0644);
 MODULE_PARM_DESC(radio_deemphasis, "Radio deemphasis time constant, "
 		 "0=None, 1=50us (elsewhere), 2=75us (USA)");
@@ -265,12 +265,12 @@
 	mode |= EN_FMRADIO_EN_RDS;
 
 	if (sap) {
-		dprintk("%s SAP (status: unknown)\n", __FUNCTION__);
+		dprintk("%s SAP (status: unknown)\n", __func__);
 		set_audio_start(core, SEL_SAP);
 		set_audio_registers(core, btsc_sap);
 		set_audio_finish(core, mode);
 	} else {
-		dprintk("%s (status: known-good)\n", __FUNCTION__);
+		dprintk("%s (status: known-good)\n", __func__);
 		set_audio_start(core, SEL_BTSC);
 		set_audio_registers(core, btsc);
 		set_audio_finish(core, mode);
@@ -351,16 +351,16 @@
 	set_audio_start(core,SEL_NICAM);
 	switch (core->tvaudio) {
 	case WW_L:
-		dprintk("%s SECAM-L NICAM (status: devel)\n", __FUNCTION__);
+		dprintk("%s SECAM-L NICAM (status: devel)\n", __func__);
 		set_audio_registers(core, nicam_l);
 		break;
 	case WW_I:
-		dprintk("%s PAL-I NICAM (status: known-good)\n", __FUNCTION__);
+		dprintk("%s PAL-I NICAM (status: known-good)\n", __func__);
 		set_audio_registers(core, nicam_bgdki_common);
 		set_audio_registers(core, nicam_i);
 		break;
 	default:
-		dprintk("%s PAL-BGDK NICAM (status: known-good)\n", __FUNCTION__);
+		dprintk("%s PAL-BGDK NICAM (status: known-good)\n", __func__);
 		set_audio_registers(core, nicam_bgdki_common);
 		set_audio_registers(core, nicam_default);
 		break;
@@ -600,28 +600,28 @@
 	set_audio_start(core, SEL_A2);
 	switch (core->tvaudio) {
 	case WW_BG:
-		dprintk("%s PAL-BG A1/2 (status: known-good)\n", __FUNCTION__);
+		dprintk("%s PAL-BG A1/2 (status: known-good)\n", __func__);
 		set_audio_registers(core, a2_bgdk_common);
 		set_audio_registers(core, a2_bg);
 		set_audio_registers(core, a2_deemph50);
 		break;
 	case WW_DK:
-		dprintk("%s PAL-DK A1/2 (status: known-good)\n", __FUNCTION__);
+		dprintk("%s PAL-DK A1/2 (status: known-good)\n", __func__);
 		set_audio_registers(core, a2_bgdk_common);
 		set_audio_registers(core, a2_dk);
 		set_audio_registers(core, a2_deemph50);
 		break;
 	case WW_I:
-		dprintk("%s PAL-I A1 (status: known-good)\n", __FUNCTION__);
+		dprintk("%s PAL-I A1 (status: known-good)\n", __func__);
 		set_audio_registers(core, a1_i);
 		set_audio_registers(core, a2_deemph50);
 		break;
 	case WW_L:
-		dprintk("%s AM-L (status: devel)\n", __FUNCTION__);
+		dprintk("%s AM-L (status: devel)\n", __func__);
 		set_audio_registers(core, am_l);
 		break;
 	default:
-		dprintk("%s Warning: wrong value\n", __FUNCTION__);
+		dprintk("%s Warning: wrong value\n", __func__);
 		return;
 		break;
 	};
@@ -637,7 +637,7 @@
 
 		{ /* end of list */ },
 	};
-	dprintk("%s (status: unknown)\n", __FUNCTION__);
+	dprintk("%s (status: unknown)\n", __func__);
 
 	set_audio_start(core, SEL_EIAJ);
 	set_audio_registers(core, eiaj);
@@ -691,7 +691,7 @@
 		{ /* end of list */ },
 	};
 
-	dprintk("%s (status: unknown)\n", __FUNCTION__);
+	dprintk("%s (status: unknown)\n", __func__);
 	set_audio_start(core, SEL_FMRADIO);
 
 	switch (deemph) {
diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c
index d96ecfc..0943060 100644
--- a/drivers/media/video/cx88/cx88-vbi.c
+++ b/drivers/media/video/cx88/cx88-vbi.c
@@ -11,7 +11,7 @@
 module_param(vbibufs,int,0644);
 MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32");
 
-static unsigned int vbi_debug = 0;
+static unsigned int vbi_debug;
 module_param(vbi_debug,int,0644);
 MODULE_PARM_DESC(vbi_debug,"enable debug messages [vbi]");
 
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 2271796..eea23f9 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -63,11 +63,11 @@
 MODULE_PARM_DESC(vbi_nr,"vbi device numbers");
 MODULE_PARM_DESC(radio_nr,"radio device numbers");
 
-static unsigned int video_debug = 0;
+static unsigned int video_debug;
 module_param(video_debug,int,0644);
 MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
 
-static unsigned int irq_debug = 0;
+static unsigned int irq_debug;
 module_param(irq_debug,int,0644);
 MODULE_PARM_DESC(irq_debug,"enable debug messages [IRQ handler]");
 
@@ -228,6 +228,30 @@
 		.mask                  = 0x00ff,
 		.shift                 = 0,
 	},{
+		.v = {
+			.id            = V4L2_CID_CHROMA_AGC,
+			.name          = "Chroma AGC",
+			.minimum       = 0,
+			.maximum       = 1,
+			.default_value = 0x1,
+			.type          = V4L2_CTRL_TYPE_BOOLEAN,
+		},
+		.reg                   = MO_INPUT_FORMAT,
+		.mask                  = 1 << 10,
+		.shift                 = 10,
+	}, {
+		.v = {
+			.id            = V4L2_CID_COLOR_KILLER,
+			.name          = "Color killer",
+			.minimum       = 0,
+			.maximum       = 1,
+			.default_value = 0x1,
+			.type          = V4L2_CTRL_TYPE_BOOLEAN,
+		},
+		.reg                   = MO_INPUT_FORMAT,
+		.mask                  = 1 << 9,
+		.shift                 = 9,
+	}, {
 	/* --- audio --- */
 		.v = {
 			.id            = V4L2_CID_AUDIO_MUTE,
@@ -282,6 +306,8 @@
 	V4L2_CID_AUDIO_VOLUME,
 	V4L2_CID_AUDIO_BALANCE,
 	V4L2_CID_AUDIO_MUTE,
+	V4L2_CID_CHROMA_AGC,
+	V4L2_CID_COLOR_KILLER,
 	0
 };
 EXPORT_SYMBOL(cx88_user_ctrls);
@@ -291,7 +317,7 @@
 	NULL
 };
 
-int cx8800_ctrl_query(struct v4l2_queryctrl *qctrl)
+int cx8800_ctrl_query(struct cx88_core *core, struct v4l2_queryctrl *qctrl)
 {
 	int i;
 
@@ -306,6 +332,11 @@
 		return 0;
 	}
 	*qctrl = cx8800_ctls[i].v;
+	/* Report chroma AGC as inactive when SECAM is selected */
+	if (cx8800_ctls[i].v.id == V4L2_CID_CHROMA_AGC &&
+	    core->tvnorm & V4L2_STD_SECAM)
+		qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+
 	return 0;
 }
 EXPORT_SYMBOL(cx8800_ctrl_query);
@@ -776,14 +807,14 @@
 	fh->height   = 240;
 	fh->fmt      = format_by_fourcc(V4L2_PIX_FMT_BGR24);
 
-	videobuf_queue_pci_init(&fh->vidq, &cx8800_video_qops,
-			    dev->pci, &dev->slock,
+	videobuf_queue_sg_init(&fh->vidq, &cx8800_video_qops,
+			    &dev->pci->dev, &dev->slock,
 			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
 			    V4L2_FIELD_INTERLACED,
 			    sizeof(struct cx88_buffer),
 			    fh);
-	videobuf_queue_pci_init(&fh->vbiq, &cx8800_vbi_qops,
-			    dev->pci, &dev->slock,
+	videobuf_queue_sg_init(&fh->vbiq, &cx8800_vbi_qops,
+			    &dev->pci->dev, &dev->slock,
 			    V4L2_BUF_TYPE_VBI_CAPTURE,
 			    V4L2_FIELD_SEQ_TB,
 			    sizeof(struct cx88_buffer),
@@ -976,6 +1007,12 @@
 		}
 		mask=0xffff;
 		break;
+	case V4L2_CID_CHROMA_AGC:
+		/* Do not allow chroma AGC to be enabled for SECAM */
+		value = ((ctl->value - c->off) << c->shift) & c->mask;
+		if (core->tvnorm & V4L2_STD_SECAM && value)
+			return -EINVAL;
+		break;
 	default:
 		value = ((ctl->value - c->off) << c->shift) & c->mask;
 		break;
@@ -1268,10 +1305,12 @@
 static int vidioc_queryctrl (struct file *file, void *priv,
 				struct v4l2_queryctrl *qctrl)
 {
+	struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
+
 	qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
 	if (unlikely(qctrl->id == 0))
 		return -EINVAL;
-	return cx8800_ctrl_query(qctrl);
+	return cx8800_ctrl_query(core, qctrl);
 }
 
 static int vidioc_g_ctrl (struct file *file, void *priv,
@@ -1832,8 +1871,11 @@
 
 	switch (core->boardnr) {
 	case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
-		request_module("ir-kbd-i2c");
+	case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
 		request_module("rtc-isl1208");
+		/* break intentionally omitted */
+	case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
+		request_module("ir-kbd-i2c");
 	}
 
 	/* register v4l devices */
@@ -1917,6 +1959,9 @@
 		core->kthread = NULL;
 	}
 
+	if (core->ir)
+		cx88_ir_stop(core, core->ir);
+
 	cx88_shutdown(core); /* FIXME */
 	pci_disable_device(pci_dev);
 
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index 37e6d2e..14ac173 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -37,6 +37,7 @@
 
 #include "btcx-risc.h"
 #include "cx88-reg.h"
+#include "tuner-xc2028.h"
 
 #include <linux/version.h>
 #include <linux/mutex.h>
@@ -211,6 +212,15 @@
 #define CX88_BOARD_HAUPPAUGE_HVR1300       56
 #define CX88_BOARD_ADSTECH_PTV_390         57
 #define CX88_BOARD_PINNACLE_PCTV_HD_800i   58
+#define CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO 59
+#define CX88_BOARD_PINNACLE_HYBRID_PCTV    60
+#define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL 61
+#define CX88_BOARD_POWERCOLOR_REAL_ANGEL   62
+#define CX88_BOARD_GENIATECH_X8000_MT      63
+#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO 64
+#define CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD 65
+#define CX88_BOARD_PROLINK_PV_8000GT       66
+#define CX88_BOARD_KWORLD_ATSC_120         67
 
 enum cx88_itype {
 	CX88_VMUX_COMPOSITE1 = 1,
@@ -595,6 +605,7 @@
 extern int cx88_get_resources(const struct cx88_core *core,
 			      struct pci_dev *pci);
 extern struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr);
+extern void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl);
 
 /* ----------------------------------------------------------- */
 /* cx88-tvaudio.c                                              */
@@ -640,7 +651,8 @@
 /* ----------------------------------------------------------- */
 /* cx88-video.c*/
 extern const u32 cx88_user_ctrls[];
-extern int cx8800_ctrl_query(struct v4l2_queryctrl *qctrl);
+extern int cx8800_ctrl_query(struct cx88_core *core,
+			     struct v4l2_queryctrl *qctrl);
 int cx88_enum_input (struct cx88_core  *core,struct v4l2_input *i);
 int cx88_set_freq (struct cx88_core  *core,struct v4l2_frequency *f);
 int cx88_get_control(struct cx88_core *core, struct v4l2_control *ctl);
diff --git a/drivers/media/video/dabfirmware.h b/drivers/media/video/dabfirmware.h
index d14d803..cbd9263 100644
--- a/drivers/media/video/dabfirmware.h
+++ b/drivers/media/video/dabfirmware.h
@@ -1,5 +1,12 @@
 /*
  * dabdata.h - dab usb firmware and bitstream data
+ *
+ * Copyright (C) 1999 BayCom GmbH
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that redistributions of source
+ * code retain the above copyright notice and this comment without
+ * modification.
  */
 
 static INTEL_HEX_RECORD firmware[] = {
diff --git a/drivers/media/video/dabusb.c b/drivers/media/video/dabusb.c
index a5731f9..8d1f8ee 100644
--- a/drivers/media/video/dabusb.c
+++ b/drivers/media/video/dabusb.c
@@ -205,7 +205,7 @@
 /*-------------------------------------------------------------------*/
 static int dabusb_alloc_buffers (pdabusb_t s)
 {
-	int buffers = 0;
+	int transfer_len = 0;
 	pbuff_t b;
 	unsigned int pipe = usb_rcvisocpipe (s->usbdev, _DABUSB_ISOPIPE);
 	int pipesize = usb_maxpacket (s->usbdev, pipe, usb_pipeout (pipe));
@@ -216,7 +216,7 @@
 	dbg("dabusb_alloc_buffers pipesize:%d packets:%d transfer_buffer_len:%d",
 		 pipesize, packets, transfer_buffer_length);
 
-	while (buffers < (s->total_buffer_size << 10)) {
+	while (transfer_len < (s->total_buffer_size << 10)) {
 		b = kzalloc(sizeof (buff_t), GFP_KERNEL);
 		if (!b) {
 			err("kzalloc(sizeof(buff_t))==NULL");
@@ -251,10 +251,10 @@
 			b->purb->iso_frame_desc[i].length = pipesize;
 		}
 
-		buffers += transfer_buffer_length;
+		transfer_len += transfer_buffer_length;
 		list_add_tail (&b->buff_list, &s->free_buff_list);
 	}
-	s->got_mem = buffers;
+	s->got_mem = transfer_len;
 
 	return 0;
 
diff --git a/drivers/media/video/dpc7146.c b/drivers/media/video/dpc7146.c
index 9ceb6b2..88d6df7 100644
--- a/drivers/media/video/dpc7146.c
+++ b/drivers/media/video/dpc7146.c
@@ -54,11 +54,11 @@
 
 #define DPC_BOARD_CAN_DO_VBI(dev)   (dev->revision != 0)
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "debug verbosity");
 
-static int dpc_num = 0;
+static int dpc_num;
 
 #define DPC_INPUTS	2
 static struct v4l2_input dpc_inputs[DPC_INPUTS] = {
diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig
index 0f7a0bd..9caffed 100644
--- a/drivers/media/video/em28xx/Kconfig
+++ b/drivers/media/video/em28xx/Kconfig
@@ -1,11 +1,13 @@
 config VIDEO_EM28XX
-	tristate "Empia EM2800/2820/2840 USB video capture support"
+	tristate "Empia EM28xx USB video capture support"
 	depends on VIDEO_DEV && I2C && INPUT
 	select VIDEO_TUNER
 	select VIDEO_TVEEPROM
 	select VIDEO_IR
+	select VIDEOBUF_VMALLOC
 	select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
 	select VIDEO_TVP5150 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO
 	---help---
 	  This is a video4linux driver for Empia 28xx based TV cards.
 
@@ -27,3 +29,13 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called em28xx-alsa
 
+config VIDEO_EM28XX_DVB
+	tristate "DVB/ATSC Support for em28xx based TV cards"
+	depends on VIDEO_EM28XX && DVB_CORE
+	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+	select VIDEOBUF_DVB
+	select FW_LOADER
+	---help---
+	  This adds support for DVB cards based on the
+	  Empiatech em28xx chips.
diff --git a/drivers/media/video/em28xx/Makefile b/drivers/media/video/em28xx/Makefile
index 0924550..3d1c3cc 100644
--- a/drivers/media/video/em28xx/Makefile
+++ b/drivers/media/video/em28xx/Makefile
@@ -5,6 +5,7 @@
 
 obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
 obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o
+obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o
 
 EXTRA_CFLAGS += -Idrivers/media/video
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c
index 8c67f67..92b2a6d 100644
--- a/drivers/media/video/em28xx/em28xx-audio.c
+++ b/drivers/media/video/em28xx/em28xx-audio.c
@@ -51,7 +51,7 @@
 #define dprintk(fmt, arg...) do {					\
 	    if (debug)							\
 		printk(KERN_INFO "em28xx-audio %s: " fmt,		\
-				  __FUNCTION__, ##arg); 		\
+				  __func__, ##arg); 		\
 	} while (0)
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index aae7753..50ccf37 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -36,7 +36,6 @@
 #include <media/v4l2-common.h>
 
 #include "em28xx.h"
-#include "tuner-xc2028.h"
 
 static int tuner = -1;
 module_param(tuner, int, 0444);
@@ -52,26 +51,6 @@
 	unsigned int  tuner;
 };
 
-/* Boards supported by driver */
-
-#define EM2800_BOARD_UNKNOWN			0
-#define EM2820_BOARD_UNKNOWN			1
-#define EM2820_BOARD_TERRATEC_CINERGY_250	2
-#define EM2820_BOARD_PINNACLE_USB_2		3
-#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2      4
-#define EM2820_BOARD_MSI_VOX_USB_2              5
-#define EM2800_BOARD_TERRATEC_CINERGY_200       6
-#define EM2800_BOARD_LEADTEK_WINFAST_USBII      7
-#define EM2800_BOARD_KWORLD_USB2800             8
-#define EM2820_BOARD_PINNACLE_DVC_90		9
-#define 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 EM2820_BOARD_PROLINK_PLAYTV_USB2	14
-#define EM2800_BOARD_VGEAR_POCKETTV             15
-#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950	16
-
 struct em28xx_board em28xx_boards[] = {
 	[EM2800_BOARD_UNKNOWN] = {
 		.name         = "Unknown EM2800 video grabber",
@@ -200,6 +179,7 @@
 		.tuner_type     = TUNER_XC2028,
 		.mts_firmware   = 1,
 		.has_12mhz_i2s  = 1,
+		.has_dvb        = 1,
 		.decoder        = EM28XX_TVP5150,
 		.input          = { {
 			.type     = EM28XX_VMUX_TELEVISION,
@@ -214,9 +194,6 @@
 			.vmux     = TVP5150_SVIDEO,
 			.amux     = 1,
 		} },
-
-		/* gpio's 4, 1, 0 */
-		.analog_gpio = 0x003d2d,
 	},
 	[EM2880_BOARD_TERRATEC_HYBRID_XS] = {
 		.name         = "Terratec Hybrid XS",
@@ -331,7 +308,7 @@
 		.name         = "Kworld USB2800",
 		.is_em2800    = 1,
 		.vchannels    = 3,
-		.tuner_type   = TUNER_PHILIPS_ATSC,
+		.tuner_type   = TUNER_PHILIPS_FCV1236D,
 		.tda9887_conf = TDA9887_PRESENT,
 		.decoder      = EM28XX_SAA7113,
 		.input          = { {
@@ -453,7 +430,36 @@
 };
 MODULE_DEVICE_TABLE(usb, em28xx_id_table);
 
-/* EEPROM hash table for devices with generic USB IDs */
+/*
+ *  Reset sequences for analog/digital modes
+ */
+
+/* Board Hauppauge WinTV HVR 900 analog */
+static struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = {
+	{EM28XX_R08_GPIO,	0x2d,	~EM_GPIO_4,	10},
+	{0x05,			0xff,	0x10,		10},
+	{  -1,			-1,	-1,		-1},
+};
+
+/* Board Hauppauge WinTV HVR 900 digital */
+static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = {
+	{EM28XX_R08_GPIO,	0x2e,	~EM_GPIO_4,	10},
+	{EM2880_R04_GPO,	0x04,	0x0f,		10},
+	{EM2880_R04_GPO,	0x0c,	0x0f,		10},
+	{ -1,			-1,	-1,		-1},
+};
+
+/* Board Hauppauge WinTV HVR 900 tuner_callback */
+static struct em28xx_reg_seq hauppauge_wintv_hvr_900_tuner_callback[] = {
+	{EM28XX_R08_GPIO,	EM_GPIO_4,	EM_GPIO_4,	10},
+	{EM28XX_R08_GPIO,	0,		EM_GPIO_4,	10},
+	{EM28XX_R08_GPIO,	EM_GPIO_4,	EM_GPIO_4,	10},
+	{  -1,			-1,		-1,		-1},
+};
+
+/*
+ * EEPROM hash table for devices with generic USB IDs
+ */
 static struct em28xx_hash_table em28xx_eeprom_hash [] = {
 	/* P/N: SA 60002070465 Tuner: TVF7533-MF */
 	{0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF},
@@ -465,34 +471,7 @@
 	{0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC},
 };
 
-/* Since em28xx_pre_card_setup() requires a proper dev->model,
- * this won't work for boards with generic PCI IDs
- */
-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_HAUPPAUGE_WINTV_HVR_950:
-	case EM2880_BOARD_TERRATEC_HYBRID_XS:
-		em28xx_write_regs(dev, XCLK_REG, "\x27", 1);
-		em28xx_write_regs(dev, I2C_CLK_REG, "\x40", 1);
-		em28xx_write_regs(dev, 0x08, "\xff", 1);
-		em28xx_write_regs(dev, 0x04, "\x00", 1);
-		msleep(100);
-		em28xx_write_regs(dev, 0x04, "\x08", 1);
-		msleep(100);
-		em28xx_write_regs(dev, 0x08, "\xff", 1);
-		msleep(50);
-		em28xx_write_regs(dev, 0x08, "\x2d", 1);
-		msleep(50);
-		em28xx_write_regs(dev, 0x08, "\x3d", 1);
-		break;
-	}
-}
-
-static int em28xx_tuner_callback(void *ptr, int command, int arg)
+int em28xx_tuner_callback(void *ptr, int command, int arg)
 {
 	int rc = 0;
 	struct em28xx *dev = ptr;
@@ -500,44 +479,105 @@
 	if (dev->tuner_type != TUNER_XC2028)
 		return 0;
 
-	switch (command) {
-	case XC2028_TUNER_RESET:
-	{
-		/* GPIO and initialization codes for analog TV and radio
-		   This code should be complemented for DTV, since reset
-		   codes are different.
-		 */
+	if (command != XC2028_TUNER_RESET)
+		return 0;
 
-		dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1);
-		dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1);
+	if (dev->mode == EM28XX_ANALOG_MODE)
+		rc = em28xx_gpio_set(dev, dev->tun_analog_gpio);
+	else
+		rc = em28xx_gpio_set(dev, dev->tun_digital_gpio);
 
-		if (dev->analog_gpio) {
-			char gpio0 = dev->analog_gpio & 0xff;
-			char gpio1 = (dev->analog_gpio >> 8) & 0xff;
-			char gpio4 = dev->analog_gpio >> 24;
+	return rc;
+}
+EXPORT_SYMBOL_GPL(em28xx_tuner_callback);
 
-			if (gpio4) {
-				dev->em28xx_write_regs(dev, 0x04, &gpio4, 1);
-				msleep(140);
-			}
+static void em28xx_set_model(struct em28xx *dev)
+{
+	dev->is_em2800 = em28xx_boards[dev->model].is_em2800;
+	dev->has_msp34xx = em28xx_boards[dev->model].has_msp34xx;
+	dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf;
+	dev->decoder = em28xx_boards[dev->model].decoder;
+	dev->video_inputs = em28xx_boards[dev->model].vchannels;
+	dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s;
+	dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480;
+	dev->has_dvb = em28xx_boards[dev->model].has_dvb;
+}
 
-			msleep(6);
-			dev->em28xx_write_regs(dev, 0x08, &gpio0, 1);
-			msleep(10);
-			dev->em28xx_write_regs(dev, 0x08, &gpio1, 1);
-			msleep(5);
+/* Since em28xx_pre_card_setup() requires a proper dev->model,
+ * this won't work for boards with generic PCI IDs
+ */
+void em28xx_pre_card_setup(struct em28xx *dev)
+{
+	int rc;
+
+	rc = em28xx_read_reg(dev, EM2880_R04_GPO);
+	if (rc >= 0)
+		dev->reg_gpo = rc;
+
+	dev->wait_after_write = 5;
+	rc = em28xx_read_reg(dev, EM28XX_R0A_CHIPID);
+	if (rc > 0) {
+		switch (rc) {
+		case CHIP_ID_EM2883:
+			em28xx_info("chip ID is em2882/em2883\n");
+			dev->wait_after_write = 0;
+			break;
+		default:
+			em28xx_info("em28xx chip ID = %d\n", rc);
 		}
+	}
+	em28xx_set_model(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:
+	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
+		em28xx_write_regs(dev, EM28XX_R0F_XCLK,    "\x27", 1);
+		em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
+		msleep(50);
+
+		/* Sets GPO/GPIO sequences for this device */
+		dev->analog_gpio      = hauppauge_wintv_hvr_900_analog;
+		dev->digital_gpio     = hauppauge_wintv_hvr_900_digital;
+		dev->tun_analog_gpio  = hauppauge_wintv_hvr_900_tuner_callback;
+		dev->tun_digital_gpio = hauppauge_wintv_hvr_900_tuner_callback;
 
 		break;
 	}
+
+	em28xx_gpio_set(dev, dev->tun_analog_gpio);
+	em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
+
+	/* Unlock device */
+	em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+}
+
+static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
+{
+	memset(ctl, 0, sizeof(*ctl));
+
+	ctl->fname   = XC2028_DEFAULT_FIRMWARE;
+	ctl->max_len = 64;
+	ctl->mts = em28xx_boards[dev->model].mts_firmware;
+
+	switch (dev->model) {
+	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+		ctl->demod = XC3028_FE_ZARLINK456;
+		break;
+	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
+		/* FIXME: Better to specify the needed IF */
+		ctl->demod = XC3028_FE_DEFAULT;
+		break;
+	default:
+		ctl->demod = XC3028_FE_OREN538;
 	}
-	return rc;
 }
 
 static void em28xx_config_tuner(struct em28xx *dev)
 {
 	struct v4l2_priv_tun_config  xc2028_cfg;
-	struct xc2028_ctrl           ctl;
 	struct tuner_setup           tun_setup;
 	struct v4l2_frequency        f;
 
@@ -552,11 +592,9 @@
 	em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
 
 	if (dev->tuner_type == TUNER_XC2028) {
-		memset(&ctl, 0, sizeof(ctl));
+		struct xc2028_ctrl           ctl;
 
-		ctl.fname   = XC2028_DEFAULT_FIRMWARE;
-		ctl.max_len = 64;
-		ctl.mts = em28xx_boards[dev->model].mts_firmware;
+		em28xx_setup_xc3028(dev, &ctl);
 
 		xc2028_cfg.tuner = TUNER_XC2028;
 		xc2028_cfg.priv  = &ctl;
@@ -654,19 +692,6 @@
 	return -1;
 }
 
-
-static void em28xx_set_model(struct em28xx *dev)
-{
-	dev->is_em2800 = em28xx_boards[dev->model].is_em2800;
-	dev->has_msp34xx = em28xx_boards[dev->model].has_msp34xx;
-	dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf;
-	dev->decoder = em28xx_boards[dev->model].decoder;
-	dev->video_inputs = em28xx_boards[dev->model].vchannels;
-	dev->analog_gpio = em28xx_boards[dev->model].analog_gpio;
-	dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s;
-	dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480;
-}
-
 /* ----------------------------------------------------------------------- */
 void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir)
 {
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index c1caaa8..f8c41d8 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -31,104 +31,33 @@
 
 /* #define ENABLE_DEBUG_ISOC_FRAMES */
 
-static unsigned int core_debug = 0;
+static unsigned int core_debug;
 module_param(core_debug,int,0644);
 MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
 
 #define em28xx_coredbg(fmt, arg...) do {\
 	if (core_debug) \
 		printk(KERN_INFO "%s %s :"fmt, \
-			 dev->name, __FUNCTION__ , ##arg); } while (0)
+			 dev->name, __func__ , ##arg); } while (0)
 
-static unsigned int reg_debug = 0;
+static unsigned int reg_debug;
 module_param(reg_debug,int,0644);
 MODULE_PARM_DESC(reg_debug,"enable debug messages [URB reg]");
 
 #define em28xx_regdbg(fmt, arg...) do {\
 	if (reg_debug) \
 		printk(KERN_INFO "%s %s :"fmt, \
-			 dev->name, __FUNCTION__ , ##arg); } while (0)
-
-static unsigned int isoc_debug = 0;
-module_param(isoc_debug,int,0644);
-MODULE_PARM_DESC(isoc_debug,"enable debug messages [isoc transfers]");
-
-#define em28xx_isocdbg(fmt, arg...) do {\
-	if (isoc_debug) \
-		printk(KERN_INFO "%s %s :"fmt, \
-			 dev->name, __FUNCTION__ , ##arg); } while (0)
+			 dev->name, __func__ , ##arg); } while (0)
 
 static int alt = EM28XX_PINOUT;
 module_param(alt, int, 0644);
 MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
 
-
-/*
- * em28xx_request_buffers()
- * allocate a number of buffers
- */
-u32 em28xx_request_buffers(struct em28xx *dev, u32 count)
-{
-	const size_t imagesize = PAGE_ALIGN(dev->frame_size);	/*needs to be page aligned cause the buffers can be mapped individually! */
-	void *buff = NULL;
-	u32 i;
-	em28xx_coredbg("requested %i buffers with size %zi\n",
-			count, imagesize);
-	if (count > EM28XX_NUM_FRAMES)
-		count = EM28XX_NUM_FRAMES;
-
-	dev->num_frames = count;
-	while (dev->num_frames > 0) {
-		if ((buff = vmalloc_32(dev->num_frames * imagesize))) {
-			memset(buff, 0, dev->num_frames * imagesize);
-			break;
-		}
-		dev->num_frames--;
-	}
-
-	for (i = 0; i < dev->num_frames; i++) {
-		dev->frame[i].bufmem = buff + i * imagesize;
-		dev->frame[i].buf.index = i;
-		dev->frame[i].buf.m.offset = i * imagesize;
-		dev->frame[i].buf.length = dev->frame_size;
-		dev->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		dev->frame[i].buf.sequence = 0;
-		dev->frame[i].buf.field = V4L2_FIELD_NONE;
-		dev->frame[i].buf.memory = V4L2_MEMORY_MMAP;
-		dev->frame[i].buf.flags = 0;
-	}
-	return dev->num_frames;
-}
-
-/*
- * em28xx_queue_unusedframes()
- * add all frames that are not currently in use to the inbuffer queue
- */
-void em28xx_queue_unusedframes(struct em28xx *dev)
-{
-	unsigned long lock_flags;
-	u32 i;
-
-	for (i = 0; i < dev->num_frames; i++)
-		if (dev->frame[i].state == F_UNUSED) {
-			dev->frame[i].state = F_QUEUED;
-			spin_lock_irqsave(&dev->queue_lock, lock_flags);
-			list_add_tail(&dev->frame[i].frame, &dev->inqueue);
-			spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
-		}
-}
-
-/*
- * em28xx_release_buffers()
- * free frame buffers
- */
-void em28xx_release_buffers(struct em28xx *dev)
-{
-	if (dev->num_frames) {
-		vfree(dev->frame[0].bufmem);
-		dev->num_frames = 0;
-	}
-}
+/* FIXME */
+#define em28xx_isocdbg(fmt, arg...) do {\
+	if (core_debug) \
+		printk(KERN_INFO "%s %s :"fmt, \
+			 dev->name, __func__ , ##arg); } while (0)
 
 /*
  * em28xx_read_reg_req()
@@ -148,11 +77,11 @@
 			      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			      0x0000, reg, buf, len, HZ);
 
-	if (reg_debug){
+	if (reg_debug) {
 		printk(ret < 0 ? " failed!\n" : "%02x values: ", ret);
-		for (byte = 0; byte < len; byte++) {
+		for (byte = 0; byte < len; byte++)
 			printk(" %02x", (unsigned char)buf[byte]);
-		}
+
 		printk("\n");
 	}
 
@@ -205,7 +134,10 @@
 	unsigned char *bufs;
 
 	if (dev->state & DEV_DISCONNECTED)
-		return(-ENODEV);
+		return -ENODEV;
+
+	if (len < 1)
+		return -EINVAL;
 
 	bufs = kmalloc(len, GFP_KERNEL);
 
@@ -214,8 +146,8 @@
 	if (reg_debug) {
 		int i;
 		for (i = 0; i < len; ++i)
-			printk (" %02x", (unsigned char)buf[i]);
-		printk ("\n");
+			printk(" %02x", (unsigned char)buf[i]);
+		printk("\n");
 	}
 
 	if (!bufs)
@@ -224,14 +156,32 @@
 	ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), req,
 			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			      0x0000, reg, bufs, len, HZ);
-	msleep(5);		/* FIXME: magic number */
+	if (dev->wait_after_write)
+		msleep(dev->wait_after_write);
+
 	kfree(bufs);
 	return ret;
 }
 
 int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len)
 {
-	return em28xx_write_regs_req(dev, USB_REQ_GET_STATUS, reg, buf, len);
+	int rc;
+
+	rc = em28xx_write_regs_req(dev, USB_REQ_GET_STATUS, reg, buf, len);
+
+	/* Stores GPO/GPIO values at the cache, if changed
+	   Only write values should be stored, since input on a GPIO
+	   register will return the input bits.
+	   Not sure what happens on reading GPO register.
+	 */
+	if (rc >= 0) {
+		if (reg == EM2880_R04_GPO)
+			dev->reg_gpo = buf[0];
+		else if (reg == EM28XX_R08_GPIO)
+			dev->reg_gpio = buf[0];
+	}
+
+	return rc;
 }
 
 /*
@@ -244,9 +194,20 @@
 {
 	int oldval;
 	u8 newval;
-	if ((oldval = em28xx_read_reg(dev, reg)) < 0)
+
+	/* Uses cache for gpo/gpio registers */
+	if (reg == EM2880_R04_GPO)
+		oldval = dev->reg_gpo;
+	else if (reg == EM28XX_R08_GPIO)
+		oldval = dev->reg_gpio;
+	else
+		oldval = em28xx_read_reg(dev, reg);
+
+	if (oldval < 0)
 		return oldval;
+
 	newval = (((u8) oldval) & ~bitmask) | (val & bitmask);
+
 	return em28xx_write_regs(dev, reg, &newval, 1);
 }
 
@@ -258,20 +219,26 @@
 {
 	int ret, i;
 	u8 addr = reg & 0x7f;
-	if ((ret = em28xx_write_regs(dev, AC97LSB_REG, val, 2)) < 0)
+
+	ret = em28xx_write_regs(dev, EM28XX_R40_AC97LSB, val, 2);
+	if (ret < 0)
 		return ret;
-	if ((ret = em28xx_write_regs(dev, AC97ADDR_REG, &addr, 1)) < 0)
+
+	ret = em28xx_write_regs(dev, EM28XX_R42_AC97ADDR, &addr, 1);
+	if (ret < 0)
 		return ret;
 
 	/* Wait up to 50 ms for AC97 command to complete */
 	for (i = 0; i < 10; i++) {
-		if ((ret = em28xx_read_reg(dev, AC97BUSY_REG)) < 0)
+		ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY);
+		if (ret < 0)
 			return ret;
+
 		if (!(ret & 0x01))
 			return 0;
 		msleep(5);
 	}
-	em28xx_warn ("AC97 command still being executed: not handled properly!\n");
+	em28xx_warn("AC97 command still being executed: not handled properly!\n");
 	return 0;
 }
 
@@ -289,7 +256,7 @@
 		else
 			input = EM2800_AUDIO_SRC_TUNER;
 
-		ret = em28xx_write_regs(dev, EM2800_AUDIOSRC_REG, &input, 1);
+		ret = em28xx_write_regs(dev, EM2800_R08_AUDIOSRC, &input, 1);
 		if (ret < 0)
 			return ret;
 	}
@@ -315,7 +282,7 @@
 		}
 	}
 
-	ret = em28xx_write_reg_bits(dev, AUDIOSRC_REG, input, 0xc0);
+	ret = em28xx_write_reg_bits(dev, EM28XX_R0E_AUDIOSRC, input, 0xc0);
 	if (ret < 0)
 		return ret;
 	msleep(5);
@@ -323,11 +290,11 @@
 	/* Sets AC97 mixer registers
 	   This is seems to be needed, even for non-ac97 configs
 	 */
-	ret = em28xx_write_ac97(dev, VIDEO_AC97, video);
+	ret = em28xx_write_ac97(dev, EM28XX_R14_VIDEO_AC97, video);
 	if (ret < 0)
 		return ret;
 
-	ret = em28xx_write_ac97(dev, LINE_IN_AC97, line);
+	ret = em28xx_write_ac97(dev, EM28XX_R10_LINE_IN_AC97, line);
 
 	return ret;
 }
@@ -343,7 +310,7 @@
 
 	/* Mute */
 	s[1] |= 0x80;
-	ret = em28xx_write_ac97(dev, MASTER_AC97, s);
+	ret = em28xx_write_ac97(dev, EM28XX_R02_MASTER_AC97, s);
 
 	if (ret < 0)
 		return ret;
@@ -354,7 +321,7 @@
 	if (!dev->mute)
 		xclk |= 0x80;
 
-	ret = em28xx_write_reg_bits(dev, XCLK_REG, xclk, 0xa7);
+	ret = em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, xclk, 0xa7);
 	if (ret < 0)
 		return ret;
 	msleep(10);
@@ -365,7 +332,7 @@
 	/* Unmute device */
 	if (!dev->mute)
 		s[1] &= ~0x80;
-	ret = em28xx_write_ac97(dev, MASTER_AC97, s);
+	ret = em28xx_write_ac97(dev, EM28XX_R02_MASTER_AC97, s);
 
 	return ret;
 }
@@ -373,50 +340,68 @@
 
 int em28xx_colorlevels_set_default(struct em28xx *dev)
 {
-	em28xx_write_regs(dev, YGAIN_REG, "\x10", 1);	/* contrast */
-	em28xx_write_regs(dev, YOFFSET_REG, "\x00", 1);	/* brightness */
-	em28xx_write_regs(dev, UVGAIN_REG, "\x10", 1);	/* saturation */
-	em28xx_write_regs(dev, UOFFSET_REG, "\x00", 1);
-	em28xx_write_regs(dev, VOFFSET_REG, "\x00", 1);
-	em28xx_write_regs(dev, SHARPNESS_REG, "\x00", 1);
+	em28xx_write_regs(dev, EM28XX_R20_YGAIN, "\x10", 1);	/* contrast */
+	em28xx_write_regs(dev, EM28XX_R21_YOFFSET, "\x00", 1);	/* brightness */
+	em28xx_write_regs(dev, EM28XX_R22_UVGAIN, "\x10", 1);	/* saturation */
+	em28xx_write_regs(dev, EM28XX_R23_UOFFSET, "\x00", 1);
+	em28xx_write_regs(dev, EM28XX_R24_VOFFSET, "\x00", 1);
+	em28xx_write_regs(dev, EM28XX_R25_SHARPNESS, "\x00", 1);
 
-	em28xx_write_regs(dev, GAMMA_REG, "\x20", 1);
-	em28xx_write_regs(dev, RGAIN_REG, "\x20", 1);
-	em28xx_write_regs(dev, GGAIN_REG, "\x20", 1);
-	em28xx_write_regs(dev, BGAIN_REG, "\x20", 1);
-	em28xx_write_regs(dev, ROFFSET_REG, "\x00", 1);
-	em28xx_write_regs(dev, GOFFSET_REG, "\x00", 1);
-	return em28xx_write_regs(dev, BOFFSET_REG, "\x00", 1);
+	em28xx_write_regs(dev, EM28XX_R14_GAMMA, "\x20", 1);
+	em28xx_write_regs(dev, EM28XX_R15_RGAIN, "\x20", 1);
+	em28xx_write_regs(dev, EM28XX_R16_GGAIN, "\x20", 1);
+	em28xx_write_regs(dev, EM28XX_R17_BGAIN, "\x20", 1);
+	em28xx_write_regs(dev, EM28XX_R18_ROFFSET, "\x00", 1);
+	em28xx_write_regs(dev, EM28XX_R19_GOFFSET, "\x00", 1);
+	return em28xx_write_regs(dev, EM28XX_R1A_BOFFSET, "\x00", 1);
 }
 
 int em28xx_capture_start(struct em28xx *dev, int start)
 {
-	int ret;
+	int rc;
 	/* FIXME: which is the best order? */
 	/* video registers are sampled by VREF */
-	if ((ret = em28xx_write_reg_bits(dev, USBSUSP_REG, start ? 0x10 : 0x00,
-					  0x10)) < 0)
-		return ret;
+	rc = em28xx_write_reg_bits(dev, EM28XX_R0C_USBSUSP,
+				   start ? 0x10 : 0x00, 0x10);
+	if (rc < 0)
+		return rc;
+
+	if (!start) {
+		/* disable video capture */
+		rc = em28xx_write_regs(dev, EM28XX_R12_VINENABLE, "\x27", 1);
+		return rc;
+	}
+
 	/* enable video capture */
-	return em28xx_write_regs(dev, VINENABLE_REG, start ? "\x67" : "\x27", 1);
+	rc = em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1);
+
+	if (dev->mode == EM28XX_ANALOG_MODE)
+		rc = em28xx_write_regs(dev, EM28XX_R12_VINENABLE, "\x67", 1);
+	else
+		rc = em28xx_write_regs(dev, EM28XX_R12_VINENABLE, "\x37", 1);
+
+	msleep(6);
+
+	return rc;
 }
 
 int em28xx_outfmt_set_yuv422(struct em28xx *dev)
 {
-	em28xx_write_regs(dev, OUTFMT_REG, "\x34", 1);
-	em28xx_write_regs(dev, VINMODE_REG, "\x10", 1);
-	return em28xx_write_regs(dev, VINCTRL_REG, "\x11", 1);
+	em28xx_write_regs(dev, EM28XX_R27_OUTFMT, "\x34", 1);
+	em28xx_write_regs(dev, EM28XX_R10_VINMODE, "\x10", 1);
+	return em28xx_write_regs(dev, EM28XX_R11_VINCTRL, "\x11", 1);
 }
 
 static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
 				  u8 ymin, u8 ymax)
 {
-	em28xx_coredbg("em28xx Scale: (%d,%d)-(%d,%d)\n", xmin, ymin, xmax, ymax);
+	em28xx_coredbg("em28xx Scale: (%d,%d)-(%d,%d)\n",
+			xmin, ymin, xmax, ymax);
 
-	em28xx_write_regs(dev, XMIN_REG, &xmin, 1);
-	em28xx_write_regs(dev, XMAX_REG, &xmax, 1);
-	em28xx_write_regs(dev, YMIN_REG, &ymin, 1);
-	return em28xx_write_regs(dev, YMAX_REG, &ymax, 1);
+	em28xx_write_regs(dev, EM28XX_R28_XMIN, &xmin, 1);
+	em28xx_write_regs(dev, EM28XX_R29_XMAX, &xmax, 1);
+	em28xx_write_regs(dev, EM28XX_R2A_YMIN, &ymin, 1);
+	return em28xx_write_regs(dev, EM28XX_R2B_YMAX, &ymax, 1);
 }
 
 static int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
@@ -426,34 +411,36 @@
 	u8 cheight = height;
 	u8 overflow = (height >> 7 & 0x02) | (width >> 8 & 0x01);
 
-	em28xx_coredbg("em28xx Area Set: (%d,%d)\n", (width | (overflow & 2) << 7),
+	em28xx_coredbg("em28xx Area Set: (%d,%d)\n",
+			(width | (overflow & 2) << 7),
 			(height | (overflow & 1) << 8));
 
-	em28xx_write_regs(dev, HSTART_REG, &hstart, 1);
-	em28xx_write_regs(dev, VSTART_REG, &vstart, 1);
-	em28xx_write_regs(dev, CWIDTH_REG, &cwidth, 1);
-	em28xx_write_regs(dev, CHEIGHT_REG, &cheight, 1);
-	return em28xx_write_regs(dev, OFLOW_REG, &overflow, 1);
+	em28xx_write_regs(dev, EM28XX_R1C_HSTART, &hstart, 1);
+	em28xx_write_regs(dev, EM28XX_R1D_VSTART, &vstart, 1);
+	em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1);
+	em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1);
+	return em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1);
 }
 
 static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
 {
 	u8 mode;
 	/* the em2800 scaler only supports scaling down to 50% */
-	if(dev->is_em2800)
+	if (dev->is_em2800)
 		mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
 	else {
 		u8 buf[2];
 		buf[0] = h;
 		buf[1] = h >> 8;
-		em28xx_write_regs(dev, HSCALELOW_REG, (char *)buf, 2);
+		em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2);
 		buf[0] = v;
 		buf[1] = v >> 8;
-		em28xx_write_regs(dev, VSCALELOW_REG, (char *)buf, 2);
-		/* it seems that both H and V scalers must be active to work correctly */
+		em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2);
+		/* it seems that both H and V scalers must be active
+		   to work correctly */
 		mode = (h || v)? 0x30: 0x00;
 	}
-	return em28xx_write_reg_bits(dev, COMPR_REG, mode, 0x30);
+	return em28xx_write_reg_bits(dev, EM28XX_R26_COMPR, mode, 0x30);
 }
 
 /* FIXME: this only function read values from dev */
@@ -469,363 +456,31 @@
 	return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
 }
 
-
-/******************* isoc transfer handling ****************************/
-
-#ifdef ENABLE_DEBUG_ISOC_FRAMES
-static void em28xx_isoc_dump(struct urb *urb)
-{
-	int len = 0;
-	int ntrans = 0;
-	int i;
-
-	printk(KERN_DEBUG "isocIrq: sf=%d np=%d ec=%x\n",
-	       urb->start_frame, urb->number_of_packets,
-	       urb->error_count);
-	for (i = 0; i < urb->number_of_packets; i++) {
-		unsigned char *buf =
-				urb->transfer_buffer +
-				urb->iso_frame_desc[i].offset;
-		int alen = urb->iso_frame_desc[i].actual_length;
-		if (alen > 0) {
-			if (buf[0] == 0x88) {
-				ntrans++;
-				len += alen;
-			} else if (buf[0] == 0x22) {
-				printk(KERN_DEBUG
-						"= l=%d nt=%d bpp=%d\n",
-				len - 4 * ntrans, ntrans,
-				ntrans == 0 ? 0 : len / ntrans);
-				ntrans = 1;
-				len = alen;
-			} else
-				printk(KERN_DEBUG "!\n");
-		}
-		printk(KERN_DEBUG "   n=%d s=%d al=%d %x\n", i,
-		       urb->iso_frame_desc[i].status,
-		       urb->iso_frame_desc[i].actual_length,
-		       (unsigned int)
-				       *((unsigned char *)(urb->transfer_buffer +
-				       urb->iso_frame_desc[i].
-				       offset)));
-	}
-}
-#endif
-
-static inline int em28xx_isoc_video(struct em28xx *dev,struct em28xx_frame_t **f,
-				    unsigned long *lock_flags, unsigned char buf)
-{
-	if (!(buf & 0x01)) {
-		if ((*f)->state == F_GRABBING) {
-			/*previous frame is incomplete */
-			if ((*f)->fieldbytesused < dev->field_size) {
-				(*f)->state = F_ERROR;
-				em28xx_isocdbg ("dropping incomplete bottom field (%i missing bytes)",
-					 dev->field_size-(*f)->fieldbytesused);
-			} else {
-				(*f)->state = F_DONE;
-				(*f)->buf.bytesused = dev->frame_size;
-			}
-		}
-		if ((*f)->state == F_DONE || (*f)->state == F_ERROR) {
-			/* move current frame to outqueue and get next free buffer from inqueue */
-			spin_lock_irqsave(&dev-> queue_lock, *lock_flags);
-			list_move_tail(&(*f)->frame, &dev->outqueue);
-			if (!list_empty(&dev->inqueue))
-				(*f) = list_entry(dev-> inqueue.next,
-			struct em28xx_frame_t,frame);
-			else
-				(*f) = NULL;
-			spin_unlock_irqrestore(&dev->queue_lock,*lock_flags);
-		}
-		if (!(*f)) {
-			em28xx_isocdbg ("new frame but no buffer is free");
-			return -1;
-		}
-		do_gettimeofday(&(*f)->buf.timestamp);
-		(*f)->buf.sequence = ++dev->frame_count;
-		(*f)->buf.field = V4L2_FIELD_INTERLACED;
-		(*f)->state = F_GRABBING;
-		(*f)->buf.bytesused = 0;
-		(*f)->top_field = 1;
-		(*f)->fieldbytesused = 0;
-	} else {
-					/* acquiring bottom field */
-		if ((*f)->state == F_GRABBING) {
-			if (!(*f)->top_field) {
-				(*f)->state = F_ERROR;
-				em28xx_isocdbg ("unexpected begin of bottom field; discarding it");
-			} else if ((*f)-> fieldbytesused < dev->field_size - 172) {
-				(*f)->state = F_ERROR;
-				em28xx_isocdbg ("dropping incomplete top field (%i missing bytes)",
-					 dev->field_size-(*f)->fieldbytesused);
-			} else {
-				(*f)->top_field = 0;
-				(*f)->fieldbytesused = 0;
-			}
-		}
-	}
-	return (0);
-}
-
-static inline void em28xx_isoc_video_copy(struct em28xx *dev,
-					  struct em28xx_frame_t **f, unsigned char *buf, int len)
-{
-	void *fieldstart, *startwrite, *startread;
-	int linesdone, currlinedone, offset, lencopy,remain;
-
-	if(dev->frame_size != (*f)->buf.length){
-		em28xx_err("frame_size %i and buf.length %i are different!!!\n",dev->frame_size,(*f)->buf.length);
-		return;
-	}
-
-	if ((*f)->fieldbytesused + len > dev->field_size)
-		len =dev->field_size - (*f)->fieldbytesused;
-
-	if (buf[0] != 0x88 && buf[0] != 0x22) {
-		em28xx_isocdbg("frame is not complete\n");
-		startread = buf;
-		len+=4;
-	} else
-		startread = buf + 4;
-
-	remain = len;
-
-	if ((*f)->top_field)
-		fieldstart = (*f)->bufmem;
-	else
-		fieldstart = (*f)->bufmem + dev->bytesperline;
-
-	linesdone = (*f)->fieldbytesused / dev->bytesperline;
-	currlinedone = (*f)->fieldbytesused % dev->bytesperline;
-	offset = linesdone * dev->bytesperline * 2 + currlinedone;
-	startwrite = fieldstart + offset;
-	lencopy = dev->bytesperline - currlinedone;
-	lencopy = lencopy > remain ? remain : lencopy;
-
-	memcpy(startwrite, startread, lencopy);
-	remain -= lencopy;
-
-	while (remain > 0) {
-		startwrite += lencopy + dev->bytesperline;
-		startread += lencopy;
-		if (dev->bytesperline > remain)
-			lencopy = remain;
-		else
-			lencopy = dev->bytesperline;
-
-		memcpy(startwrite, startread, lencopy);
-		remain -= lencopy;
-	}
-
-	(*f)->fieldbytesused += len;
-}
-
-/*
- * em28xx_isoIrq()
- * handles the incoming isoc urbs and fills the frames from our inqueue
- */
-static void em28xx_isocIrq(struct urb *urb)
-{
-	struct em28xx *dev = urb->context;
-	int i, status;
-	struct em28xx_frame_t **f;
-	unsigned long lock_flags;
-
-	if (!dev)
-		return;
-#ifdef ENABLE_DEBUG_ISOC_FRAMES
-	if (isoc_debug>1)
-		em28xx_isoc_dump(urb);
-#endif
-
-	if (urb->status == -ENOENT)
-		return;
-
-	f = &dev->frame_current;
-
-	if (dev->stream == STREAM_INTERRUPT) {
-		dev->stream = STREAM_OFF;
-		if ((*f))
-			(*f)->state = F_QUEUED;
-		em28xx_isocdbg("stream interrupted");
-		wake_up_interruptible(&dev->wait_stream);
-	}
-
-	if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
-		return;
-
-	if (dev->stream == STREAM_ON && !list_empty(&dev->inqueue)) {
-		if (!(*f))
-			(*f) = list_entry(dev->inqueue.next,
-		struct em28xx_frame_t, frame);
-
-		for (i = 0; i < urb->number_of_packets; i++) {
-			unsigned char *buf = urb->transfer_buffer +
-					urb->iso_frame_desc[i].offset;
-			int len = urb->iso_frame_desc[i].actual_length - 4;
-
-			if (urb->iso_frame_desc[i].status) {
-				em28xx_isocdbg("data error: [%d] len=%d, status=%d", i,
-					urb->iso_frame_desc[i].actual_length,
-					urb->iso_frame_desc[i].status);
-				if (urb->iso_frame_desc[i].status != -EPROTO)
-					continue;
-			}
-			if (urb->iso_frame_desc[i].actual_length <= 0) {
-				em28xx_isocdbg("packet %d is empty",i);
-				continue;
-			}
-			if (urb->iso_frame_desc[i].actual_length >
-			    urb->iso_frame_desc[i].length) {
-				em28xx_isocdbg("packet bigger than packet size");
-				continue;
-			}
-			/*new frame */
-			if (buf[0] == 0x22 && buf[1] == 0x5a) {
-				em28xx_isocdbg("Video frame, length=%i!",len);
-
-				if (em28xx_isoc_video(dev,f,&lock_flags,buf[2]))
-				break;
-			} else if (buf[0]==0x33 && buf[1]==0x95 && buf[2]==0x00) {
-				em28xx_isocdbg("VBI HEADER!!!");
-			}
-
-			/* actual copying */
-			if ((*f)->state == F_GRABBING) {
-				em28xx_isoc_video_copy(dev,f,buf, len);
-			}
-		}
-	}
-
-	for (i = 0; i < urb->number_of_packets; i++) {
-		urb->iso_frame_desc[i].status = 0;
-		urb->iso_frame_desc[i].actual_length = 0;
-	}
-
-	urb->status = 0;
-	if ((status = usb_submit_urb(urb, GFP_ATOMIC))) {
-		em28xx_errdev("resubmit of urb failed (error=%i)\n", status);
-		dev->state |= DEV_MISCONFIGURED;
-	}
-	wake_up_interruptible(&dev->wait_frame);
-	return;
-}
-
-/*
- * em28xx_uninit_isoc()
- * deallocates the buffers and urbs allocated during em28xx_init_iosc()
- */
-void em28xx_uninit_isoc(struct em28xx *dev)
-{
-	int i;
-
-	for (i = 0; i < EM28XX_NUM_BUFS; i++) {
-		if (dev->urb[i]) {
-			usb_kill_urb(dev->urb[i]);
-			if (dev->transfer_buffer[i]) {
-				usb_buffer_free(dev->udev,
-						dev->urb[i]->transfer_buffer_length,
-						dev->transfer_buffer[i],
-						dev->urb[i]->transfer_dma);
-			}
-			usb_free_urb(dev->urb[i]);
-		}
-		dev->urb[i] = NULL;
-		dev->transfer_buffer[i] = NULL;
-	}
-	em28xx_capture_start(dev, 0);
-}
-
-/*
- * em28xx_init_isoc()
- * allocates transfer buffers and submits the urbs for isoc transfer
- */
-int em28xx_init_isoc(struct em28xx *dev)
-{
-	/* change interface to 3 which allows the biggest packet sizes */
-	int i, errCode;
-	int sb_size;
-
-	em28xx_set_alternate(dev);
-	sb_size = EM28XX_NUM_PACKETS * dev->max_pkt_size;
-
-	/* reset streaming vars */
-	dev->frame_current = NULL;
-	dev->frame_count = 0;
-
-	/* allocate urbs */
-	for (i = 0; i < EM28XX_NUM_BUFS; i++) {
-		struct urb *urb;
-		int j;
-		/* allocate transfer buffer */
-		urb = usb_alloc_urb(EM28XX_NUM_PACKETS, GFP_KERNEL);
-		if (!urb){
-			em28xx_errdev("cannot alloc urb %i\n", i);
-			em28xx_uninit_isoc(dev);
-			return -ENOMEM;
-		}
-		dev->transfer_buffer[i] = usb_buffer_alloc(dev->udev, sb_size,
-							   GFP_KERNEL,
-							   &urb->transfer_dma);
-		if (!dev->transfer_buffer[i]) {
-			em28xx_errdev
-					("unable to allocate %i bytes for transfer buffer %i\n",
-					 sb_size, i);
-			em28xx_uninit_isoc(dev);
-			usb_free_urb(urb);
-			return -ENOMEM;
-		}
-		memset(dev->transfer_buffer[i], 0, sb_size);
-		urb->dev = dev->udev;
-		urb->context = dev;
-		urb->pipe = usb_rcvisocpipe(dev->udev, 0x82);
-		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
-		urb->interval = 1;
-		urb->transfer_buffer = dev->transfer_buffer[i];
-		urb->complete = em28xx_isocIrq;
-		urb->number_of_packets = EM28XX_NUM_PACKETS;
-		urb->transfer_buffer_length = sb_size;
-		for (j = 0; j < EM28XX_NUM_PACKETS; j++) {
-			urb->iso_frame_desc[j].offset = j * dev->max_pkt_size;
-			urb->iso_frame_desc[j].length = dev->max_pkt_size;
-		}
-		dev->urb[i] = urb;
-	}
-
-	/* submit urbs */
-	em28xx_coredbg("Submitting %d urbs of %d packets (%d each)\n",
-		       EM28XX_NUM_BUFS, EM28XX_NUM_PACKETS, dev->max_pkt_size);
-	for (i = 0; i < EM28XX_NUM_BUFS; i++) {
-		errCode = usb_submit_urb(dev->urb[i], GFP_KERNEL);
-		if (errCode) {
-			em28xx_errdev("submit of urb %i failed (error=%i)\n", i,
-				      errCode);
-			em28xx_uninit_isoc(dev);
-			return errCode;
-		}
-	}
-
-	return 0;
-}
-
 int em28xx_set_alternate(struct em28xx *dev)
 {
 	int errCode, prev_alt = dev->alt;
 	int i;
-	unsigned int min_pkt_size = dev->bytesperline+4;
+	unsigned int min_pkt_size = dev->width * 2 + 4;
 
-	/* When image size is bigger than a ceirtain value,
+	/* When image size is bigger than a certain value,
 	   the frame size should be increased, otherwise, only
 	   green screen will be received.
 	 */
-	if (dev->frame_size > 720*240*2)
+	if (dev->width * 2 * dev->height > 720 * 240 * 2)
 		min_pkt_size *= 2;
 
-	for (i = 0; i < dev->num_alt; i++)
-		if (dev->alt_max_pkt_size[i] >= min_pkt_size)
+	for (i = 0; i < dev->num_alt; i++) {
+		/* stop when the selected alt setting offers enough bandwidth */
+		if (dev->alt_max_pkt_size[i] >= min_pkt_size) {
+			dev->alt = i;
 			break;
-	dev->alt = i;
+		/* otherwise make sure that we end up with the maximum bandwidth
+		   because the min_pkt_size equation might be wrong...
+		*/
+		} else if (dev->alt_max_pkt_size[i] >
+			   dev->alt_max_pkt_size[dev->alt])
+			dev->alt = i;
+	}
 
 	if (dev->alt != prev_alt) {
 		em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n",
@@ -835,10 +490,237 @@
 			       dev->alt, dev->max_pkt_size);
 		errCode = usb_set_interface(dev->udev, 0, dev->alt);
 		if (errCode < 0) {
-			em28xx_errdev ("cannot change alternate number to %d (error=%i)\n",
+			em28xx_errdev("cannot change alternate number to %d (error=%i)\n",
 					dev->alt, errCode);
 			return errCode;
 		}
 	}
 	return 0;
 }
+
+int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio)
+{
+	int rc = 0;
+
+	if (!gpio)
+		return rc;
+
+	dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1);
+	if (dev->mode == EM28XX_ANALOG_MODE)
+		dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1);
+	else
+		dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x37", 1);
+	msleep(6);
+
+	/* Send GPIO reset sequences specified at board entry */
+	while (gpio->sleep >= 0) {
+		if (gpio->reg >= 0) {
+			rc = em28xx_write_reg_bits(dev,
+						   gpio->reg,
+						   gpio->val,
+						   gpio->mask);
+			if (rc < 0)
+				return rc;
+		}
+		if (gpio->sleep > 0)
+			msleep(gpio->sleep);
+
+		gpio++;
+	}
+	return rc;
+}
+
+int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode)
+{
+	if (dev->mode == set_mode)
+		return 0;
+
+	if (set_mode == EM28XX_MODE_UNDEFINED) {
+		dev->mode = set_mode;
+		return 0;
+	}
+
+	dev->mode = set_mode;
+
+	if (dev->mode == EM28XX_DIGITAL_MODE)
+		return em28xx_gpio_set(dev, dev->digital_gpio);
+	else
+		return em28xx_gpio_set(dev, dev->analog_gpio);
+}
+EXPORT_SYMBOL_GPL(em28xx_set_mode);
+
+/* ------------------------------------------------------------------
+	URB control
+   ------------------------------------------------------------------*/
+
+/*
+ * IRQ callback, called by URB callback
+ */
+static void em28xx_irq_callback(struct urb *urb)
+{
+	struct em28xx_dmaqueue  *dma_q = urb->context;
+	struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
+	int rc, i;
+
+	/* Copy data from URB */
+	spin_lock(&dev->slock);
+	rc = dev->isoc_ctl.isoc_copy(dev, urb);
+	spin_unlock(&dev->slock);
+
+	/* Reset urb buffers */
+	for (i = 0; i < urb->number_of_packets; i++) {
+		urb->iso_frame_desc[i].status = 0;
+		urb->iso_frame_desc[i].actual_length = 0;
+	}
+	urb->status = 0;
+
+	urb->status = usb_submit_urb(urb, GFP_ATOMIC);
+	if (urb->status) {
+		em28xx_isocdbg("urb resubmit failed (error=%i)\n",
+			       urb->status);
+	}
+}
+
+/*
+ * Stop and Deallocate URBs
+ */
+void em28xx_uninit_isoc(struct em28xx *dev)
+{
+	struct urb *urb;
+	int i;
+
+	em28xx_isocdbg("em28xx: called em28xx_uninit_isoc\n");
+
+	dev->isoc_ctl.nfields = -1;
+	for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+		urb = dev->isoc_ctl.urb[i];
+		if (urb) {
+			usb_kill_urb(urb);
+			usb_unlink_urb(urb);
+			if (dev->isoc_ctl.transfer_buffer[i]) {
+				usb_buffer_free(dev->udev,
+					urb->transfer_buffer_length,
+					dev->isoc_ctl.transfer_buffer[i],
+					urb->transfer_dma);
+			}
+			usb_free_urb(urb);
+			dev->isoc_ctl.urb[i] = NULL;
+		}
+		dev->isoc_ctl.transfer_buffer[i] = NULL;
+	}
+
+	kfree(dev->isoc_ctl.urb);
+	kfree(dev->isoc_ctl.transfer_buffer);
+
+	dev->isoc_ctl.urb = NULL;
+	dev->isoc_ctl.transfer_buffer = NULL;
+	dev->isoc_ctl.num_bufs = 0;
+
+	em28xx_capture_start(dev, 0);
+}
+EXPORT_SYMBOL_GPL(em28xx_uninit_isoc);
+
+/*
+ * Allocate URBs and start IRQ
+ */
+int em28xx_init_isoc(struct em28xx *dev, int max_packets,
+		     int num_bufs, int max_pkt_size,
+		     int (*isoc_copy) (struct em28xx *dev, struct urb *urb))
+{
+	struct em28xx_dmaqueue *dma_q = &dev->vidq;
+	int i;
+	int sb_size, pipe;
+	struct urb *urb;
+	int j, k;
+	int rc;
+
+	em28xx_isocdbg("em28xx: called em28xx_prepare_isoc\n");
+
+	/* De-allocates all pending stuff */
+	em28xx_uninit_isoc(dev);
+
+	dev->isoc_ctl.isoc_copy = isoc_copy;
+	dev->isoc_ctl.num_bufs = num_bufs;
+
+	dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs,  GFP_KERNEL);
+	if (!dev->isoc_ctl.urb) {
+		em28xx_errdev("cannot alloc memory for usb buffers\n");
+		return -ENOMEM;
+	}
+
+	dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
+					      GFP_KERNEL);
+	if (!dev->isoc_ctl.urb) {
+		em28xx_errdev("cannot allocate memory for usbtransfer\n");
+		kfree(dev->isoc_ctl.urb);
+		return -ENOMEM;
+	}
+
+	dev->isoc_ctl.max_pkt_size = max_pkt_size;
+	dev->isoc_ctl.buf = NULL;
+
+	sb_size = max_packets * dev->isoc_ctl.max_pkt_size;
+
+	/* allocate urbs and transfer buffers */
+	for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+		urb = usb_alloc_urb(max_packets, GFP_KERNEL);
+		if (!urb) {
+			em28xx_err("cannot alloc isoc_ctl.urb %i\n", i);
+			em28xx_uninit_isoc(dev);
+			return -ENOMEM;
+		}
+		dev->isoc_ctl.urb[i] = urb;
+
+		dev->isoc_ctl.transfer_buffer[i] = usb_buffer_alloc(dev->udev,
+			sb_size, GFP_KERNEL, &urb->transfer_dma);
+		if (!dev->isoc_ctl.transfer_buffer[i]) {
+			em28xx_err("unable to allocate %i bytes for transfer"
+					" buffer %i%s\n",
+					sb_size, i,
+					in_interrupt()?" while in int":"");
+			em28xx_uninit_isoc(dev);
+			return -ENOMEM;
+		}
+		memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);
+
+		/* FIXME: this is a hack - should be
+			'desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK'
+			should also be using 'desc.bInterval'
+		 */
+		pipe = usb_rcvisocpipe(dev->udev,
+			dev->mode == EM28XX_ANALOG_MODE ? 0x82 : 0x84);
+
+		usb_fill_int_urb(urb, dev->udev, pipe,
+				 dev->isoc_ctl.transfer_buffer[i], sb_size,
+				 em28xx_irq_callback, dma_q, 1);
+
+		urb->number_of_packets = max_packets;
+		urb->transfer_flags = URB_ISO_ASAP;
+
+		k = 0;
+		for (j = 0; j < max_packets; j++) {
+			urb->iso_frame_desc[j].offset = k;
+			urb->iso_frame_desc[j].length =
+						dev->isoc_ctl.max_pkt_size;
+			k += dev->isoc_ctl.max_pkt_size;
+		}
+	}
+
+	init_waitqueue_head(&dma_q->wq);
+
+	em28xx_capture_start(dev, 1);
+
+	/* submit urbs and enables IRQ */
+	for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+		rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
+		if (rc) {
+			em28xx_err("submit of urb %i failed (error=%i)\n", i,
+				   rc);
+			em28xx_uninit_isoc(dev);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(em28xx_init_isoc);
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c
new file mode 100644
index 0000000..7df81575
--- /dev/null
+++ b/drivers/media/video/em28xx/em28xx-dvb.c
@@ -0,0 +1,474 @@
+/*
+ DVB device driver for em28xx
+
+ (c) 2008 Mauro Carvalho Chehab <mchehab@infradead.org>
+
+ (c) 2008 Devin Heitmueller <devin.heitmueller@gmail.com>
+	- Fixes for the driver to properly work with HVR-950
+
+ (c) 2008 Aidan Thornton <makosoft@googlemail.com>
+
+ Based on cx88-dvb, saa7134-dvb and videobuf-dvb originally written by:
+	(c) 2004, 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
+	(c) 2004 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/usb.h>
+
+#include "em28xx.h"
+#include <media/v4l2-common.h>
+#include <media/videobuf-vmalloc.h>
+
+#include "lgdt330x.h"
+#include "zl10353.h"
+
+MODULE_DESCRIPTION("driver for em28xx based DVB cards");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_LICENSE("GPL");
+
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages [dvb]");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define dprintk(level, fmt, arg...) do {			\
+if (debug >= level) 						\
+	printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg);	\
+} while (0)
+
+#define EM28XX_DVB_NUM_BUFS 5
+#define EM28XX_DVB_MAX_PACKETSIZE 564
+#define EM28XX_DVB_MAX_PACKETS 64
+
+struct em28xx_dvb {
+	struct dvb_frontend        *frontend;
+
+	/* feed count management */
+	struct mutex               lock;
+	int                        nfeeds;
+
+	/* general boilerplate stuff */
+	struct dvb_adapter         adapter;
+	struct dvb_demux           demux;
+	struct dmxdev              dmxdev;
+	struct dmx_frontend        fe_hw;
+	struct dmx_frontend        fe_mem;
+	struct dvb_net             net;
+};
+
+
+static inline void print_err_status(struct em28xx *dev,
+				     int packet, int status)
+{
+	char *errmsg = "Unknown";
+
+	switch (status) {
+	case -ENOENT:
+		errmsg = "unlinked synchronuously";
+		break;
+	case -ECONNRESET:
+		errmsg = "unlinked asynchronuously";
+		break;
+	case -ENOSR:
+		errmsg = "Buffer error (overrun)";
+		break;
+	case -EPIPE:
+		errmsg = "Stalled (device not responding)";
+		break;
+	case -EOVERFLOW:
+		errmsg = "Babble (bad cable?)";
+		break;
+	case -EPROTO:
+		errmsg = "Bit-stuff error (bad cable?)";
+		break;
+	case -EILSEQ:
+		errmsg = "CRC/Timeout (could be anything)";
+		break;
+	case -ETIME:
+		errmsg = "Device does not respond";
+		break;
+	}
+	if (packet < 0) {
+		dprintk(1, "URB status %d [%s].\n", status, errmsg);
+	} else {
+		dprintk(1, "URB packet %d, status %d [%s].\n",
+			packet, status, errmsg);
+	}
+}
+
+static inline int dvb_isoc_copy(struct em28xx *dev, struct urb *urb)
+{
+	int i;
+
+	if (!dev)
+		return 0;
+
+	if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+		return 0;
+
+	if (urb->status < 0) {
+		print_err_status(dev, -1, urb->status);
+		if (urb->status == -ENOENT)
+			return 0;
+	}
+
+	for (i = 0; i < urb->number_of_packets; i++) {
+		int status = urb->iso_frame_desc[i].status;
+
+		if (status < 0) {
+			print_err_status(dev, i, status);
+			if (urb->iso_frame_desc[i].status != -EPROTO)
+				continue;
+		}
+
+		dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer +
+				 urb->iso_frame_desc[i].offset,
+				 urb->iso_frame_desc[i].actual_length);
+	}
+
+	return 0;
+}
+
+static int start_streaming(struct em28xx_dvb *dvb)
+{
+	int rc;
+	struct em28xx *dev = dvb->adapter.priv;
+
+	usb_set_interface(dev->udev, 0, 1);
+	rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
+	if (rc < 0)
+		return rc;
+
+	return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS,
+				EM28XX_DVB_NUM_BUFS, EM28XX_DVB_MAX_PACKETSIZE,
+				dvb_isoc_copy);
+}
+
+static int stop_streaming(struct em28xx_dvb *dvb)
+{
+	struct em28xx *dev = dvb->adapter.priv;
+
+	em28xx_uninit_isoc(dev);
+
+	em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+
+	return 0;
+}
+
+static int start_feed(struct dvb_demux_feed *feed)
+{
+	struct dvb_demux *demux  = feed->demux;
+	struct em28xx_dvb *dvb = demux->priv;
+	int rc, ret;
+
+	if (!demux->dmx.frontend)
+		return -EINVAL;
+
+	mutex_lock(&dvb->lock);
+	dvb->nfeeds++;
+	rc = dvb->nfeeds;
+
+	if (dvb->nfeeds == 1) {
+		ret = start_streaming(dvb);
+		if (ret < 0)
+			rc = ret;
+	}
+
+	mutex_unlock(&dvb->lock);
+	return rc;
+}
+
+static int stop_feed(struct dvb_demux_feed *feed)
+{
+	struct dvb_demux *demux  = feed->demux;
+	struct em28xx_dvb *dvb = demux->priv;
+	int err = 0;
+
+	mutex_lock(&dvb->lock);
+	dvb->nfeeds--;
+
+	if (0 == dvb->nfeeds)
+		err = stop_streaming(dvb);
+
+	mutex_unlock(&dvb->lock);
+	return err;
+}
+
+
+
+/* ------------------------------------------------------------------ */
+static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
+{
+	struct em28xx *dev = fe->dvb->priv;
+
+	if (acquire)
+		return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
+	else
+		return em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+}
+
+/* ------------------------------------------------------------------ */
+
+static struct lgdt330x_config em2880_lgdt3303_dev = {
+	.demod_address = 0x0e,
+	.demod_chip = LGDT3303,
+};
+
+static struct zl10353_config em28xx_zl10353_with_xc3028 = {
+	.demod_address = (0x1e >> 1),
+	.no_tuner = 1,
+	.parallel_ts = 1,
+	.if2 = 45600,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int attach_xc3028(u8 addr, struct em28xx *dev)
+{
+	struct dvb_frontend *fe;
+	struct xc2028_config cfg;
+
+	memset(&cfg, 0, sizeof(cfg));
+	cfg.i2c_adap  = &dev->i2c_adap;
+	cfg.i2c_addr  = addr;
+	cfg.callback  = em28xx_tuner_callback;
+
+	if (!dev->dvb->frontend) {
+		printk(KERN_ERR "%s/2: dvb frontend not attached. "
+				"Can't attach xc3028\n",
+		       dev->name);
+		return -EINVAL;
+	}
+
+	fe = dvb_attach(xc2028_attach, dev->dvb->frontend, &cfg);
+	if (!fe) {
+		printk(KERN_ERR "%s/2: xc3028 attach failed\n",
+		       dev->name);
+		dvb_frontend_detach(dev->dvb->frontend);
+		dvb_unregister_frontend(dev->dvb->frontend);
+		dev->dvb->frontend = NULL;
+		return -EINVAL;
+	}
+
+	printk(KERN_INFO "%s/2: xc3028 attached\n", dev->name);
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+int register_dvb(struct em28xx_dvb *dvb,
+		 struct module *module,
+		 struct em28xx *dev,
+		 struct device *device)
+{
+	int result;
+
+	mutex_init(&dvb->lock);
+
+	/* register adapter */
+	result = dvb_register_adapter(&dvb->adapter, dev->name, module, device,
+				      adapter_nr);
+	if (result < 0) {
+		printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n",
+		       dev->name, result);
+		goto fail_adapter;
+	}
+
+	/* Ensure all frontends negotiate bus access */
+	dvb->frontend->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl;
+
+	dvb->adapter.priv = dev;
+
+	/* register frontend */
+	result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
+	if (result < 0) {
+		printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n",
+		       dev->name, result);
+		goto fail_frontend;
+	}
+
+	/* register demux stuff */
+	dvb->demux.dmx.capabilities =
+		DMX_TS_FILTERING | DMX_SECTION_FILTERING |
+		DMX_MEMORY_BASED_FILTERING;
+	dvb->demux.priv       = dvb;
+	dvb->demux.filternum  = 256;
+	dvb->demux.feednum    = 256;
+	dvb->demux.start_feed = start_feed;
+	dvb->demux.stop_feed  = stop_feed;
+
+	result = dvb_dmx_init(&dvb->demux);
+	if (result < 0) {
+		printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n",
+		       dev->name, result);
+		goto fail_dmx;
+	}
+
+	dvb->dmxdev.filternum    = 256;
+	dvb->dmxdev.demux        = &dvb->demux.dmx;
+	dvb->dmxdev.capabilities = 0;
+	result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
+	if (result < 0) {
+		printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n",
+		       dev->name, result);
+		goto fail_dmxdev;
+	}
+
+	dvb->fe_hw.source = DMX_FRONTEND_0;
+	result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+	if (result < 0) {
+		printk(KERN_WARNING "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n",
+		       dev->name, result);
+		goto fail_fe_hw;
+	}
+
+	dvb->fe_mem.source = DMX_MEMORY_FE;
+	result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+	if (result < 0) {
+		printk(KERN_WARNING "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n",
+		       dev->name, result);
+		goto fail_fe_mem;
+	}
+
+	result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+	if (result < 0) {
+		printk(KERN_WARNING "%s: connect_frontend failed (errno = %d)\n",
+		       dev->name, result);
+		goto fail_fe_conn;
+	}
+
+	/* register network adapter */
+	dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
+	return 0;
+
+fail_fe_conn:
+	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+fail_fe_mem:
+	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+fail_fe_hw:
+	dvb_dmxdev_release(&dvb->dmxdev);
+fail_dmxdev:
+	dvb_dmx_release(&dvb->demux);
+fail_dmx:
+	dvb_unregister_frontend(dvb->frontend);
+fail_frontend:
+	dvb_frontend_detach(dvb->frontend);
+	dvb_unregister_adapter(&dvb->adapter);
+fail_adapter:
+	return result;
+}
+
+static void unregister_dvb(struct em28xx_dvb *dvb)
+{
+	dvb_net_release(&dvb->net);
+	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+	dvb_dmxdev_release(&dvb->dmxdev);
+	dvb_dmx_release(&dvb->demux);
+	dvb_unregister_frontend(dvb->frontend);
+	dvb_frontend_detach(dvb->frontend);
+	dvb_unregister_adapter(&dvb->adapter);
+}
+
+
+static int dvb_init(struct em28xx *dev)
+{
+	int result = 0;
+	struct em28xx_dvb *dvb;
+
+	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
+
+	if (dvb == NULL) {
+		printk(KERN_INFO "em28xx_dvb: memory allocation failed\n");
+		return -ENOMEM;
+	}
+	dev->dvb = dvb;
+
+	em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
+	/* init frontend */
+	switch (dev->model) {
+	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
+		dvb->frontend = dvb_attach(lgdt330x_attach,
+					   &em2880_lgdt3303_dev,
+					   &dev->i2c_adap);
+		if (attach_xc3028(0x61, dev) < 0) {
+			result = -EINVAL;
+			goto out_free;
+		}
+		break;
+	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+		dvb->frontend = dvb_attach(zl10353_attach,
+					   &em28xx_zl10353_with_xc3028,
+					   &dev->i2c_adap);
+		if (attach_xc3028(0x61, dev) < 0) {
+			result = -EINVAL;
+			goto out_free;
+		}
+		break;
+	default:
+		printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card"
+				" isn't supported yet\n",
+		       dev->name);
+		break;
+	}
+	if (NULL == dvb->frontend) {
+		printk(KERN_ERR
+		       "%s/2: frontend initialization failed\n",
+		       dev->name);
+		result = -EINVAL;
+		goto out_free;
+	}
+
+	/* register everything */
+	result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev);
+
+	if (result < 0)
+		goto out_free;
+
+	em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+	printk(KERN_INFO "Successfully loaded em28xx-dvb\n");
+	return 0;
+
+out_free:
+	em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+	kfree(dvb);
+	dev->dvb = NULL;
+	return result;
+}
+
+static int dvb_fini(struct em28xx *dev)
+{
+	if (dev->dvb) {
+		unregister_dvb(dev->dvb);
+		dev->dvb = NULL;
+	}
+
+	return 0;
+}
+
+static struct em28xx_ops dvb_ops = {
+	.id   = EM28XX_DVB,
+	.name = "Em28xx dvb Extension",
+	.init = dvb_init,
+	.fini = dvb_fini,
+};
+
+static int __init em28xx_dvb_register(void)
+{
+	return em28xx_register_extension(&dvb_ops);
+}
+
+static void __exit em28xx_dvb_unregister(void)
+{
+	em28xx_unregister_extension(&dvb_ops);
+}
+
+module_init(em28xx_dvb_register);
+module_exit(em28xx_dvb_unregister);
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
index cacd04d..6a78fd2 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -33,19 +33,29 @@
 
 /* ----------------------------------------------------------- */
 
-static unsigned int i2c_scan = 0;
+static unsigned int i2c_scan;
 module_param(i2c_scan, int, 0444);
 MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
 
-static unsigned int i2c_debug = 0;
+static unsigned int i2c_debug;
 module_param(i2c_debug, int, 0644);
 MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
 
-#define dprintk1(lvl,fmt, args...) if (i2c_debug>=lvl) do {\
-			printk(fmt, ##args); } while (0)
-#define dprintk2(lvl,fmt, args...) if (i2c_debug>=lvl) do{ \
-			printk(KERN_DEBUG "%s at %s: " fmt, \
-			dev->name, __FUNCTION__ , ##args); } while (0)
+
+#define dprintk1(lvl, fmt, args...)			\
+do {							\
+	if (i2c_debug >= lvl) {				\
+	printk(fmt, ##args);				\
+      }							\
+} while (0)
+
+#define dprintk2(lvl, fmt, args...)			\
+do {							\
+	if (i2c_debug >= lvl) {				\
+		printk(KERN_DEBUG "%s at %s: " fmt,	\
+		       dev->name, __func__ , ##args);	\
+      } 						\
+} while (0)
 
 /*
  * em2800_i2c_send_max4()
@@ -235,16 +245,16 @@
 		return 0;
 	for (i = 0; i < num; i++) {
 		addr = msgs[i].addr << 1;
-		dprintk2(2,"%s %s addr=%x len=%d:",
+		dprintk2(2, "%s %s addr=%x len=%d:",
 			 (msgs[i].flags & I2C_M_RD) ? "read" : "write",
 			 i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
-		if (!msgs[i].len) {	/* no len: check only for device presence */
+		if (!msgs[i].len) { /* no len: check only for device presence */
 			if (dev->is_em2800)
 				rc = em2800_i2c_check_for_device(dev, addr);
 			else
 				rc = em28xx_i2c_check_for_device(dev, addr);
 			if (rc < 0) {
-				dprintk2(2," no device\n");
+				dprintk2(2, " no device\n");
 				return rc;
 			}
 
@@ -258,14 +268,13 @@
 				rc = em28xx_i2c_recv_bytes(dev, addr,
 							   msgs[i].buf,
 							   msgs[i].len);
-			if (i2c_debug>=2) {
-				for (byte = 0; byte < msgs[i].len; byte++) {
+			if (i2c_debug >= 2) {
+				for (byte = 0; byte < msgs[i].len; byte++)
 					printk(" %02x", msgs[i].buf[byte]);
-				}
 			}
 		} else {
 			/* write bytes */
-			if (i2c_debug>=2) {
+			if (i2c_debug >= 2) {
 				for (byte = 0; byte < msgs[i].len; byte++)
 					printk(" %02x", msgs[i].buf[byte]);
 			}
@@ -281,13 +290,13 @@
 		}
 		if (rc < 0)
 			goto err;
-		if (i2c_debug>=2)
+		if (i2c_debug >= 2)
 			printk("\n");
 	}
 
 	return num;
-      err:
-	dprintk2(2," ERROR: %i\n", rc);
+err:
+	dprintk2(2, " ERROR: %i\n", rc);
 	return rc;
 }
 
@@ -330,7 +339,9 @@
 		return -1;
 
 	buf = 0;
-	if (1 != (err = i2c_master_send(&dev->i2c_client, &buf, 1))) {
+
+	err = i2c_master_send(&dev->i2c_client, &buf, 1);
+	if (err != 1) {
 		printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
 		       dev->name, err);
 		return -1;
@@ -403,8 +414,10 @@
 		break;
 	}
 	printk(KERN_INFO "Table at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
-				em_eeprom->string_idx_table,em_eeprom->string1,
-				em_eeprom->string2,em_eeprom->string3);
+				em_eeprom->string_idx_table,
+				em_eeprom->string1,
+				em_eeprom->string2,
+				em_eeprom->string3);
 
 	return 0;
 }
@@ -430,58 +443,61 @@
 	struct em28xx *dev = client->adapter->algo_data;
 
 	switch (client->addr << 1) {
-		case 0x86:
-		case 0x84:
-		case 0x96:
-		case 0x94:
-		{
-			struct v4l2_priv_tun_config tda9887_cfg;
+	case 0x86:
+	case 0x84:
+	case 0x96:
+	case 0x94:
+	{
+		struct v4l2_priv_tun_config tda9887_cfg;
 
-			struct tuner_setup tun_setup;
+		struct tuner_setup tun_setup;
 
-			tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
-			tun_setup.type = TUNER_TDA9887;
-			tun_setup.addr = client->addr;
+		tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+		tun_setup.type = TUNER_TDA9887;
+		tun_setup.addr = client->addr;
 
-			em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
+		em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR,
+			&tun_setup);
 
-			tda9887_cfg.tuner = TUNER_TDA9887;
-			tda9887_cfg.priv = &dev->tda9887_conf;
-			em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG,
-						&tda9887_cfg);
-			break;
-		}
-		case 0x42:
-			dprintk1(1,"attach_inform: saa7114 detected.\n");
-			break;
-		case 0x4a:
-			dprintk1(1,"attach_inform: saa7113 detected.\n");
-			break;
-		case 0xa0:
-			dprintk1(1,"attach_inform: eeprom detected.\n");
-			break;
-		case 0x60:
-		case 0x8e:
-		{
-			struct IR_i2c *ir = i2c_get_clientdata(client);
-			dprintk1(1,"attach_inform: IR detected (%s).\n",ir->phys);
-			em28xx_set_ir(dev,ir);
-			break;
-		}
-		case 0x80:
-		case 0x88:
-			dprintk1(1,"attach_inform: msp34xx detected.\n");
-			break;
-		case 0xb8:
-		case 0xba:
-			dprintk1(1,"attach_inform: tvp5150 detected.\n");
-			break;
+		tda9887_cfg.tuner = TUNER_TDA9887;
+		tda9887_cfg.priv = &dev->tda9887_conf;
+		em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG,
+					&tda9887_cfg);
+		break;
+	}
+	case 0x42:
+		dprintk1(1, "attach_inform: saa7114 detected.\n");
+		break;
+	case 0x4a:
+		dprintk1(1, "attach_inform: saa7113 detected.\n");
+		break;
+	case 0xa0:
+		dprintk1(1, "attach_inform: eeprom detected.\n");
+		break;
+	case 0x60:
+	case 0x8e:
+	{
+		struct IR_i2c *ir = i2c_get_clientdata(client);
+		dprintk1(1, "attach_inform: IR detected (%s).\n",
+			ir->phys);
+		em28xx_set_ir(dev, ir);
+		break;
+	}
+	case 0x80:
+	case 0x88:
+		dprintk1(1, "attach_inform: msp34xx detected.\n");
+		break;
+	case 0xb8:
+	case 0xba:
+		dprintk1(1, "attach_inform: tvp5150 detected.\n");
+		break;
 
-		default:
-			if (!dev->tuner_addr)
-				dev->tuner_addr = client->addr;
+	default:
+		if (!dev->tuner_addr)
+			dev->tuner_addr = client->addr;
 
-			dprintk1(1,"attach inform: detected I2C address %x\n", client->addr << 1);
+		dprintk1(1, "attach inform: detected I2C address %x\n",
+				client->addr << 1);
 
 	}
 
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index 10da2fd..bb58071 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -32,10 +32,12 @@
 
 static unsigned int ir_debug;
 module_param(ir_debug, int, 0644);
-MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
+MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
 
-#define dprintk(fmt, arg...)	if (ir_debug) \
-	printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg)
+#define dprintk(fmt, arg...) \
+	if (ir_debug) { \
+		printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg); \
+	}
 
 /* ----------------------------------------------------------------------- */
 
@@ -44,7 +46,7 @@
 	unsigned char b;
 
 	/* poll IR chip */
-	if (1 != i2c_master_recv(&ir->c,&b,1)) {
+	if (1 != i2c_master_recv(&ir->c, &b, 1)) {
 		dprintk("read error\n");
 		return -EIO;
 	}
@@ -74,24 +76,25 @@
 	unsigned char code;
 
 	/* poll IR chip */
-	if (2 != i2c_master_recv(&ir->c,buf,2))
+	if (2 != i2c_master_recv(&ir->c, buf, 2))
 		return -EIO;
 
 	/* Does eliminate repeated parity code */
-	if (buf[1]==0xff)
+	if (buf[1] == 0xff)
 		return 0;
 
-	ir->old=buf[1];
+	ir->old = buf[1];
 
 	/* Rearranges bits to the right order */
-	code=    ((buf[0]&0x01)<<5) | /* 0010 0000 */
+	code =   ((buf[0]&0x01)<<5) | /* 0010 0000 */
 		 ((buf[0]&0x02)<<3) | /* 0001 0000 */
 		 ((buf[0]&0x04)<<1) | /* 0000 1000 */
 		 ((buf[0]&0x08)>>1) | /* 0000 0100 */
 		 ((buf[0]&0x10)>>3) | /* 0000 0010 */
 		 ((buf[0]&0x20)>>5);  /* 0000 0001 */
 
-	dprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x)\n",code,buf[0]);
+	dprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x)\n",
+			code, buf[0]);
 
 	/* return key */
 	*ir_key = code;
@@ -106,15 +109,14 @@
 
 	/* poll IR chip */
 
-	if (3 != i2c_master_recv(&ir->c,buf,3)) {
+	if (3 != i2c_master_recv(&ir->c, buf, 3)) {
 		dprintk("read error\n");
 		return -EIO;
 	}
 
 	dprintk("key %02x\n", buf[2]&0x3f);
-	if (buf[0]!=0x00){
+	if (buf[0] != 0x00)
 		return 0;
-	}
 
 	*ir_key = buf[2]&0x3f;
 	*ir_raw = buf[2]&0x3f;
diff --git a/drivers/media/video/em28xx/em28xx-reg.h b/drivers/media/video/em28xx/em28xx-reg.h
new file mode 100644
index 0000000..9058bed
--- /dev/null
+++ b/drivers/media/video/em28xx/em28xx-reg.h
@@ -0,0 +1,88 @@
+#define EM_GPIO_0  (1 << 0)
+#define EM_GPIO_1  (1 << 1)
+#define EM_GPIO_2  (1 << 2)
+#define EM_GPIO_3  (1 << 3)
+#define EM_GPIO_4  (1 << 4)
+#define EM_GPIO_5  (1 << 5)
+#define EM_GPIO_6  (1 << 6)
+#define EM_GPIO_7  (1 << 7)
+
+#define EM_GPO_0   (1 << 0)
+#define EM_GPO_1   (1 << 1)
+#define EM_GPO_2   (1 << 2)
+#define EM_GPO_3   (1 << 3)
+
+/* em2800 registers */
+#define EM2800_R08_AUDIOSRC 0x08
+
+/* em28xx registers */
+
+	/* GPIO/GPO registers */
+#define EM2880_R04_GPO	0x04    /* em2880-em2883 only */
+#define EM28XX_R08_GPIO	0x08	/* em2820 or upper */
+
+#define EM28XX_R06_I2C_CLK	0x06
+#define EM28XX_R0A_CHIPID	0x0a
+#define EM28XX_R0C_USBSUSP	0x0c	/* */
+
+#define EM28XX_R0E_AUDIOSRC	0x0e
+#define EM28XX_R0F_XCLK	0x0f
+
+#define EM28XX_R10_VINMODE	0x10
+#define EM28XX_R11_VINCTRL	0x11
+#define EM28XX_R12_VINENABLE	0x12	/* */
+
+#define EM28XX_R14_GAMMA	0x14
+#define EM28XX_R15_RGAIN	0x15
+#define EM28XX_R16_GGAIN	0x16
+#define EM28XX_R17_BGAIN	0x17
+#define EM28XX_R18_ROFFSET	0x18
+#define EM28XX_R19_GOFFSET	0x19
+#define EM28XX_R1A_BOFFSET	0x1a
+
+#define EM28XX_R1B_OFLOW	0x1b
+#define EM28XX_R1C_HSTART	0x1c
+#define EM28XX_R1D_VSTART	0x1d
+#define EM28XX_R1E_CWIDTH	0x1e
+#define EM28XX_R1F_CHEIGHT	0x1f
+
+#define EM28XX_R20_YGAIN	0x20
+#define EM28XX_R21_YOFFSET	0x21
+#define EM28XX_R22_UVGAIN	0x22
+#define EM28XX_R23_UOFFSET	0x23
+#define EM28XX_R24_VOFFSET	0x24
+#define EM28XX_R25_SHARPNESS	0x25
+
+#define EM28XX_R26_COMPR	0x26
+#define EM28XX_R27_OUTFMT	0x27
+
+#define EM28XX_R28_XMIN	0x28
+#define EM28XX_R29_XMAX	0x29
+#define EM28XX_R2A_YMIN	0x2a
+#define EM28XX_R2B_YMAX	0x2b
+
+#define EM28XX_R30_HSCALELOW	0x30
+#define EM28XX_R31_HSCALEHIGH	0x31
+#define EM28XX_R32_VSCALELOW	0x32
+#define EM28XX_R33_VSCALEHIGH	0x33
+
+#define EM28XX_R40_AC97LSB	0x40
+#define EM28XX_R41_AC97MSB	0x41
+#define EM28XX_R42_AC97ADDR	0x42
+#define EM28XX_R43_AC97BUSY	0x43
+
+/* em202 registers */
+#define EM28XX_R02_MASTER_AC97	0x02
+#define EM28XX_R10_LINE_IN_AC97    0x10
+#define EM28XX_R14_VIDEO_AC97	0x14
+
+/* register settings */
+#define EM2800_AUDIO_SRC_TUNER  0x0d
+#define EM2800_AUDIO_SRC_LINE   0x0c
+#define EM28XX_AUDIO_SRC_TUNER	0xc0
+#define EM28XX_AUDIO_SRC_LINE	0x80
+
+/* FIXME: Need to be populated with the other chip ID's */
+enum em28xx_chip_id {
+	CHIP_ID_EM2883 = 36,
+};
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 4abe670..8996175 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -1,5 +1,6 @@
 /*
-   em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+   em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB
+		    video capture devices
 
    Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
 		      Markus Rechberger <mrechberger@gmail.com>
@@ -52,7 +53,19 @@
 #define em28xx_videodbg(fmt, arg...) do {\
 	if (video_debug) \
 		printk(KERN_INFO "%s %s :"fmt, \
-			 dev->name, __FUNCTION__ , ##arg); } while (0)
+			 dev->name, __func__ , ##arg); } while (0)
+
+static unsigned int isoc_debug;
+module_param(isoc_debug, int, 0644);
+MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
+
+#define em28xx_isocdbg(fmt, arg...) \
+do {\
+	if (isoc_debug) { \
+		printk(KERN_INFO "%s %s :"fmt, \
+			 dev->name, __func__ , ##arg); \
+	} \
+  } while (0)
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
@@ -74,9 +87,9 @@
 MODULE_PARM_DESC(vbi_nr,   "vbi device numbers");
 MODULE_PARM_DESC(radio_nr, "radio device numbers");
 
-static unsigned int video_debug = 0;
-module_param(video_debug,int,0644);
-MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
+static unsigned int video_debug;
+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;
@@ -93,7 +106,7 @@
 		.step = 0x1,
 		.default_value = 0x1f,
 		.flags = 0,
-	},{
+	}, {
 		.id = V4L2_CID_AUDIO_MUTE,
 		.type = V4L2_CTRL_TYPE_BOOLEAN,
 		.name = "Mute",
@@ -107,8 +120,391 @@
 
 static struct usb_driver em28xx_usb_driver;
 
+/* ------------------------------------------------------------------
+	DMA and thread functions
+   ------------------------------------------------------------------*/
 
-/*********************  v4l2 interface  ******************************************/
+/*
+ * Announces that a buffer were filled and request the next
+ */
+static inline void buffer_filled(struct em28xx *dev,
+				  struct em28xx_dmaqueue *dma_q,
+				  struct em28xx_buffer *buf)
+{
+	/* Advice that buffer was filled */
+	em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
+	buf->vb.state = VIDEOBUF_DONE;
+	buf->vb.field_count++;
+	do_gettimeofday(&buf->vb.ts);
+
+	dev->isoc_ctl.buf = NULL;
+
+	list_del(&buf->vb.queue);
+	wake_up(&buf->vb.done);
+}
+
+/*
+ * Identify the buffer header type and properly handles
+ */
+static void em28xx_copy_video(struct em28xx *dev,
+			      struct em28xx_dmaqueue  *dma_q,
+			      struct em28xx_buffer *buf,
+			      unsigned char *p,
+			      unsigned char *outp, unsigned long len)
+{
+	void *fieldstart, *startwrite, *startread;
+	int  linesdone, currlinedone, offset, lencopy, remain;
+	int bytesperline = dev->width << 1;
+
+	if (dma_q->pos + len > buf->vb.size)
+		len = buf->vb.size - dma_q->pos;
+
+	if (p[0] != 0x88 && p[0] != 0x22) {
+		em28xx_isocdbg("frame is not complete\n");
+		len += 4;
+	} else
+		p += 4;
+
+	startread = p;
+	remain = len;
+
+	/* Interlaces frame */
+	if (buf->top_field)
+		fieldstart = outp;
+	else
+		fieldstart = outp + bytesperline;
+
+	linesdone = dma_q->pos / bytesperline;
+	currlinedone = dma_q->pos % bytesperline;
+	offset = linesdone * bytesperline * 2 + currlinedone;
+	startwrite = fieldstart + offset;
+	lencopy = bytesperline - currlinedone;
+	lencopy = lencopy > remain ? remain : lencopy;
+
+	if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) {
+		em28xx_isocdbg("Overflow of %zi bytes past buffer end (1)\n",
+			       ((char *)startwrite + lencopy) -
+			       ((char *)outp + buf->vb.size));
+		lencopy = remain = (char *)outp + buf->vb.size - (char *)startwrite;
+	}
+	if (lencopy <= 0)
+		return;
+	memcpy(startwrite, startread, lencopy);
+
+	remain -= lencopy;
+
+	while (remain > 0) {
+		startwrite += lencopy + bytesperline;
+		startread += lencopy;
+		if (bytesperline > remain)
+			lencopy = remain;
+		else
+			lencopy = bytesperline;
+
+		if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) {
+			em28xx_isocdbg("Overflow of %zi bytes past buffer end (2)\n",
+				       ((char *)startwrite + lencopy) -
+				       ((char *)outp + buf->vb.size));
+			lencopy = remain = (char *)outp + buf->vb.size -
+					   (char *)startwrite;
+		}
+		if (lencopy <= 0)
+			break;
+
+		memcpy(startwrite, startread, lencopy);
+
+		remain -= lencopy;
+	}
+
+	dma_q->pos += len;
+}
+
+static inline void print_err_status(struct em28xx *dev,
+				     int packet, int status)
+{
+	char *errmsg = "Unknown";
+
+	switch (status) {
+	case -ENOENT:
+		errmsg = "unlinked synchronuously";
+		break;
+	case -ECONNRESET:
+		errmsg = "unlinked asynchronuously";
+		break;
+	case -ENOSR:
+		errmsg = "Buffer error (overrun)";
+		break;
+	case -EPIPE:
+		errmsg = "Stalled (device not responding)";
+		break;
+	case -EOVERFLOW:
+		errmsg = "Babble (bad cable?)";
+		break;
+	case -EPROTO:
+		errmsg = "Bit-stuff error (bad cable?)";
+		break;
+	case -EILSEQ:
+		errmsg = "CRC/Timeout (could be anything)";
+		break;
+	case -ETIME:
+		errmsg = "Device does not respond";
+		break;
+	}
+	if (packet < 0) {
+		em28xx_isocdbg("URB status %d [%s].\n",	status, errmsg);
+	} else {
+		em28xx_isocdbg("URB packet %d, status %d [%s].\n",
+			       packet, status, errmsg);
+	}
+}
+
+/*
+ * video-buf generic routine to get the next available buffer
+ */
+static inline void get_next_buf(struct em28xx_dmaqueue *dma_q,
+					  struct em28xx_buffer **buf)
+{
+	struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
+	char *outp;
+
+	if (list_empty(&dma_q->active)) {
+		em28xx_isocdbg("No active queue to serve\n");
+		dev->isoc_ctl.buf = NULL;
+		*buf = NULL;
+		return;
+	}
+
+	/* Get the next buffer */
+	*buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue);
+
+	/* Cleans up buffer - Usefull for testing for frame/URB loss */
+	outp = videobuf_to_vmalloc(&(*buf)->vb);
+	memset(outp, 0, (*buf)->vb.size);
+
+	dev->isoc_ctl.buf = *buf;
+
+	return;
+}
+
+/*
+ * Controls the isoc copy of each urb packet
+ */
+static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb)
+{
+	struct em28xx_buffer    *buf;
+	struct em28xx_dmaqueue  *dma_q = urb->context;
+	unsigned char *outp = NULL;
+	int i, len = 0, rc = 1;
+	unsigned char *p;
+
+	if (!dev)
+		return 0;
+
+	if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+		return 0;
+
+	if (urb->status < 0) {
+		print_err_status(dev, -1, urb->status);
+		if (urb->status == -ENOENT)
+			return 0;
+	}
+
+	buf = dev->isoc_ctl.buf;
+	if (buf != NULL)
+		outp = videobuf_to_vmalloc(&buf->vb);
+
+	for (i = 0; i < urb->number_of_packets; i++) {
+		int status = urb->iso_frame_desc[i].status;
+
+		if (status < 0) {
+			print_err_status(dev, i, status);
+			if (urb->iso_frame_desc[i].status != -EPROTO)
+				continue;
+		}
+
+		len = urb->iso_frame_desc[i].actual_length - 4;
+
+		if (urb->iso_frame_desc[i].actual_length <= 0) {
+			/* em28xx_isocdbg("packet %d is empty",i); - spammy */
+			continue;
+		}
+		if (urb->iso_frame_desc[i].actual_length >
+						dev->max_pkt_size) {
+			em28xx_isocdbg("packet bigger than packet size");
+			continue;
+		}
+
+		p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+
+		/* FIXME: incomplete buffer checks where removed to make
+		   logic simpler. Impacts of those changes should be evaluated
+		 */
+		if (p[0] == 0x33 && p[1] == 0x95 && p[2] == 0x00) {
+			em28xx_isocdbg("VBI HEADER!!!\n");
+			/* FIXME: Should add vbi copy */
+			continue;
+		}
+		if (p[0] == 0x22 && p[1] == 0x5a) {
+			em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2],
+				       len, (p[2] & 1)? "odd" : "even");
+
+			if (!(p[2] & 1)) {
+				if (buf != NULL)
+					buffer_filled(dev, dma_q, buf);
+				get_next_buf(dma_q, &buf);
+				if (buf == NULL)
+					outp = NULL;
+				else
+					outp = videobuf_to_vmalloc(&buf->vb);
+			}
+
+			if (buf != NULL) {
+				if (p[2] & 1)
+					buf->top_field = 0;
+				else
+					buf->top_field = 1;
+			}
+
+			dma_q->pos = 0;
+		}
+		if (buf != NULL)
+			em28xx_copy_video(dev, dma_q, buf, p, outp, len);
+	}
+	return rc;
+}
+
+/* ------------------------------------------------------------------
+	Videobuf operations
+   ------------------------------------------------------------------*/
+
+static int
+buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
+{
+	struct em28xx_fh *fh = vq->priv_data;
+	struct em28xx        *dev = fh->dev;
+	struct v4l2_frequency f;
+
+	*size = 16 * fh->dev->width * fh->dev->height >> 3;
+	if (0 == *count)
+		*count = EM28XX_DEF_BUF;
+
+	if (*count < EM28XX_MIN_BUF)
+		*count = EM28XX_MIN_BUF;
+
+	/* Ask tuner to go to analog mode */
+	memset(&f, 0, sizeof(f));
+	f.frequency = dev->ctl_freq;
+
+	em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f);
+
+	return 0;
+}
+
+/* This is called *without* dev->slock held; please keep it that way */
+static void free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf)
+{
+	struct em28xx_fh     *fh  = vq->priv_data;
+	struct em28xx        *dev = fh->dev;
+	unsigned long flags = 0;
+	if (in_interrupt())
+		BUG();
+
+	/* We used to wait for the buffer to finish here, but this didn't work
+	   because, as we were keeping the state as VIDEOBUF_QUEUED,
+	   videobuf_queue_cancel marked it as finished for us.
+	   (Also, it could wedge forever if the hardware was misconfigured.)
+
+	   This should be safe; by the time we get here, the buffer isn't
+	   queued anymore. If we ever start marking the buffers as
+	   VIDEOBUF_ACTIVE, it won't be, though.
+	*/
+	spin_lock_irqsave(&dev->slock, flags);
+	if (dev->isoc_ctl.buf == buf)
+		dev->isoc_ctl.buf = NULL;
+	spin_unlock_irqrestore(&dev->slock, flags);
+
+	videobuf_vmalloc_free(&buf->vb);
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int
+buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+						enum v4l2_field field)
+{
+	struct em28xx_fh     *fh  = vq->priv_data;
+	struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
+	struct em28xx        *dev = fh->dev;
+	int                  rc = 0, urb_init = 0;
+
+	/* FIXME: It assumes depth = 16 */
+	/* The only currently supported format is 16 bits/pixel */
+	buf->vb.size = 16 * dev->width * dev->height >> 3;
+
+	if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
+		return -EINVAL;
+
+	buf->vb.width  = dev->width;
+	buf->vb.height = dev->height;
+	buf->vb.field  = field;
+
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+		rc = videobuf_iolock(vq, &buf->vb, NULL);
+		if (rc < 0)
+			goto fail;
+	}
+
+	if (!dev->isoc_ctl.num_bufs)
+		urb_init = 1;
+
+	if (urb_init) {
+		rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS,
+				      EM28XX_NUM_BUFS, dev->max_pkt_size,
+				      em28xx_isoc_copy);
+		if (rc < 0)
+			goto fail;
+	}
+
+	buf->vb.state = VIDEOBUF_PREPARED;
+	return 0;
+
+fail:
+	free_buffer(vq, buf);
+	return rc;
+}
+
+static void
+buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+	struct em28xx_buffer    *buf     = container_of(vb, struct em28xx_buffer, vb);
+	struct em28xx_fh        *fh      = vq->priv_data;
+	struct em28xx           *dev     = fh->dev;
+	struct em28xx_dmaqueue  *vidq    = &dev->vidq;
+
+	buf->vb.state = VIDEOBUF_QUEUED;
+	list_add_tail(&buf->vb.queue, &vidq->active);
+
+}
+
+static void buffer_release(struct videobuf_queue *vq,
+				struct videobuf_buffer *vb)
+{
+	struct em28xx_buffer   *buf  = container_of(vb, struct em28xx_buffer, vb);
+	struct em28xx_fh       *fh   = vq->priv_data;
+	struct em28xx          *dev  = (struct em28xx *)fh->dev;
+
+	em28xx_isocdbg("em28xx: called buffer_release\n");
+
+	free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops em28xx_video_qops = {
+	.buf_setup      = buffer_setup,
+	.buf_prepare    = buffer_prepare,
+	.buf_queue      = buffer_queue,
+	.buf_release    = buffer_release,
+};
+
+/*********************  v4l2 interface  **************************************/
 
 /*
  * em28xx_config()
@@ -123,9 +519,9 @@
 
 	/* 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_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);
 
 	dev->mute = 1;		/* maybe not the right place... */
 	dev->volume = 0x1f;
@@ -152,23 +548,6 @@
 	em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL);
 }
 
-/*
- * em28xx_empty_framequeues()
- * prepare queues for incoming and outgoing frames
- */
-static void em28xx_empty_framequeues(struct em28xx *dev)
-{
-	u32 i;
-
-	INIT_LIST_HEAD(&dev->inqueue);
-	INIT_LIST_HEAD(&dev->outqueue);
-
-	for (i = 0; i < EM28XX_NUM_FRAMES; i++) {
-		dev->frame[i].state = F_UNUSED;
-		dev->frame[i].buf.bytesused = 0;
-	}
-}
-
 static void video_mux(struct em28xx *dev, int index)
 {
 	struct v4l2_routing route;
@@ -181,12 +560,15 @@
 	em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
 
 	if (dev->has_msp34xx) {
-		if (dev->i2s_speed)
-			em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ, &dev->i2s_speed);
+		if (dev->i2s_speed) {
+			em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ,
+				&dev->i2s_speed);
+		}
 		route.input = dev->ctl_ainput;
 		route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
 		/* Note: this is msp3400 specific */
-		em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+		em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING,
+			&route);
 	}
 
 	em28xx_audio_analog_set(dev);
@@ -202,15 +584,12 @@
 	if (fh->stream_on)
 		return rc;
 
-	mutex_lock(&dev->lock);
-
 	if (dev->stream_on)
-		rc = -EINVAL;
-	else {
-		dev->stream_on = 1;
-		fh->stream_on  = 1;
-	}
+		return -EINVAL;
 
+	mutex_lock(&dev->lock);
+	dev->stream_on = 1;
+	fh->stream_on  = 1;
 	mutex_unlock(&dev->lock);
 	return rc;
 }
@@ -231,33 +610,6 @@
 }
 
 /*
- * em28xx_vm_open()
- */
-static void em28xx_vm_open(struct vm_area_struct *vma)
-{
-	struct em28xx_frame_t *f = vma->vm_private_data;
-	f->vma_use_count++;
-}
-
-/*
- * em28xx_vm_close()
- */
-static void em28xx_vm_close(struct vm_area_struct *vma)
-{
-	/* NOTE: buffers are not freed here */
-	struct em28xx_frame_t *f = vma->vm_private_data;
-
-	if (f->vma_use_count)
-		f->vma_use_count--;
-}
-
-static struct vm_operations_struct em28xx_vm_ops = {
-	.open = em28xx_vm_open,
-	.close = em28xx_vm_close,
-};
-
-
-/*
  * em28xx_get_ctrl()
  * return the current saturation, brightness or contrast, mute state
  */
@@ -296,34 +648,6 @@
 	}
 }
 
-/*
- * em28xx_stream_interrupt()
- * stops streaming
- */
-static int em28xx_stream_interrupt(struct em28xx *dev)
-{
-	int rc = 0;
-
-	/* stop reading from the device */
-
-	dev->stream = STREAM_INTERRUPT;
-	rc = wait_event_timeout(dev->wait_stream,
-				(dev->stream == STREAM_OFF) ||
-				(dev->state & DEV_DISCONNECTED),
-				EM28XX_URB_TIMEOUT);
-
-	if (rc) {
-		dev->state |= DEV_MISCONFIGURED;
-		em28xx_videodbg("device is misconfigured; close and "
-			"open /dev/video%d again\n",
-				dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN);
-		return rc;
-	}
-
-	return 0;
-}
-
-
 static int check_dev(struct em28xx *dev)
 {
 	if (dev->state & DEV_DISCONNECTED) {
@@ -370,8 +694,8 @@
 	f->fmt.pix.width = dev->width;
 	f->fmt.pix.height = dev->height;
 	f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
-	f->fmt.pix.bytesperline = dev->bytesperline;
-	f->fmt.pix.sizeimage = dev->frame_size;
+	f->fmt.pix.bytesperline = dev->width * 2;
+	f->fmt.pix.sizeimage = f->fmt.pix.bytesperline  * dev->height;
 	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
 
 	/* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
@@ -447,7 +771,7 @@
 {
 	struct em28xx_fh      *fh  = priv;
 	struct em28xx         *dev = fh->dev;
-	int                   rc, i;
+	int                   rc;
 
 	rc = check_dev(dev);
 	if (rc < 0)
@@ -457,49 +781,34 @@
 
 	mutex_lock(&dev->lock);
 
-	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");
-			rc = -EINVAL;
-			goto err;
-		}
-
-	/* stop io in case it is already in progress */
-	if (dev->stream == STREAM_ON) {
-		em28xx_videodbg("VIDIOC_SET_FMT: interrupting stream\n");
-		rc = em28xx_stream_interrupt(dev);
-		if (rc < 0)
-			goto err;
+	if (videobuf_queue_is_busy(&fh->vb_vidq)) {
+		em28xx_errdev("%s queue busy\n", __func__);
+		rc = -EBUSY;
+		goto out;
 	}
 
-	em28xx_release_buffers(dev);
-	dev->io = IO_NONE;
+	if (dev->stream_on && !fh->stream_on) {
+		em28xx_errdev("%s device in use by another fh\n", __func__);
+		rc = -EBUSY;
+		goto out;
+	}
 
 	/* set new image size */
 	dev->width = f->fmt.pix.width;
 	dev->height = f->fmt.pix.height;
-	dev->frame_size = dev->width * dev->height * 2;
-	dev->field_size = dev->frame_size >> 1;
-	dev->bytesperline = dev->width * 2;
 	get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
 
-	/* FIXME: This is really weird! Why capture is starting with
-	   this ioctl ???
-	 */
-	em28xx_uninit_isoc(dev);
 	em28xx_set_alternate(dev);
-	em28xx_capture_start(dev, 1);
 	em28xx_resolution_set(dev);
-	em28xx_init_isoc(dev);
+
 	rc = 0;
 
-err:
+out:
 	mutex_unlock(&dev->lock);
 	return rc;
 }
 
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm)
 {
 	struct em28xx_fh   *fh  = priv;
 	struct em28xx      *dev = fh->dev;
@@ -524,9 +833,6 @@
 	/* set new image size */
 	dev->width = f.fmt.pix.width;
 	dev->height = f.fmt.pix.height;
-	dev->frame_size = dev->width * dev->height * 2;
-	dev->field_size = dev->frame_size >> 1;
-	dev->bytesperline = dev->width * 2;
 	get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
 
 	em28xx_resolution_set(dev);
@@ -619,11 +925,11 @@
 
 	index = dev->ctl_ainput;
 
-	if (index == 0) {
+	if (index == 0)
 		strcpy(a->name, "Television");
-	} else {
+	else
 		strcpy(a->name, "Line In");
-	}
+
 	a->capability = V4L2_AUDCAP_STEREO;
 	a->index = index;
 
@@ -834,9 +1140,9 @@
 static int em28xx_reg_len(int reg)
 {
 	switch (reg) {
-	case AC97LSB_REG:
-	case HSCALELOW_REG:
-	case VSCALELOW_REG:
+	case EM28XX_R40_AC97LSB:
+	case EM28XX_R30_HSCALELOW:
+	case EM28XX_R32_VSCALELOW:
 		return 2;
 	default:
 		return 1;
@@ -918,23 +1224,11 @@
 	if (rc < 0)
 		return rc;
 
-	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP)
-		return -EINVAL;
 
-	if (list_empty(&dev->inqueue))
-		return -EINVAL;
-
-	mutex_lock(&dev->lock);
-
-	if (unlikely(res_get(fh) < 0)) {
-		mutex_unlock(&dev->lock);
+	if (unlikely(res_get(fh) < 0))
 		return -EBUSY;
-	}
 
-	dev->stream = STREAM_ON;	/* FIXME: Start video capture here? */
-
-	mutex_unlock(&dev->lock);
-	return 0;
+	return (videobuf_streamon(&fh->vb_vidq));
 }
 
 static int vidioc_streamoff(struct file *file, void *priv,
@@ -948,23 +1242,14 @@
 	if (rc < 0)
 		return rc;
 
-	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP)
+	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	if (type != fh->type)
 		return -EINVAL;
 
-	mutex_lock(&dev->lock);
+	videobuf_streamoff(&fh->vb_vidq);
+	res_free(fh);
 
-	if (dev->stream == STREAM_ON) {
-		em28xx_videodbg("VIDIOC_STREAMOFF: interrupting stream\n");
-		rc = em28xx_stream_interrupt(dev);
-		if (rc < 0) {
-			mutex_unlock(&dev->lock);
-			return rc;
-		}
-	}
-
-	em28xx_empty_framequeues(dev);
-
-	mutex_unlock(&dev->lock);
 	return 0;
 }
 
@@ -1058,53 +1343,13 @@
 {
 	struct em28xx_fh      *fh  = priv;
 	struct em28xx         *dev = fh->dev;
-	u32                   i;
 	int                   rc;
 
 	rc = check_dev(dev);
 	if (rc < 0)
 		return rc;
 
-	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;
-		}
-
-	mutex_lock(&dev->lock);
-
-	if (dev->stream == STREAM_ON) {
-		em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n");
-		rc = em28xx_stream_interrupt(dev);
-		if (rc < 0) {
-			mutex_unlock(&dev->lock);
-			return rc;
-		}
-	}
-
-	em28xx_empty_framequeues(dev);
-
-	em28xx_release_buffers(dev);
-	if (rb->count)
-		rb->count = em28xx_request_buffers(dev, rb->count);
-
-	dev->frame_current = NULL;
-	dev->io = rb->count ? IO_MMAP : IO_NONE;
-
-	mutex_unlock(&dev->lock);
-	return 0;
+	return (videobuf_reqbufs(&fh->vb_vidq, rb));
 }
 
 static int vidioc_querybuf(struct file *file, void *priv,
@@ -1118,52 +1363,20 @@
 	if (rc < 0)
 		return rc;
 
-	if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-		b->index >= dev->num_frames || dev->io != IO_MMAP)
-		return -EINVAL;
-
-	mutex_lock(&dev->lock);
-
-	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;
-
-	mutex_unlock(&dev->lock);
-	return 0;
+	return (videobuf_querybuf(&fh->vb_vidq, b));
 }
 
 static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
 {
 	struct em28xx_fh      *fh  = priv;
 	struct em28xx         *dev = fh->dev;
-	unsigned long         lock_flags;
 	int                   rc;
 
 	rc = check_dev(dev);
 	if (rc < 0)
 		return rc;
 
-	if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE  || dev->io != IO_MMAP ||
-						b->index >= dev->num_frames)
-		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;
+	return (videobuf_qbuf(&fh->vb_vidq, b));
 }
 
 static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
@@ -1171,47 +1384,25 @@
 	struct em28xx_fh      *fh  = priv;
 	struct em28xx         *dev = fh->dev;
 	int                   rc;
-	struct em28xx_frame_t *f;
-	unsigned long         lock_flags;
 
 	rc = check_dev(dev);
 	if (rc < 0)
 		return rc;
 
-	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 (file->f_flags & O_NONBLOCK)
-			return -EAGAIN;
-
-		rc = wait_event_interruptible(dev->wait_frame,
-					(!list_empty(&dev->outqueue)) ||
-					(dev->state & DEV_DISCONNECTED));
-		if (rc)
-			return rc;
-
-		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;
+	return (videobuf_dqbuf(&fh->vb_vidq, b,
+				file->f_flags & O_NONBLOCK));
 }
 
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
+{
+	struct em28xx_fh  *fh = priv;
+
+	return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
+}
+#endif
+
+
 /* ----------------------------------------------------------- */
 /* RADIO ESPECIFIC IOCTLS                                      */
 /* ----------------------------------------------------------- */
@@ -1316,17 +1507,18 @@
 {
 	int minor = iminor(inode);
 	int errCode = 0, radio = 0;
-	struct em28xx *h,*dev = NULL;
+	struct em28xx *h, *dev = NULL;
 	struct em28xx_fh *fh;
+	enum v4l2_buf_type fh_type = 0;
 
 	list_for_each_entry(h, &em28xx_devlist, devlist) {
 		if (h->vdev->minor == minor) {
 			dev  = h;
-			dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+			fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 		}
 		if (h->vbi_dev->minor == minor) {
 			dev  = h;
-			dev->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+			fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
 		}
 		if (h->radio_dev &&
 		    h->radio_dev->minor == minor) {
@@ -1338,10 +1530,10 @@
 		return -ENODEV;
 
 	em28xx_videodbg("open minor=%d type=%s users=%d\n",
-				minor,v4l2_type_names[dev->type],dev->users);
+				minor, v4l2_type_names[fh_type], dev->users);
+
 
 	fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
-
 	if (!fh) {
 		em28xx_errdev("em28xx-video.c: Out of memory?!\n");
 		return -ENOMEM;
@@ -1349,28 +1541,24 @@
 	mutex_lock(&dev->lock);
 	fh->dev = dev;
 	fh->radio = radio;
+	fh->type = fh_type;
 	filp->private_data = fh;
 
-	if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 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_set_mode(dev, EM28XX_ANALOG_MODE);
 		em28xx_set_alternate(dev);
-		em28xx_capture_start(dev, 1);
 		em28xx_resolution_set(dev);
 
+		/* Needed, since GPIO might have disabled power of
+		   some i2c device
+		 */
+		em28xx_config_i2c(dev);
 
-		/* start the transfer */
-		errCode = em28xx_init_isoc(dev);
-		if (errCode)
-			goto err;
-
-		em28xx_empty_framequeues(dev);
 	}
 	if (fh->radio) {
 		em28xx_videodbg("video_open: setting radio device\n");
@@ -1379,8 +1567,12 @@
 
 	dev->users++;
 
-err:
+	videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops,
+			NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED,
+			sizeof(struct em28xx_buffer), fh);
+
 	mutex_unlock(&dev->lock);
+
 	return errCode;
 }
 
@@ -1423,12 +1615,13 @@
 	usb_put_dev(dev->udev);
 
 	/* Mark device as unused */
-	em28xx_devused&=~(1<<dev->devno);
+	em28xx_devused &= ~(1<<dev->devno);
 }
 
 /*
  * em28xx_v4l2_close()
- * stops streaming and deallocates all resources allocated by the v4l2 calls and ioctls
+ * stops streaming and deallocates all resources allocated by the v4l2
+ * calls and ioctls
  */
 static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
 {
@@ -1445,9 +1638,8 @@
 	mutex_lock(&dev->lock);
 
 	if (dev->users == 1) {
-		em28xx_uninit_isoc(dev);
-		em28xx_release_buffers(dev);
-		dev->io = IO_NONE;
+		videobuf_stop(&fh->vb_vidq);
+		videobuf_mmap_free(&fh->vb_vidq);
 
 		/* the device is already disconnect,
 		   free the remaining resources */
@@ -1458,6 +1650,10 @@
 			return 0;
 		}
 
+		/* do this before setting alternate! */
+		em28xx_uninit_isoc(dev);
+		em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+
 		/* set alternate 0 */
 		dev->alt = 0;
 		em28xx_videodbg("setting alternate 0\n");
@@ -1479,135 +1675,29 @@
  * will allocate buffers when called for the first time
  */
 static ssize_t
-em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
-		 loff_t * f_pos)
+em28xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
+		 loff_t *pos)
 {
-	struct em28xx_frame_t *f, *i;
-	unsigned long lock_flags;
-	int ret = 0;
 	struct em28xx_fh *fh = filp->private_data;
 	struct em28xx *dev = fh->dev;
+	int rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
 
 	/* FIXME: read() is not prepared to allow changing the video
 	   resolution while streaming. Seems a bug at em28xx_set_fmt
 	 */
 
-	if (unlikely(res_get(fh) < 0))
-		return -EBUSY;
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		if (unlikely(res_get(fh)))
+			return -EBUSY;
 
-	mutex_lock(&dev->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->lock);
-			return -EFAULT;
-		}
-		mutex_unlock(&dev->lock);
-		return (1);
+		return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
+					filp->f_flags & O_NONBLOCK);
 	}
-	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->lock);
-			return -EFAULT;
-		}
-		mutex_unlock(&dev->lock);
-		return (1);
-	}
-
-	if (dev->state & DEV_DISCONNECTED) {
-		em28xx_videodbg("device not present\n");
-		mutex_unlock(&dev->lock);
-		return -ENODEV;
-	}
-
-	if (dev->state & DEV_MISCONFIGURED) {
-		em28xx_videodbg("device misconfigured; close and open it again\n");
-		mutex_unlock(&dev->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");
-		mutex_unlock(&dev->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");
-			mutex_unlock(&dev->lock);
-			return -ENOMEM;
-		}
-		dev->io = IO_READ;
-		dev->stream = STREAM_ON;
-		em28xx_queue_unusedframes(dev);
-	}
-
-	if (!count) {
-		mutex_unlock(&dev->lock);
-		return 0;
-	}
-
-	if (list_empty(&dev->outqueue)) {
-		if (filp->f_flags & O_NONBLOCK) {
-			mutex_unlock(&dev->lock);
-			return -EAGAIN;
-		}
-		ret = wait_event_interruptible
-		    (dev->wait_frame,
-		     (!list_empty(&dev->outqueue)) ||
-		     (dev->state & DEV_DISCONNECTED));
-		if (ret) {
-			mutex_unlock(&dev->lock);
-			return ret;
-		}
-		if (dev->state & DEV_DISCONNECTED) {
-			mutex_unlock(&dev->lock);
-			return -ENODEV;
-		}
-		dev->video_bytesread = 0;
-	}
-
-	f = list_entry(dev->outqueue.prev, struct em28xx_frame_t, frame);
-
-	em28xx_queue_unusedframes(dev);
-
-	if (count > f->buf.length)
-		count = f->buf.length;
-
-	if ((dev->video_bytesread + count) > dev->frame_size)
-		count = dev->frame_size - dev->video_bytesread;
-
-	if (copy_to_user(buf, f->bufmem+dev->video_bytesread, count)) {
-		em28xx_err("Error while copying to user\n");
-		return -EFAULT;
-	}
-	dev->video_bytesread += count;
-
-	if (dev->video_bytesread == dev->frame_size) {
-		spin_lock_irqsave(&dev->queue_lock, lock_flags);
-		list_for_each_entry(i, &dev->outqueue, frame)
-				    i->state = F_UNUSED;
-		INIT_LIST_HEAD(&dev->outqueue);
-		spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
-
-		em28xx_queue_unusedframes(dev);
-		dev->video_bytesread = 0;
-	}
-
-	*f_pos += count;
-
-	mutex_unlock(&dev->lock);
-
-	return count;
+	return 0;
 }
 
 /*
@@ -1616,46 +1706,21 @@
  */
 static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
 {
-	unsigned int mask = 0;
 	struct em28xx_fh *fh = filp->private_data;
 	struct em28xx *dev = fh->dev;
+	int rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
 
 	if (unlikely(res_get(fh) < 0))
 		return POLLERR;
 
-	mutex_lock(&dev->lock);
+	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
+		return POLLERR;
 
-	if (dev->state & DEV_DISCONNECTED) {
-		em28xx_videodbg("device not present\n");
-	} else if (dev->state & DEV_MISCONFIGURED) {
-		em28xx_videodbg("device is misconfigured; close and open it again\n");
-	} else {
-		if (dev->io == IO_NONE) {
-			if (!em28xx_request_buffers
-			    (dev, EM28XX_NUM_READ_FRAMES)) {
-				em28xx_warn
-				    ("poll() failed, not enough memory\n");
-			} else {
-				dev->io = IO_READ;
-				dev->stream = STREAM_ON;
-			}
-		}
-
-		if (dev->io == IO_READ) {
-			em28xx_queue_unusedframes(dev);
-			poll_wait(filp, &dev->wait_frame, wait);
-
-			if (!list_empty(&dev->outqueue))
-				mask |= POLLIN | POLLRDNORM;
-
-			mutex_unlock(&dev->lock);
-
-			return mask;
-		}
-	}
-
-	mutex_unlock(&dev->lock);
-	return POLLERR;
+	return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
 }
 
 /*
@@ -1665,69 +1730,23 @@
 {
 	struct em28xx_fh *fh    = filp->private_data;
 	struct em28xx	 *dev   = fh->dev;
-	unsigned long	 size   = vma->vm_end - vma->vm_start;
-	unsigned long	 start  = vma->vm_start;
-	void 		 *pos;
-	u32		 i;
+	int		 rc;
 
 	if (unlikely(res_get(fh) < 0))
 		return -EBUSY;
 
-	mutex_lock(&dev->lock);
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
 
-	if (dev->state & DEV_DISCONNECTED) {
-		em28xx_videodbg("mmap: device not present\n");
-		mutex_unlock(&dev->lock);
-		return -ENODEV;
-	}
+	rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
 
-	if (dev->state & DEV_MISCONFIGURED) {
-		em28xx_videodbg ("mmap: Device is misconfigured; close and "
-						"open it again\n");
-		mutex_unlock(&dev->lock);
-		return -EIO;
-	}
+	em28xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n",
+		(unsigned long)vma->vm_start,
+		(unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
+		rc);
 
-	if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE)) {
-		mutex_unlock(&dev->lock);
-		return -EINVAL;
-	}
-
-	if (size > PAGE_ALIGN(dev->frame[0].buf.length))
-		size = PAGE_ALIGN(dev->frame[0].buf.length);
-
-	for (i = 0; i < dev->num_frames; i++) {
-		if ((dev->frame[i].buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
-			break;
-	}
-	if (i == dev->num_frames) {
-		em28xx_videodbg("mmap: user supplied mapping address is out of range\n");
-		mutex_unlock(&dev->lock);
-		return -EINVAL;
-	}
-
-	/* VM_IO is eventually going to replace PageReserved altogether */
-	vma->vm_flags |= VM_IO;
-	vma->vm_flags |= VM_RESERVED;	/* avoid to swap out this VMA */
-
-	pos = dev->frame[i].bufmem;
-	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");
-			mutex_unlock(&dev->lock);
-			return -EAGAIN;
-		}
-		start += PAGE_SIZE;
-		pos += PAGE_SIZE;
-		size -= PAGE_SIZE;
-	}
-
-	vma->vm_ops = &em28xx_vm_ops;
-	vma->vm_private_data = &dev->frame[i];
-
-	em28xx_vm_open(vma);
-	mutex_unlock(&dev->lock);
-	return 0;
+	return rc;
 }
 
 static const struct file_operations em28xx_v4l_fops = {
@@ -1790,6 +1809,9 @@
 	.vidioc_g_register          = vidioc_g_register,
 	.vidioc_s_register          = vidioc_s_register,
 #endif
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+	.vidiocgmbuf                = vidiocgmbuf,
+#endif
 
 	.tvnorms                    = V4L2_STD_ALL,
 	.current_norm               = V4L2_STD_PAL,
@@ -1818,7 +1840,7 @@
 #endif
 };
 
-/******************************** usb interface *****************************************/
+/******************************** usb interface ******************************/
 
 
 static LIST_HEAD(em28xx_extension_devlist);
@@ -1875,6 +1897,7 @@
 	vfd->dev = &dev->udev->dev;
 	vfd->release = video_device_release;
 	vfd->type = type;
+	vfd->debug = video_debug;
 
 	snprintf(vfd->name, sizeof(vfd->name), "%s %s",
 		 dev->name, type_name);
@@ -1898,7 +1921,7 @@
 
 	dev->udev = udev;
 	mutex_init(&dev->lock);
-	spin_lock_init(&dev->queue_lock);
+	spin_lock_init(&dev->slock);
 	init_waitqueue_head(&dev->open);
 	init_waitqueue_head(&dev->wait_frame);
 	init_waitqueue_head(&dev->wait_stream);
@@ -1910,10 +1933,6 @@
 	dev->em28xx_read_reg_req = em28xx_read_reg_req;
 	dev->is_em2800 = em28xx_boards[dev->model].is_em2800;
 
-	errCode = em28xx_read_reg(dev, CHIPID_REG);
-	if (errCode >= 0)
-		em28xx_info("em28xx chip ID = %d\n", errCode);
-
 	em28xx_pre_card_setup(dev);
 
 	errCode = em28xx_config(dev);
@@ -1946,10 +1965,6 @@
 	dev->width = maxw;
 	dev->height = maxh;
 	dev->interlaced = EM28XX_INTERLACED_DEFAULT;
-	dev->field_size = dev->width * dev->height;
-	dev->frame_size =
-	    dev->interlaced ? dev->field_size << 1 : dev->field_size;
-	dev->bytesperline = dev->width * 2;
 	dev->hscale = 0;
 	dev->vscale = 0;
 	dev->ctl_input = 2;
@@ -2005,6 +2020,10 @@
 			    dev->radio_dev->minor & 0x1f);
 	}
 
+	/* init video dma queues */
+	INIT_LIST_HEAD(&dev->vidq.active);
+	INIT_LIST_HEAD(&dev->vidq.queued);
+
 
 	if (dev->has_msp34xx) {
 		/* Send a reset to other chips via gpio */
@@ -2048,6 +2067,9 @@
 		request_module("snd-usb-audio");
 	else
 		request_module("em28xx-alsa");
+
+	if (dev->has_dvb)
+		request_module("em28xx-dvb");
 }
 
 static void request_modules(struct em28xx *dev)
@@ -2077,22 +2099,24 @@
 	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;
+	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) {
 		em28xx_err(DRIVER_NAME " audio device (%04x:%04x): interface %i, class %i\n",
-				udev->descriptor.idVendor,udev->descriptor.idProduct,
+				udev->descriptor.idVendor,
+				udev->descriptor.idProduct,
 				ifnum,
 				interface->altsetting[0].desc.bInterfaceClass);
 
-		em28xx_devused&=~(1<<nr);
+		em28xx_devused &= ~(1<<nr);
 		return -ENODEV;
 	}
 
 	em28xx_err(DRIVER_NAME " new video device (%04x:%04x): interface %i, class %i\n",
-			udev->descriptor.idVendor,udev->descriptor.idProduct,
+			udev->descriptor.idVendor,
+			udev->descriptor.idProduct,
 			ifnum,
 			interface->altsetting[0].desc.bInterfaceClass);
 
@@ -2102,18 +2126,19 @@
 	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);
+		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);
+		em28xx_devused &= ~(1<<nr);
 		return -ENODEV;
 	}
 
 	if (nr >= EM28XX_MAXBOARDS) {
-		printk (DRIVER_NAME ": Supports only %i em28xx boards.\n",EM28XX_MAXBOARDS);
-		em28xx_devused&=~(1<<nr);
+		printk(DRIVER_NAME ": Supports only %i em28xx boards.\n",
+				EM28XX_MAXBOARDS);
+		em28xx_devused &= ~(1<<nr);
 		return -ENOMEM;
 	}
 
@@ -2121,7 +2146,7 @@
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (dev == NULL) {
 		em28xx_err(DRIVER_NAME ": out of memory!\n");
-		em28xx_devused&=~(1<<nr);
+		em28xx_devused &= ~(1<<nr);
 		return -ENOMEM;
 	}
 
@@ -2145,14 +2170,14 @@
 	/* compute alternate max packet sizes */
 	uif = udev->actconfig->interface[0];
 
-	dev->num_alt=uif->num_altsetting;
-	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);
+	dev->num_alt = uif->num_altsetting;
+	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_errdev("out of memory!\n");
-		em28xx_devused&=~(1<<nr);
+		em28xx_devused &= ~(1<<nr);
 		kfree(dev);
 		return -ENOMEM;
 	}
@@ -2162,11 +2187,11 @@
 							wMaxPacketSize);
 		dev->alt_max_pkt_size[i] =
 		    (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
-		em28xx_info("Alternate setting %i, max size= %i\n",i,
-							dev->alt_max_pkt_size[i]);
+		em28xx_info("Alternate setting %i, max size= %i\n", i,
+						dev->alt_max_pkt_size[i]);
 	}
 
-	if ((card[nr]>=0)&&(card[nr]<em28xx_bcount))
+	if ((card[nr] >= 0) && (card[nr] < em28xx_bcount))
 		dev->model = card[nr];
 
 	/* allocate device struct */
@@ -2202,7 +2227,8 @@
 
 	em28xx_info("disconnecting %s\n", dev->vdev->name);
 
-	/* wait until all current v4l2 io is finished then deallocate resources */
+	/* wait until all current v4l2 io is finished then deallocate
+	   resources */
 	mutex_lock(&dev->lock);
 
 	wake_up_interruptible_all(&dev->open);
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index 04e0e48..002f170 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -26,11 +26,39 @@
 #define _EM28XX_H
 
 #include <linux/videodev2.h>
+#include <media/videobuf-vmalloc.h>
+
 #include <linux/i2c.h>
 #include <linux/mutex.h>
 #include <media/ir-kbd-i2c.h>
+#if defined(CONFIG_VIDEO_EM28XX_DVB) || defined(CONFIG_VIDEO_EM28XX_DVB_MODULE)
+#include <media/videobuf-dvb.h>
+#endif
+#include "tuner-xc2028.h"
+#include "em28xx-reg.h"
 
-#define UNSET -1
+/* Boards supported by driver */
+#define EM2800_BOARD_UNKNOWN			0
+#define EM2820_BOARD_UNKNOWN			1
+#define EM2820_BOARD_TERRATEC_CINERGY_250	2
+#define EM2820_BOARD_PINNACLE_USB_2		3
+#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2      4
+#define EM2820_BOARD_MSI_VOX_USB_2              5
+#define EM2800_BOARD_TERRATEC_CINERGY_200       6
+#define EM2800_BOARD_LEADTEK_WINFAST_USBII      7
+#define EM2800_BOARD_KWORLD_USB2800             8
+#define EM2820_BOARD_PINNACLE_DVC_90		9
+#define 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 EM2820_BOARD_PROLINK_PLAYTV_USB2	14
+#define EM2800_BOARD_VGEAR_POCKETTV             15
+#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950	16
+
+/* Limits minimum and default number of buffers */
+#define EM28XX_MIN_BUF 4
+#define EM28XX_DEF_BUF 8
 
 /* maximum number of em28xx boards */
 #define EM28XX_MAXBOARDS 4 /*FIXME: should be bigger */
@@ -81,31 +109,78 @@
 /* time in msecs to wait for i2c writes to finish */
 #define EM2800_I2C_WRITE_TIMEOUT 20
 
-/* the various frame states */
-enum em28xx_frame_state {
-	F_UNUSED = 0,
-	F_QUEUED,
-	F_GRABBING,
-	F_DONE,
-	F_ERROR,
+enum em28xx_mode {
+	EM28XX_MODE_UNDEFINED,
+	EM28XX_ANALOG_MODE,
+	EM28XX_DIGITAL_MODE,
 };
 
-/* stream states */
 enum em28xx_stream_state {
 	STREAM_OFF,
 	STREAM_INTERRUPT,
 	STREAM_ON,
 };
 
-/* frames */
-struct em28xx_frame_t {
-	void *bufmem;
-	struct v4l2_buffer buf;
-	enum em28xx_frame_state state;
+struct em28xx;
+
+struct em28xx_usb_isoc_ctl {
+		/* max packet size of isoc transaction */
+	int				max_pkt_size;
+
+		/* number of allocated urbs */
+	int				num_bufs;
+
+		/* urb for isoc transfers */
+	struct urb			**urb;
+
+		/* transfer buffers for isoc transfer */
+	char				**transfer_buffer;
+
+		/* Last buffer command and region */
+	u8				cmd;
+	int				pos, size, pktsize;
+
+		/* Last field: ODD or EVEN? */
+	int				field;
+
+		/* Stores incomplete commands */
+	u32				tmp_buf;
+	int				tmp_buf_len;
+
+		/* Stores already requested buffers */
+	struct em28xx_buffer    	*buf;
+
+		/* Stores the number of received fields */
+	int				nfields;
+
+		/* isoc urb callback */
+	int (*isoc_copy) (struct em28xx *dev, struct urb *urb);
+
+};
+
+struct em28xx_fmt {
+	char  *name;
+	u32   fourcc;          /* v4l2 format id */
+};
+
+/* buffer for one video frame */
+struct em28xx_buffer {
+	/* common v4l buffer stuff -- must be first */
+	struct videobuf_buffer vb;
+
 	struct list_head frame;
-	unsigned long vma_use_count;
 	int top_field;
-	int fieldbytesused;
+	int receiving;
+};
+
+struct em28xx_dmaqueue {
+	struct list_head       active;
+	struct list_head       queued;
+
+	wait_queue_head_t          wq;
+
+	/* Counters to control buffer fill */
+	int                        pos;
 };
 
 /* io methods */
@@ -152,6 +227,12 @@
 	EM28XX_SAA7114
 };
 
+struct em28xx_reg_seq {
+	int reg;
+	unsigned char val, mask;
+	int sleep;
+};
+
 struct em28xx_board {
 	char *name;
 	int vchannels;
@@ -165,8 +246,7 @@
 	unsigned int mts_firmware:1;
 	unsigned int has_12mhz_i2s:1;
 	unsigned int max_range_640_480:1;
-
-	unsigned int analog_gpio;
+	unsigned int has_dvb:1;
 
 	enum em28xx_decoder decoder;
 
@@ -199,7 +279,10 @@
 #define EM28XX_NUM_AUDIO_PACKETS 64
 #define EM28XX_AUDIO_MAX_PACKET_SIZE 196 /* static value */
 #define EM28XX_CAPTURE_STREAM_EN 1
+
+/* em28xx extensions */
 #define EM28XX_AUDIO   0x10
+#define EM28XX_DVB     0x20
 
 struct em28xx_audio {
 	char name[50];
@@ -217,13 +300,24 @@
 	spinlock_t slock;
 };
 
+struct em28xx;
+
+struct em28xx_fh {
+	struct em28xx *dev;
+	unsigned int  stream_on:1;	/* Locks streams */
+	int           radio;
+
+	struct videobuf_queue        vb_vidq;
+
+	enum v4l2_buf_type           type;
+};
+
 /* main device struct */
 struct em28xx {
 	/* generic device properties */
 	char name[30];		/* name (including minor) of the device */
 	int model;		/* index in the device_data struct */
 	int devno;		/* marks the number of this device */
-	unsigned int analog_gpio;
 	unsigned int is_em2800:1;
 	unsigned int has_msp34xx:1;
 	unsigned int has_tda9887:1;
@@ -231,6 +325,16 @@
 	unsigned int has_audio_class:1;
 	unsigned int has_12mhz_i2s:1;
 	unsigned int max_range_640_480:1;
+	unsigned int has_dvb:1;
+
+	/* Some older em28xx chips needs a waiting time after writing */
+	unsigned int wait_after_write;
+
+	/* GPIO sequences for analog and digital mode */
+	struct em28xx_reg_seq *analog_gpio, *digital_gpio;
+
+	/* GPIO sequences for tuner callbacks */
+	struct em28xx_reg_seq *tun_analog_gpio, *tun_digital_gpio;
 
 	int video_inputs;	/* number of video inputs */
 	struct list_head	devlist;
@@ -255,36 +359,28 @@
 	int mute;
 	int volume;
 	/* frame properties */
-	struct em28xx_frame_t frame[EM28XX_NUM_FRAMES];	/* list of frames */
-	int num_frames;		/* number of frames currently in use */
-	unsigned int frame_count;	/* total number of transfered frames */
-	struct em28xx_frame_t *frame_current;	/* the frame that is being filled */
 	int width;		/* current frame width */
 	int height;		/* current frame height */
-	int frame_size;		/* current frame size */
-	int field_size;		/* current field size */
-	int bytesperline;
 	int hscale;		/* horizontal scale factor (see datasheet) */
 	int vscale;		/* vertical scale factor (see datasheet) */
 	int interlaced;		/* 1=interlace fileds, 0=just top fileds */
-	int type;
 	unsigned int video_bytesread;	/* Number of bytes read */
 
 	unsigned long hash;	/* eeprom hash - for boards with generic ID */
-	unsigned long i2c_hash;	/* i2c devicelist hash - for boards with generic ID */
+	unsigned long i2c_hash;	/* i2c devicelist hash -
+				   for boards with generic ID */
 
 	struct em28xx_audio *adev;
 
 	/* states */
 	enum em28xx_dev_state state;
-	enum em28xx_stream_state stream;
 	enum em28xx_io_method io;
 
 	struct work_struct         request_module_wk;
 
 	/* locks */
 	struct mutex lock;
-	spinlock_t queue_lock;
+	/* spinlock_t queue_lock; */
 	struct list_head inqueue, outqueue;
 	wait_queue_head_t open, wait_frame, wait_stream;
 	struct video_device *vbi_dev;
@@ -292,6 +388,11 @@
 
 	unsigned char eedata[256];
 
+	/* Isoc control struct */
+	struct em28xx_dmaqueue vidq;
+	struct em28xx_usb_isoc_ctl isoc_ctl;
+	spinlock_t slock;
+
 	/* usb transfer */
 	struct usb_device *udev;	/* the usb device */
 	int alt;		/* alternate */
@@ -301,20 +402,21 @@
 	struct urb *urb[EM28XX_NUM_BUFS];	/* urb for isoc transfers */
 	char *transfer_buffer[EM28XX_NUM_BUFS];	/* transfer buffers for isoc transfer */
 	/* helper funcs that call usb_control_msg */
-	int (*em28xx_write_regs) (struct em28xx * dev, u16 reg, char *buf,
-				  int len);
-	int (*em28xx_read_reg) (struct em28xx * dev, u16 reg);
-	int (*em28xx_read_reg_req_len) (struct em28xx * dev, u8 req, u16 reg,
+	int (*em28xx_write_regs) (struct em28xx *dev, u16 reg,
 					char *buf, int len);
-	int (*em28xx_write_regs_req) (struct em28xx * dev, u8 req, u16 reg,
+	int (*em28xx_read_reg) (struct em28xx *dev, u16 reg);
+	int (*em28xx_read_reg_req_len) (struct em28xx *dev, u8 req, u16 reg,
+					char *buf, int len);
+	int (*em28xx_write_regs_req) (struct em28xx *dev, u8 req, u16 reg,
 				      char *buf, int len);
-	int (*em28xx_read_reg_req) (struct em28xx * dev, u8 req, u16 reg);
-};
+	int (*em28xx_read_reg_req) (struct em28xx *dev, u8 req, u16 reg);
 
-struct em28xx_fh {
-	struct em28xx *dev;
-	unsigned int  stream_on:1;	/* Locks streams */
-	int           radio;
+	enum em28xx_mode mode;
+
+	/* Caches GPO and GPIO registers */
+	unsigned char	reg_gpo, reg_gpio;
+
+	struct em28xx_dvb *dvb;
 };
 
 struct em28xx_ops {
@@ -351,22 +453,27 @@
 int em28xx_capture_start(struct em28xx *dev, int start);
 int em28xx_outfmt_set_yuv422(struct em28xx *dev);
 int em28xx_resolution_set(struct em28xx *dev);
-int em28xx_init_isoc(struct em28xx *dev);
-void em28xx_uninit_isoc(struct em28xx *dev);
 int em28xx_set_alternate(struct em28xx *dev);
+int em28xx_init_isoc(struct em28xx *dev, int max_packets,
+		     int num_bufs, int max_pkt_size,
+		     int (*isoc_copy) (struct em28xx *dev, struct urb *urb));
+void em28xx_uninit_isoc(struct em28xx *dev);
+int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode);
+int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio);
 
 /* Provided by em28xx-video.c */
 int em28xx_register_extension(struct em28xx_ops *dev);
 void em28xx_unregister_extension(struct em28xx_ops *dev);
 
 /* Provided by em28xx-cards.c */
-extern int em2800_variant_detect(struct usb_device* udev,int model);
+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[];
 extern const unsigned int em28xx_bcount;
 void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir);
+int em28xx_tuner_callback(void *ptr, int command, int arg);
 
 /* Provided by em28xx-input.c */
 /* TODO: Check if the standard get_key handlers on ir-common can be used */
@@ -375,71 +482,6 @@
 int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
 				     u32 *ir_raw);
 
-/* em2800 registers */
-#define EM2800_AUDIOSRC_REG 0x08
-
-/* em28xx registers */
-#define I2C_CLK_REG	0x06
-#define CHIPID_REG	0x0a
-#define USBSUSP_REG	0x0c	/* */
-
-#define AUDIOSRC_REG	0x0e
-#define XCLK_REG	0x0f
-
-#define VINMODE_REG	0x10
-#define VINCTRL_REG	0x11
-#define VINENABLE_REG	0x12	/* */
-
-#define GAMMA_REG	0x14
-#define RGAIN_REG	0x15
-#define GGAIN_REG	0x16
-#define BGAIN_REG	0x17
-#define ROFFSET_REG	0x18
-#define GOFFSET_REG	0x19
-#define BOFFSET_REG	0x1a
-
-#define OFLOW_REG	0x1b
-#define HSTART_REG	0x1c
-#define VSTART_REG	0x1d
-#define CWIDTH_REG	0x1e
-#define CHEIGHT_REG	0x1f
-
-#define YGAIN_REG	0x20
-#define YOFFSET_REG	0x21
-#define UVGAIN_REG	0x22
-#define UOFFSET_REG	0x23
-#define VOFFSET_REG	0x24
-#define SHARPNESS_REG	0x25
-
-#define COMPR_REG	0x26
-#define OUTFMT_REG	0x27
-
-#define XMIN_REG	0x28
-#define XMAX_REG	0x29
-#define YMIN_REG	0x2a
-#define YMAX_REG	0x2b
-
-#define HSCALELOW_REG	0x30
-#define HSCALEHIGH_REG	0x31
-#define VSCALELOW_REG	0x32
-#define VSCALEHIGH_REG	0x33
-
-#define AC97LSB_REG	0x40
-#define AC97MSB_REG	0x41
-#define AC97ADDR_REG	0x42
-#define AC97BUSY_REG	0x43
-
-/* em202 registers */
-#define MASTER_AC97	0x02
-#define LINE_IN_AC97    0x10
-#define VIDEO_AC97	0x14
-
-/* register settings */
-#define EM2800_AUDIO_SRC_TUNER  0x0d
-#define EM2800_AUDIO_SRC_LINE   0x0c
-#define EM28XX_AUDIO_SRC_TUNER	0xc0
-#define EM28XX_AUDIO_SRC_LINE	0x80
-
 /* printk macros */
 
 #define em28xx_err(fmt, arg...) do {\
@@ -456,80 +498,80 @@
 	printk(KERN_WARNING "%s: "fmt,\
 			dev->name , ##arg); } while (0)
 
-inline static int em28xx_compression_disable(struct em28xx *dev)
+static inline int em28xx_compression_disable(struct em28xx *dev)
 {
 	/* side effect of disabling scaler and mixer */
-	return em28xx_write_regs(dev, COMPR_REG, "\x00", 1);
+	return em28xx_write_regs(dev, EM28XX_R26_COMPR, "\x00", 1);
 }
 
-inline static int em28xx_contrast_get(struct em28xx *dev)
+static inline int em28xx_contrast_get(struct em28xx *dev)
 {
-	return em28xx_read_reg(dev, YGAIN_REG) & 0x1f;
+	return em28xx_read_reg(dev, EM28XX_R20_YGAIN) & 0x1f;
 }
 
-inline static int em28xx_brightness_get(struct em28xx *dev)
+static inline int em28xx_brightness_get(struct em28xx *dev)
 {
-	return em28xx_read_reg(dev, YOFFSET_REG);
+	return em28xx_read_reg(dev, EM28XX_R21_YOFFSET);
 }
 
-inline static int em28xx_saturation_get(struct em28xx *dev)
+static inline int em28xx_saturation_get(struct em28xx *dev)
 {
-	return em28xx_read_reg(dev, UVGAIN_REG) & 0x1f;
+	return em28xx_read_reg(dev, EM28XX_R22_UVGAIN) & 0x1f;
 }
 
-inline static int em28xx_u_balance_get(struct em28xx *dev)
+static inline int em28xx_u_balance_get(struct em28xx *dev)
 {
-	return em28xx_read_reg(dev, UOFFSET_REG);
+	return em28xx_read_reg(dev, EM28XX_R23_UOFFSET);
 }
 
-inline static int em28xx_v_balance_get(struct em28xx *dev)
+static inline int em28xx_v_balance_get(struct em28xx *dev)
 {
-	return em28xx_read_reg(dev, VOFFSET_REG);
+	return em28xx_read_reg(dev, EM28XX_R24_VOFFSET);
 }
 
-inline static int em28xx_gamma_get(struct em28xx *dev)
+static inline int em28xx_gamma_get(struct em28xx *dev)
 {
-	return em28xx_read_reg(dev, GAMMA_REG) & 0x3f;
+	return em28xx_read_reg(dev, EM28XX_R14_GAMMA) & 0x3f;
 }
 
-inline static int em28xx_contrast_set(struct em28xx *dev, s32 val)
+static inline int em28xx_contrast_set(struct em28xx *dev, s32 val)
 {
 	u8 tmp = (u8) val;
-	return em28xx_write_regs(dev, YGAIN_REG, &tmp, 1);
+	return em28xx_write_regs(dev, EM28XX_R20_YGAIN, &tmp, 1);
 }
 
-inline static int em28xx_brightness_set(struct em28xx *dev, s32 val)
+static inline int em28xx_brightness_set(struct em28xx *dev, s32 val)
 {
 	u8 tmp = (u8) val;
-	return em28xx_write_regs(dev, YOFFSET_REG, &tmp, 1);
+	return em28xx_write_regs(dev, EM28XX_R21_YOFFSET, &tmp, 1);
 }
 
-inline static int em28xx_saturation_set(struct em28xx *dev, s32 val)
+static inline int em28xx_saturation_set(struct em28xx *dev, s32 val)
 {
 	u8 tmp = (u8) val;
-	return em28xx_write_regs(dev, UVGAIN_REG, &tmp, 1);
+	return em28xx_write_regs(dev, EM28XX_R22_UVGAIN, &tmp, 1);
 }
 
-inline static int em28xx_u_balance_set(struct em28xx *dev, s32 val)
+static inline int em28xx_u_balance_set(struct em28xx *dev, s32 val)
 {
 	u8 tmp = (u8) val;
-	return em28xx_write_regs(dev, UOFFSET_REG, &tmp, 1);
+	return em28xx_write_regs(dev, EM28XX_R23_UOFFSET, &tmp, 1);
 }
 
-inline static int em28xx_v_balance_set(struct em28xx *dev, s32 val)
+static inline int em28xx_v_balance_set(struct em28xx *dev, s32 val)
 {
 	u8 tmp = (u8) val;
-	return em28xx_write_regs(dev, VOFFSET_REG, &tmp, 1);
+	return em28xx_write_regs(dev, EM28XX_R24_VOFFSET, &tmp, 1);
 }
 
-inline static int em28xx_gamma_set(struct em28xx *dev, s32 val)
+static inline int em28xx_gamma_set(struct em28xx *dev, s32 val)
 {
 	u8 tmp = (u8) val;
-	return em28xx_write_regs(dev, GAMMA_REG, &tmp, 1);
+	return em28xx_write_regs(dev, EM28XX_R14_GAMMA, &tmp, 1);
 }
 
 /*FIXME: maxw should be dependent of alt mode */
-inline static unsigned int norm_maxw(struct em28xx *dev)
+static inline unsigned int norm_maxw(struct em28xx *dev)
 {
 	if (dev->max_range_640_480)
 		return 640;
@@ -537,7 +579,7 @@
 		return 720;
 }
 
-inline static unsigned int norm_maxh(struct em28xx *dev)
+static inline unsigned int norm_maxh(struct em28xx *dev)
 {
 	if (dev->max_range_640_480)
 		return 480;
diff --git a/drivers/media/video/et61x251/et61x251.h b/drivers/media/video/et61x251/et61x251.h
index 02c741d..cc77d14 100644
--- a/drivers/media/video/et61x251/et61x251.h
+++ b/drivers/media/video/et61x251/et61x251.h
@@ -199,7 +199,7 @@
 			dev_info(&cam->usbdev->dev, fmt "\n", ## args);       \
 		else if ((level) >= 3)                                        \
 			dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n",   \
-				 __FILE__, __FUNCTION__, __LINE__ , ## args); \
+				 __FILE__, __func__, __LINE__ , ## args); \
 	}                                                                     \
 } while (0)
 #	define KDBG(level, fmt, args...)                                      \
@@ -209,7 +209,7 @@
 			pr_info("et61x251: " fmt "\n", ## args);              \
 		else if ((level) == 3)                                        \
 			pr_debug("sn9c102: [%s:%s:%d] " fmt "\n", __FILE__,   \
-				 __FUNCTION__, __LINE__ , ## args);           \
+				 __func__, __LINE__ , ## args);           \
 	}                                                                     \
 } while (0)
 #	define V4LDBG(level, name, cmd)                                       \
@@ -225,7 +225,7 @@
 
 #undef PDBG
 #define PDBG(fmt, args...)                                                    \
-dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__,   \
+dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __func__,   \
 	 __LINE__ , ## args)
 
 #undef PDBGG
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
index 06b6a3a..5e749c5 100644
--- a/drivers/media/video/et61x251/et61x251_core.c
+++ b/drivers/media/video/et61x251/et61x251_core.c
@@ -2523,7 +2523,9 @@
 	.open =    et61x251_open,
 	.release = et61x251_release,
 	.ioctl =   et61x251_ioctl,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl = v4l_compat_ioctl32,
+#endif
 	.read =    et61x251_read,
 	.poll =    et61x251_poll,
 	.mmap =    et61x251_mmap,
@@ -2538,7 +2540,7 @@
 {
 	struct usb_device *udev = interface_to_usbdev(intf);
 	struct et61x251_device* cam;
-	static unsigned int dev_nr = 0;
+	static unsigned int dev_nr;
 	unsigned int i;
 	int err = 0;
 
diff --git a/drivers/media/video/hexium_gemini.c b/drivers/media/video/hexium_gemini.c
index c7fed34..352f84d 100644
--- a/drivers/media/video/hexium_gemini.c
+++ b/drivers/media/video/hexium_gemini.c
@@ -25,12 +25,12 @@
 
 #include <media/saa7146_vv.h>
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "debug verbosity");
 
 /* global variables */
-static int hexium_num = 0;
+static int hexium_num;
 
 #define HEXIUM_GEMINI			4
 #define HEXIUM_GEMINI_DUAL		5
diff --git a/drivers/media/video/hexium_orion.c b/drivers/media/video/hexium_orion.c
index 137c473..8d3c148 100644
--- a/drivers/media/video/hexium_orion.c
+++ b/drivers/media/video/hexium_orion.c
@@ -25,12 +25,12 @@
 
 #include <media/saa7146_vv.h>
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "debug verbosity");
 
 /* global variables */
-static int hexium_num = 0;
+static int hexium_num;
 
 #define HEXIUM_HV_PCI6_ORION		1
 #define HEXIUM_ORION_1SVHS_3BNC		2
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index dabafdf..11c5fde 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -50,7 +50,7 @@
 static int debug;
 module_param(debug, int, 0644);    /* debug level (0,1,2) */
 
-static int hauppauge = 0;
+static int hauppauge;
 module_param(hauppauge, int, 0644);    /* Choose Hauppauge remote */
 MODULE_PARM_DESC(hauppauge, "Specify Hauppauge remote: 0=black, 1=grey (defaults to 0)");
 
@@ -153,7 +153,7 @@
 	}
 
 	if(buf[0] !=0 || buf[1] !=0 || buf[2] !=0 || buf[3] != 0)
-		dprintk(2, "%s: 0x%2x 0x%2x 0x%2x 0x%2x\n", __FUNCTION__,
+		dprintk(2, "%s: 0x%2x 0x%2x 0x%2x 0x%2x\n", __func__,
 			buf[0], buf[1], buf[2], buf[3]);
 
 	/* no key pressed or signal from other ir remote */
@@ -508,10 +508,10 @@
 	static const int probe_em28XX[] = { 0x30, 0x47, -1 };
 	static const int probe_cx88[] = { 0x18, 0x6b, 0x71, -1 };
 	static const int probe_cx23885[] = { 0x6b, -1 };
-	const int *probe = NULL;
-	struct i2c_client c;
+	const int *probe;
+	struct i2c_client *c;
 	unsigned char buf;
-	int i,rc;
+	int i, rc;
 
 	switch (adap->id) {
 	case I2C_HW_B_BT848:
@@ -532,23 +532,27 @@
 	case I2C_HW_B_CX23885:
 		probe = probe_cx23885;
 		break;
-	}
-	if (NULL == probe)
+	default:
 		return 0;
+	}
 
-	memset(&c,0,sizeof(c));
-	c.adapter = adap;
+	c = kzalloc(sizeof(*c), GFP_KERNEL);
+	if (!c)
+		return -ENOMEM;
+
+	c->adapter = adap;
 	for (i = 0; -1 != probe[i]; i++) {
-		c.addr = probe[i];
-		rc = i2c_master_recv(&c,&buf,0);
+		c->addr = probe[i];
+		rc = i2c_master_recv(c, &buf, 0);
 		dprintk(1,"probe 0x%02x @ %s: %s\n",
 			probe[i], adap->name,
 			(0 == rc) ? "yes" : "no");
 		if (0 == rc) {
-			ir_attach(adap,probe[i],0,0);
+			ir_attach(adap, probe[i], 0, 0);
 			break;
 		}
 	}
+	kfree(c);
 	return 0;
 }
 
diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig
index 270906f..b617170 100644
--- a/drivers/media/video/ivtv/Kconfig
+++ b/drivers/media/video/ivtv/Kconfig
@@ -10,6 +10,7 @@
 	select VIDEO_CX25840
 	select VIDEO_MSP3400
 	select VIDEO_SAA711X
+	select VIDEO_SAA717X
 	select VIDEO_SAA7127
 	select VIDEO_TVAUDIO
 	select VIDEO_CS53L32A
diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c
index f23c6b8..e908649 100644
--- a/drivers/media/video/ivtv/ivtv-cards.c
+++ b/drivers/media/video/ivtv/ivtv-cards.c
@@ -416,11 +416,10 @@
 	   on the country/region setting of the user to decide which tuner
 	   is available. */
 	.tuners = {
-		/* This tuner has been verified for the AVC2410 */
 		{ .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
-		/* This is a good guess, but I'm not totally sure this is
-		   the correct tuner for NTSC. */
-		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
+		{ .std = V4L2_STD_ALL - V4L2_STD_NTSC_M_JP,
+			.tuner = TUNER_PHILIPS_FM1236_MK3 },
+		{ .std = V4L2_STD_NTSC_M_JP, .tuner = TUNER_PHILIPS_FQ1286 },
 	},
 	.pci_list = ivtv_pci_avc2410,
 	.i2c = &ivtv_i2c_std,
diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h
index 191aafd..9186fa2 100644
--- a/drivers/media/video/ivtv/ivtv-cards.h
+++ b/drivers/media/video/ivtv/ivtv-cards.h
@@ -119,7 +119,7 @@
 
 #define IVTV_CARD_MAX_VIDEO_INPUTS 6
 #define IVTV_CARD_MAX_AUDIO_INPUTS 3
-#define IVTV_CARD_MAX_TUNERS  	   2
+#define IVTV_CARD_MAX_TUNERS  	   3
 
 /* SAA71XX HW inputs */
 #define IVTV_SAA71XX_COMPOSITE0 0
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 948ca35..065df53 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -101,7 +101,7 @@
 static unsigned int cardtype_c = 1;
 static unsigned int tuner_c = 1;
 static unsigned int radio_c = 1;
-static char pal[] = "--";
+static char pal[] = "---";
 static char secam[] = "--";
 static char ntsc[] = "-";
 
@@ -126,12 +126,13 @@
 static int dec_yuv_buffers = IVTV_DEFAULT_DEC_YUV_BUFFERS;
 static int dec_vbi_buffers = IVTV_DEFAULT_DEC_VBI_BUFFERS;
 
-static int ivtv_yuv_mode = 0;
-static int ivtv_yuv_threshold=-1;
+static int ivtv_yuv_mode;
+static int ivtv_yuv_threshold = -1;
 static int ivtv_pci_latency = 1;
 
-int ivtv_debug = 0;
+int ivtv_debug;
 
+static int tunertype = -1;
 static int newi2c = -1;
 
 module_param_array(tuner, int, &tuner_c, 0644);
@@ -154,6 +155,7 @@
 module_param(dec_yuv_buffers, int, 0644);
 module_param(dec_vbi_buffers, int, 0644);
 
+module_param(tunertype, int, 0644);
 module_param(newi2c, int, 0644);
 
 MODULE_PARM_DESC(tuner, "Tuner type selection,\n"
@@ -190,9 +192,14 @@
 		 "\t\t\t24 = AverMedia EZMaker PCI Deluxe\n"
 		 "\t\t\t 0 = Autodetect (default)\n"
 		 "\t\t\t-1 = Ignore this card\n\t\t");
-MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
-MODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC");
-MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K");
+MODULE_PARM_DESC(pal, "Set PAL standard: BGH, DK, I, M, N, Nc, 60");
+MODULE_PARM_DESC(secam, "Set SECAM standard: BGH, DK, L, LC");
+MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J (Japan), K (South Korea)");
+MODULE_PARM_DESC(tunertype,
+		"Specify tuner type:\n"
+		"\t\t\t 0 = tuner for PAL-B/G/H/D/K/I, SECAM-B/G/H/D/K/L/Lc\n"
+		"\t\t\t 1 = tuner for NTSC-M/J/K, PAL-M/N/Nc\n"
+		"\t\t\t-1 = Autodetect (default)\n");
 MODULE_PARM_DESC(debug,
 		 "Debug level (bitmask). Default: 0\n"
 		 "\t\t\t   1/0x0001: warning\n"
@@ -490,30 +497,35 @@
 {
 	switch (pal[0]) {
 		case '6':
+			tunertype = 0;
 			return V4L2_STD_PAL_60;
 		case 'b':
 		case 'B':
 		case 'g':
 		case 'G':
-			return V4L2_STD_PAL_BG;
 		case 'h':
 		case 'H':
-			return V4L2_STD_PAL_H;
+			tunertype = 0;
+			return V4L2_STD_PAL_BG | V4L2_STD_PAL_H;
 		case 'n':
 		case 'N':
+			tunertype = 1;
 			if (pal[1] == 'c' || pal[1] == 'C')
 				return V4L2_STD_PAL_Nc;
 			return V4L2_STD_PAL_N;
 		case 'i':
 		case 'I':
+			tunertype = 0;
 			return V4L2_STD_PAL_I;
 		case 'd':
 		case 'D':
 		case 'k':
 		case 'K':
+			tunertype = 0;
 			return V4L2_STD_PAL_DK;
 		case 'M':
 		case 'm':
+			tunertype = 1;
 			return V4L2_STD_PAL_M;
 		case '-':
 			break;
@@ -529,14 +541,17 @@
 		case 'G':
 		case 'h':
 		case 'H':
+			tunertype = 0;
 			return V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
 		case 'd':
 		case 'D':
 		case 'k':
 		case 'K':
+			tunertype = 0;
 			return V4L2_STD_SECAM_DK;
 		case 'l':
 		case 'L':
+			tunertype = 0;
 			if (secam[1] == 'C' || secam[1] == 'c')
 				return V4L2_STD_SECAM_LC;
 			return V4L2_STD_SECAM_L;
@@ -550,12 +565,15 @@
 	switch (ntsc[0]) {
 		case 'm':
 		case 'M':
+			tunertype = 1;
 			return V4L2_STD_NTSC_M;
 		case 'j':
 		case 'J':
+			tunertype = 1;
 			return V4L2_STD_NTSC_M_JP;
 		case 'k':
 		case 'K':
+			tunertype = 1;
 			return V4L2_STD_NTSC_M_KR;
 		case '-':
 			break;
@@ -584,8 +602,13 @@
 	itv->options.tuner = tuner[itv->num];
 	itv->options.radio = radio[itv->num];
 	itv->options.newi2c = newi2c;
-
+	if (tunertype < -1 || tunertype > 1) {
+		IVTV_WARN("Invalid tunertype argument, will autodetect instead\n");
+		tunertype = -1;
+	}
 	itv->std = ivtv_parse_std(itv);
+	if (itv->std == 0 && tunertype >= 0)
+		itv->std = tunertype ? V4L2_STD_MN : (V4L2_STD_ALL & ~V4L2_STD_MN);
 	itv->has_cx23415 = (itv->dev->device == PCI_DEVICE_ID_IVTV15);
 	chipname = itv->has_cx23415 ? "cx23415" : "cx23416";
 	if (itv->options.cardtype == -1) {
@@ -711,6 +734,7 @@
 	itv->yuv_info.lace_mode = ivtv_yuv_mode;
 	itv->yuv_info.lace_threshold = ivtv_yuv_threshold;
 	itv->yuv_info.max_frames_buffered = 3;
+	itv->yuv_info.track_osd = 1;
 	return 0;
 }
 
@@ -859,7 +883,9 @@
 #ifndef CONFIG_VIDEO_SAA7127
 	hw = ivtv_request_module(itv, hw, "saa7127", IVTV_HW_SAA7127);
 #endif
+#ifndef CONFIG_VIDEO_SAA717X
 	hw = ivtv_request_module(itv, hw, "saa717x", IVTV_HW_SAA717X);
+#endif
 #ifndef CONFIG_VIDEO_UPD64031A
 	hw = ivtv_request_module(itv, hw, "upd64031a", IVTV_HW_UPD64031A);
 #endif
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index 536140f..ba06e81 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -456,6 +456,8 @@
 	int v_filter_2;
 	int h_filter;
 
+	u8 track_osd; /* Should yuv output track the OSD size & position */
+
 	u32 osd_x_offset;
 	u32 osd_y_offset;
 
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index 6fb96f1..a7640c4 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -219,7 +219,9 @@
 			/* Process pending program info updates and pending VBI data */
 			ivtv_update_pgm_info(itv);
 
-			if (jiffies - itv->dualwatch_jiffies > msecs_to_jiffies(1000)) {
+			if (time_after(jiffies,
+				       itv->dualwatch_jiffies +
+				       msecs_to_jiffies(1000))) {
 				itv->dualwatch_jiffies = jiffies;
 				ivtv_dualwatch(itv);
 			}
@@ -753,7 +755,7 @@
 	IVTV_DEBUG_HI_FILE("Encoder poll\n");
 	poll_wait(filp, &s->waitq, wait);
 
-	if (eof || s->q_full.length)
+	if (eof || s->q_full.length || s->q_io.length)
 		return POLLIN | POLLRDNORM;
 	return 0;
 }
diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
index fa5ab1e..9824eaf 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/drivers/media/video/ivtv/ivtv-i2c.c
@@ -177,10 +177,16 @@
 	}
 
 	if (id != I2C_DRIVERID_TUNER) {
-		c = i2c_new_device(&itv->i2c_adap, &info);
-		if (c->driver == NULL)
+		if (id == I2C_DRIVERID_UPD64031A ||
+		    id == I2C_DRIVERID_UPD64083) {
+			unsigned short addrs[2] = { info.addr, I2C_CLIENT_END };
+
+			c = i2c_new_probed_device(&itv->i2c_adap, &info, addrs);
+		} else
+			c = i2c_new_device(&itv->i2c_adap, &info);
+		if (c && c->driver == NULL)
 			i2c_unregister_device(c);
-		else
+		else if (c)
 			itv->i2c_clients[i] = c;
 		return itv->i2c_clients[i] ? 0 : -ENODEV;
 	}
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
index edef2a5..15cac18 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -712,6 +712,7 @@
 int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg)
 {
 	struct ivtv_open_id *id = NULL;
+	struct yuv_playback_info *yi = &itv->yuv_info;
 	u32 data[CX2341X_MBOX_MAX_DATA];
 	int streamtype = 0;
 
@@ -741,7 +742,8 @@
 
 		memset(vcap, 0, sizeof(*vcap));
 		strcpy(vcap->driver, IVTV_DRIVER_NAME);     /* driver name */
-		strcpy(vcap->card, itv->card_name); 	    /* card type */
+		strncpy(vcap->card, itv->card_name,
+				sizeof(vcap->card)-1); 	    /* card type */
 		strcpy(vcap->bus_info, pci_name(itv->dev)); /* bus info... */
 		vcap->version = IVTV_DRIVER_VERSION; 	    /* version */
 		vcap->capabilities = itv->v4l2_cap; 	    /* capabilities */
@@ -827,8 +829,7 @@
 	case VIDIOC_CROPCAP: {
 		struct v4l2_cropcap *cropcap = arg;
 
-		if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-		    cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
 			return -EINVAL;
 		cropcap->bounds.top = cropcap->bounds.left = 0;
 		cropcap->bounds.width = 720;
@@ -837,8 +838,14 @@
 			cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10;
 			cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11;
 		} else if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
-			cropcap->bounds.width = itv->yuv_info.osd_full_w;
-			cropcap->bounds.height = itv->yuv_info.osd_full_h;
+			if (yi->track_osd) {
+				cropcap->bounds.width = yi->osd_full_w;
+				cropcap->bounds.height = yi->osd_full_h;
+			} else {
+				cropcap->bounds.width = 720;
+				cropcap->bounds.height =
+						itv->is_out_50hz ? 576 : 480;
+			}
 			cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
 			cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
 		} else {
@@ -856,7 +863,7 @@
 		if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
 		    (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
 			if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
-				itv->yuv_info.main_rect = crop->c;
+				yi->main_rect = crop->c;
 				return 0;
 			} else {
 				if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
@@ -867,9 +874,7 @@
 			}
 			return -EINVAL;
 		}
-		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-			return -EINVAL;
-		return itv->video_dec_func(itv, VIDIOC_S_CROP, arg);
+		return -EINVAL;
 	}
 
 	case VIDIOC_G_CROP: {
@@ -878,14 +883,12 @@
 		if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
 		    (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
 			if (streamtype == IVTV_DEC_STREAM_TYPE_YUV)
-				crop->c = itv->yuv_info.main_rect;
+				crop->c = yi->main_rect;
 			else
 				crop->c = itv->main_rect;
 			return 0;
 		}
-		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-			return -EINVAL;
-		return itv->video_dec_func(itv, VIDIOC_G_CROP, arg);
+		return -EINVAL;
 	}
 
 	case VIDIOC_ENUM_FMT: {
@@ -1070,11 +1073,10 @@
 			itv->main_rect.height = itv->params.height;
 			ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
 				720, itv->main_rect.height, 0, 0);
-			itv->yuv_info.main_rect = itv->main_rect;
+			yi->main_rect = itv->main_rect;
 			if (!itv->osd_info) {
-				itv->yuv_info.osd_full_w = 720;
-				itv->yuv_info.osd_full_h =
-						itv->is_out_50hz ? 576 : 480;
+				yi->osd_full_w = 720;
+				yi->osd_full_h = itv->is_out_50hz ? 576 : 480;
 			}
 		}
 		break;
@@ -1272,6 +1274,8 @@
 			else
 				fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
 		}
+		if (yi->track_osd)
+			fb->flags |= V4L2_FBUF_FLAG_OVERLAY;
 		break;
 	}
 
@@ -1285,6 +1289,7 @@
 			(fb->flags & (V4L2_FBUF_FLAG_LOCAL_ALPHA|V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)) != 0;
 		itv->osd_chroma_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
 		ivtv_set_osd_alpha(itv);
+		yi->track_osd = (fb->flags & V4L2_FBUF_FLAG_OVERLAY) != 0;
 		break;
 	}
 
@@ -1628,6 +1633,7 @@
 		if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
 			printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
 			v4l_printk_ioctl(cmd);
+			printk("\n");
 		}
 		return ivtv_debug_ioctls(filp, cmd, arg);
 
@@ -1671,6 +1677,7 @@
 		if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
 			printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
 			v4l_printk_ioctl(cmd);
+			printk("\n");
 		}
 		return ivtv_v4l2_ioctls(itv, filp, cmd, arg);
 
@@ -1684,6 +1691,7 @@
 		if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
 			printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
 			v4l_printk_ioctl(cmd);
+			printk("\n");
 		}
 		return ivtv_control_ioctls(itv, cmd, arg);
 
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c
index 65604dd..a329c46 100644
--- a/drivers/media/video/ivtv/ivtv-irq.c
+++ b/drivers/media/video/ivtv/ivtv-irq.c
@@ -384,6 +384,8 @@
 	ivtv_stream_sync_for_device(s);
 	write_reg(s->sg_handle, IVTV_REG_ENCDMAADDR);
 	write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER);
+	itv->dma_timer.expires = jiffies + msecs_to_jiffies(100);
+	add_timer(&itv->dma_timer);
 }
 
 static void ivtv_dma_dec_start_xfer(struct ivtv_stream *s)
@@ -398,6 +400,8 @@
 	ivtv_stream_sync_for_device(s);
 	write_reg(s->sg_handle, IVTV_REG_DECDMAADDR);
 	write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER);
+	itv->dma_timer.expires = jiffies + msecs_to_jiffies(100);
+	add_timer(&itv->dma_timer);
 }
 
 /* start the encoder DMA */
@@ -459,8 +463,6 @@
 		ivtv_dma_enc_start_xfer(s);
 		set_bit(IVTV_F_I_DMA, &itv->i_flags);
 		itv->cur_dma_stream = s->type;
-		itv->dma_timer.expires = jiffies + msecs_to_jiffies(100);
-		add_timer(&itv->dma_timer);
 	}
 }
 
@@ -481,8 +483,6 @@
 	ivtv_dma_dec_start_xfer(s);
 	set_bit(IVTV_F_I_DMA, &itv->i_flags);
 	itv->cur_dma_stream = s->type;
-	itv->dma_timer.expires = jiffies + msecs_to_jiffies(100);
-	add_timer(&itv->dma_timer);
 }
 
 static void ivtv_irq_dma_read(struct ivtv *itv)
@@ -492,10 +492,11 @@
 	int hw_stream_type = 0;
 
 	IVTV_DEBUG_HI_IRQ("DEC DMA READ\n");
-	if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) && itv->cur_dma_stream < 0) {
-		del_timer(&itv->dma_timer);
+
+	del_timer(&itv->dma_timer);
+
+	if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) && itv->cur_dma_stream < 0)
 		return;
-	}
 
 	if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
 		s = &itv->streams[itv->cur_dma_stream];
@@ -543,7 +544,6 @@
 		}
 		wake_up(&s->waitq);
 	}
-	del_timer(&itv->dma_timer);
 	clear_bit(IVTV_F_I_UDMA, &itv->i_flags);
 	clear_bit(IVTV_F_I_DMA, &itv->i_flags);
 	itv->cur_dma_stream = -1;
@@ -557,10 +557,12 @@
 
 	ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data);
 	IVTV_DEBUG_HI_IRQ("ENC DMA COMPLETE %x %d (%d)\n", data[0], data[1], itv->cur_dma_stream);
-	if (itv->cur_dma_stream < 0) {
-		del_timer(&itv->dma_timer);
+
+	del_timer(&itv->dma_timer);
+
+	if (itv->cur_dma_stream < 0)
 		return;
-	}
+
 	s = &itv->streams[itv->cur_dma_stream];
 	ivtv_stream_sync_for_cpu(s);
 
@@ -585,7 +587,6 @@
 		ivtv_dma_enc_start_xfer(s);
 		return;
 	}
-	del_timer(&itv->dma_timer);
 	clear_bit(IVTV_F_I_DMA, &itv->i_flags);
 	itv->cur_dma_stream = -1;
 	dma_post(s);
diff --git a/drivers/media/video/ivtv/ivtv-mailbox.c b/drivers/media/video/ivtv/ivtv-mailbox.c
index 13a6c37..1b5c0ac 100644
--- a/drivers/media/video/ivtv/ivtv-mailbox.c
+++ b/drivers/media/video/ivtv/ivtv-mailbox.c
@@ -177,7 +177,8 @@
 
 		/* Sleep before a retry, if not atomic */
 		if (!(flags & API_NO_WAIT_MB)) {
-			if (jiffies - then > msecs_to_jiffies(10*retries))
+			if (time_after(jiffies,
+				       then + msecs_to_jiffies(10*retries)))
 			       break;
 			ivtv_msleep_timeout(10, 0);
 		}
@@ -244,7 +245,9 @@
 	   data, then just return 0 as there is no need to issue this command again.
 	   Just an optimization to prevent unnecessary use of mailboxes. */
 	if (itv->api_cache[cmd].last_jiffies &&
-	    jiffies - itv->api_cache[cmd].last_jiffies < msecs_to_jiffies(1800000) &&
+	    time_before(jiffies,
+			itv->api_cache[cmd].last_jiffies +
+			msecs_to_jiffies(1800000)) &&
 	    !memcmp(data, itv->api_cache[cmd].data, sizeof(itv->api_cache[cmd].data))) {
 		itv->api_cache[cmd].last_jiffies = jiffies;
 		return 0;
@@ -299,7 +302,7 @@
 		}
 	}
 	while (!(readl(&mbox->flags) & IVTV_MBOX_FIRMWARE_DONE)) {
-		if (jiffies - then > api_timeout) {
+		if (time_after(jiffies, then + api_timeout)) {
 			IVTV_DEBUG_WARN("Could not get result (%s)\n", api_info[cmd].name);
 			/* reset the mailbox, but it is likely too late already */
 			write_sync(0, &mbox->flags);
@@ -311,7 +314,7 @@
 		else
 			ivtv_msleep_timeout(1, 0);
 	}
-	if (jiffies - then > msecs_to_jiffies(100))
+	if (time_after(jiffies, then + msecs_to_jiffies(100)))
 		IVTV_DEBUG_WARN("%s took %u jiffies\n",
 				api_info[cmd].name,
 				jiffies_to_msecs(jiffies - then));
diff --git a/drivers/media/video/ivtv/ivtv-queue.c b/drivers/media/video/ivtv/ivtv-queue.c
index 39a2167..3e1deec 100644
--- a/drivers/media/video/ivtv/ivtv-queue.c
+++ b/drivers/media/video/ivtv/ivtv-queue.c
@@ -51,7 +51,7 @@
 
 void ivtv_enqueue(struct ivtv_stream *s, struct ivtv_buffer *buf, struct ivtv_queue *q)
 {
-	unsigned long flags = 0;
+	unsigned long flags;
 
 	/* clear the buffer if it is going to be enqueued to the free queue */
 	if (q == &s->q_free) {
@@ -71,7 +71,7 @@
 struct ivtv_buffer *ivtv_dequeue(struct ivtv_stream *s, struct ivtv_queue *q)
 {
 	struct ivtv_buffer *buf = NULL;
-	unsigned long flags = 0;
+	unsigned long flags;
 
 	spin_lock_irqsave(&s->qlock, flags);
 	if (!list_empty(&q->list)) {
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index 24d98ec..4ab8d36 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -768,7 +768,8 @@
 
 			/* wait 2s for EOS interrupt */
 			while (!test_bit(IVTV_F_I_EOS, &itv->i_flags) &&
-				jiffies < then + msecs_to_jiffies (2000)) {
+				time_before(jiffies,
+					    then + msecs_to_jiffies(2000))) {
 				schedule_timeout(msecs_to_jiffies(10));
 			}
 
diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c
index 8518348..393d917 100644
--- a/drivers/media/video/ivtv/ivtv-yuv.c
+++ b/drivers/media/video/ivtv/ivtv-yuv.c
@@ -718,9 +718,11 @@
 		f->src_w -= (osd_scale * osd_crop) >> 16;
 	}
 
-	/* The OSD can be moved. Track to it */
-	f->dst_x += itv->yuv_info.osd_x_offset;
-	f->dst_y += itv->yuv_info.osd_y_offset;
+	if (itv->yuv_info.track_osd) {
+		/* The OSD can be moved. Track to it */
+		f->dst_x += itv->yuv_info.osd_x_offset;
+		f->dst_y += itv->yuv_info.osd_y_offset;
+	}
 
 	/* Width & height for both src & dst must be even.
 	   Same for coordinates. */
@@ -792,11 +794,19 @@
 	IVTV_DEBUG_YUV("Update yuv registers for frame %d\n", frame);
 	f = yi->new_frame_info[frame];
 
-	/* Update the osd pan info */
-	f.pan_x = yi->osd_x_pan;
-	f.pan_y = yi->osd_y_pan;
-	f.vis_w = yi->osd_vis_w;
-	f.vis_h = yi->osd_vis_h;
+	if (yi->track_osd) {
+		/* Snapshot the osd pan info */
+		f.pan_x = yi->osd_x_pan;
+		f.pan_y = yi->osd_y_pan;
+		f.vis_w = yi->osd_vis_w;
+		f.vis_h = yi->osd_vis_h;
+	} else {
+		/* Not tracking the osd, so assume full screen */
+		f.pan_x = 0;
+		f.pan_y = 0;
+		f.vis_w = 720;
+		f.vis_h = yi->decode_height;
+	}
 
 	/* Calculate the display window coordinates. Exit if nothing left */
 	if (!(yuv_update = ivtv_yuv_window_setup(itv, &f)))
@@ -914,7 +924,7 @@
 }
 
 /* Get next available yuv buffer on PVR350 */
-void ivtv_yuv_next_free(struct ivtv *itv)
+static void ivtv_yuv_next_free(struct ivtv *itv)
 {
 	int draw, display;
 	struct yuv_playback_info *yi = &itv->yuv_info;
@@ -937,7 +947,7 @@
 }
 
 /* Set up frame according to ivtv_dma_frame parameters */
-void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
+static void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
 {
 	struct yuv_playback_info *yi = &itv->yuv_info;
 	u8 frame = yi->draw_frame;
@@ -965,12 +975,6 @@
 	/* Are we going to offset the Y plane */
 	nf->offset_y = (nf->tru_h + nf->src_x < 512 - 16) ? 1 : 0;
 
-	/* Snapshot the osd pan info */
-	nf->pan_x = yi->osd_x_pan;
-	nf->pan_y = yi->osd_y_pan;
-	nf->vis_w = yi->osd_vis_w;
-	nf->vis_h = yi->osd_vis_h;
-
 	nf->update = 0;
 	nf->interlaced_y = 0;
 	nf->interlaced_uv = 0;
@@ -1042,7 +1046,7 @@
 			(itv->yuv_info.draw_frame + 1) % IVTV_YUV_BUFFERS);
 }
 
-int ivtv_yuv_udma_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
+static int ivtv_yuv_udma_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
 {
 	DEFINE_WAIT(wait);
 	int rc = 0;
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index 3d51fa0..e7ccbc8 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -42,15 +42,10 @@
 #include <linux/meye.h>
 
 MODULE_AUTHOR("Stelian Pop <stelian@popies.net>");
-MODULE_DESCRIPTION("v4l/v4l2 driver for the MotionEye camera");
+MODULE_DESCRIPTION("v4l2 driver for the MotionEye camera");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(MEYE_DRIVER_VERSION);
 
-/* force usage of V4L1 API */
-static int forcev4l1; /* = 0 */
-module_param(forcev4l1, int, 0644);
-MODULE_PARM_DESC(forcev4l1, "force use of V4L1 instead of V4L2");
-
 /* number of grab buffers */
 static unsigned int gbuffers = 2;
 module_param(gbuffers, int, 0444);
@@ -789,7 +784,7 @@
 {
 	u32 v;
 	int reqnr;
-	static int sequence = 0;
+	static int sequence;
 
 	v = mchip_read(MCHIP_MM_INTA);
 
@@ -876,795 +871,735 @@
 	return 0;
 }
 
-static int meye_do_ioctl(struct inode *inode, struct file *file,
-			 unsigned int cmd, void *arg)
+static int meyeioc_g_params(struct meye_params *p)
 {
-	switch (cmd) {
+	*p = meye.params;
+	return 0;
+}
 
-	case VIDIOCGCAP: {
-		struct video_capability *b = arg;
-		strcpy(b->name,meye.video_dev->name);
-		b->type = VID_TYPE_CAPTURE;
-		b->channels = 1;
-		b->audios = 0;
-		b->maxwidth = 640;
-		b->maxheight = 480;
-		b->minwidth = 320;
-		b->minheight = 240;
-		break;
+static int meyeioc_s_params(struct meye_params *jp)
+{
+	if (jp->subsample > 1)
+		return -EINVAL;
+
+	if (jp->quality > 10)
+		return -EINVAL;
+
+	if (jp->sharpness > 63 || jp->agc > 63 || jp->picture > 63)
+		return -EINVAL;
+
+	if (jp->framerate > 31)
+		return -EINVAL;
+
+	mutex_lock(&meye.lock);
+
+	if (meye.params.subsample != jp->subsample ||
+	    meye.params.quality != jp->quality)
+		mchip_hic_stop();	/* need restart */
+
+	meye.params = *jp;
+	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERASHARPNESS,
+			      meye.params.sharpness);
+	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC,
+			      meye.params.agc);
+	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE,
+			      meye.params.picture);
+	mutex_unlock(&meye.lock);
+
+	return 0;
+}
+
+static int meyeioc_qbuf_capt(int *nb)
+{
+	if (!meye.grab_fbuffer)
+		return -EINVAL;
+
+	if (*nb >= gbuffers)
+		return -EINVAL;
+
+	if (*nb < 0) {
+		/* stop capture */
+		mchip_hic_stop();
+		return 0;
 	}
 
-	case VIDIOCGCHAN: {
-		struct video_channel *v = arg;
-		v->flags = 0;
-		v->tuners = 0;
-		v->type = VIDEO_TYPE_CAMERA;
-		if (v->channel != 0)
-			return -EINVAL;
-		strcpy(v->name,"Camera");
-		break;
-	}
+	if (meye.grab_buffer[*nb].state != MEYE_BUF_UNUSED)
+		return -EBUSY;
 
-	case VIDIOCSCHAN: {
-		struct video_channel *v = arg;
-		if (v->channel != 0)
-			return -EINVAL;
-		break;
-	}
+	mutex_lock(&meye.lock);
 
-	case VIDIOCGPICT: {
-		struct video_picture *p = arg;
-		*p = meye.picture;
-		break;
-	}
+	if (meye.mchip_mode != MCHIP_HIC_MODE_CONT_COMP)
+		mchip_cont_compression_start();
 
-	case VIDIOCSPICT: {
-		struct video_picture *p = arg;
-		if (p->depth != 16)
-			return -EINVAL;
-		if (p->palette != VIDEO_PALETTE_YUV422 && p->palette != VIDEO_PALETTE_YUYV)
-			return -EINVAL;
-		mutex_lock(&meye.lock);
-		sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERABRIGHTNESS,
-				      p->brightness >> 10);
-		sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAHUE,
-				      p->hue >> 10);
-		sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACOLOR,
-				      p->colour >> 10);
-		sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACONTRAST,
-				      p->contrast >> 10);
-		meye.picture = *p;
+	meye.grab_buffer[*nb].state = MEYE_BUF_USING;
+	kfifo_put(meye.grabq, (unsigned char *)nb, sizeof(int));
+	mutex_unlock(&meye.lock);
+
+	return 0;
+}
+
+static int meyeioc_sync(struct file *file, void *fh, int *i)
+{
+	int unused;
+
+	if (*i < 0 || *i >= gbuffers)
+		return -EINVAL;
+
+	mutex_lock(&meye.lock);
+	switch (meye.grab_buffer[*i].state) {
+
+	case MEYE_BUF_UNUSED:
 		mutex_unlock(&meye.lock);
-		break;
-	}
-
-	case VIDIOCSYNC: {
-		int *i = arg;
-		int unused;
-
-		if (*i < 0 || *i >= gbuffers)
-			return -EINVAL;
-
-		mutex_lock(&meye.lock);
-
-		switch (meye.grab_buffer[*i].state) {
-
-		case MEYE_BUF_UNUSED:
-			mutex_unlock(&meye.lock);
-			return -EINVAL;
-		case MEYE_BUF_USING:
-			if (file->f_flags & O_NONBLOCK) {
-				mutex_unlock(&meye.lock);
-				return -EAGAIN;
-			}
-			if (wait_event_interruptible(meye.proc_list,
-						     (meye.grab_buffer[*i].state != MEYE_BUF_USING))) {
-				mutex_unlock(&meye.lock);
-				return -EINTR;
-			}
-			/* fall through */
-		case MEYE_BUF_DONE:
-			meye.grab_buffer[*i].state = MEYE_BUF_UNUSED;
-			kfifo_get(meye.doneq, (unsigned char *)&unused, sizeof(int));
-		}
-		mutex_unlock(&meye.lock);
-		break;
-	}
-
-	case VIDIOCMCAPTURE: {
-		struct video_mmap *vm = arg;
-		int restart = 0;
-
-		if (vm->frame >= gbuffers || vm->frame < 0)
-			return -EINVAL;
-		if (vm->format != VIDEO_PALETTE_YUV422 && vm->format != VIDEO_PALETTE_YUYV)
-			return -EINVAL;
-		if (vm->height * vm->width * 2 > gbufsize)
-			return -EINVAL;
-		if (!meye.grab_fbuffer)
-			return -EINVAL;
-		if (meye.grab_buffer[vm->frame].state != MEYE_BUF_UNUSED)
-			return -EBUSY;
-
-		mutex_lock(&meye.lock);
-		if (vm->width == 640 && vm->height == 480) {
-			if (meye.params.subsample) {
-				meye.params.subsample = 0;
-				restart = 1;
-			}
-		} else if (vm->width == 320 && vm->height == 240) {
-			if (!meye.params.subsample) {
-				meye.params.subsample = 1;
-				restart = 1;
-			}
-		} else {
-			mutex_unlock(&meye.lock);
-			return -EINVAL;
-		}
-
-		if (restart || meye.mchip_mode != MCHIP_HIC_MODE_CONT_OUT)
-			mchip_continuous_start();
-		meye.grab_buffer[vm->frame].state = MEYE_BUF_USING;
-		kfifo_put(meye.grabq, (unsigned char *)&vm->frame, sizeof(int));
-		mutex_unlock(&meye.lock);
-		break;
-	}
-
-	case VIDIOCGMBUF: {
-		struct video_mbuf *vm = arg;
-		int i;
-
-		memset(vm, 0 , sizeof(*vm));
-		vm->size = gbufsize * gbuffers;
-		vm->frames = gbuffers;
-		for (i = 0; i < gbuffers; i++)
-			vm->offsets[i] = i * gbufsize;
-		break;
-	}
-
-	case MEYEIOC_G_PARAMS: {
-		struct meye_params *p = arg;
-		*p = meye.params;
-		break;
-	}
-
-	case MEYEIOC_S_PARAMS: {
-		struct meye_params *jp = arg;
-		if (jp->subsample > 1)
-			return -EINVAL;
-		if (jp->quality > 10)
-			return -EINVAL;
-		if (jp->sharpness > 63 || jp->agc > 63 || jp->picture > 63)
-			return -EINVAL;
-		if (jp->framerate > 31)
-			return -EINVAL;
-		mutex_lock(&meye.lock);
-		if (meye.params.subsample != jp->subsample ||
-		    meye.params.quality != jp->quality)
-			mchip_hic_stop();	/* need restart */
-		meye.params = *jp;
-		sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERASHARPNESS,
-				      meye.params.sharpness);
-		sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC,
-				      meye.params.agc);
-		sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE,
-				      meye.params.picture);
-		mutex_unlock(&meye.lock);
-		break;
-	}
-
-	case MEYEIOC_QBUF_CAPT: {
-		int *nb = arg;
-
-		if (!meye.grab_fbuffer)
-			return -EINVAL;
-		if (*nb >= gbuffers)
-			return -EINVAL;
-		if (*nb < 0) {
-			/* stop capture */
-			mchip_hic_stop();
-			return 0;
-		}
-		if (meye.grab_buffer[*nb].state != MEYE_BUF_UNUSED)
-			return -EBUSY;
-		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));
-		mutex_unlock(&meye.lock);
-		break;
-	}
-
-	case MEYEIOC_SYNC: {
-		int *i = arg;
-		int unused;
-
-		if (*i < 0 || *i >= gbuffers)
-			return -EINVAL;
-
-		mutex_lock(&meye.lock);
-		switch (meye.grab_buffer[*i].state) {
-
-		case MEYE_BUF_UNUSED:
-			mutex_unlock(&meye.lock);
-			return -EINVAL;
-		case MEYE_BUF_USING:
-			if (file->f_flags & O_NONBLOCK) {
-				mutex_unlock(&meye.lock);
-				return -EAGAIN;
-			}
-			if (wait_event_interruptible(meye.proc_list,
-						     (meye.grab_buffer[*i].state != MEYE_BUF_USING))) {
-				mutex_unlock(&meye.lock);
-				return -EINTR;
-			}
-			/* fall through */
-		case MEYE_BUF_DONE:
-			meye.grab_buffer[*i].state = MEYE_BUF_UNUSED;
-			kfifo_get(meye.doneq, (unsigned char *)&unused, sizeof(int));
-		}
-		*i = meye.grab_buffer[*i].size;
-		mutex_unlock(&meye.lock);
-		break;
-	}
-
-	case MEYEIOC_STILLCAPT: {
-
-		if (!meye.grab_fbuffer)
-			return -EINVAL;
-		if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED)
-			return -EBUSY;
-		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;
-		mutex_unlock(&meye.lock);
-		break;
-	}
-
-	case MEYEIOC_STILLJCAPT: {
-		int *len = arg;
-
-		if (!meye.grab_fbuffer)
-			return -EINVAL;
-		if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED)
-			return -EBUSY;
-		mutex_lock(&meye.lock);
-		meye.grab_buffer[0].state = MEYE_BUF_USING;
-		*len = -1;
-		while (*len == -1) {
-			mchip_take_picture();
-			*len = mchip_compress_frame(meye.grab_fbuffer, gbufsize);
-		}
-		meye.grab_buffer[0].state = MEYE_BUF_DONE;
-		mutex_unlock(&meye.lock);
-		break;
-	}
-
-	case VIDIOC_QUERYCAP: {
-		struct v4l2_capability *cap = arg;
-
-		if (forcev4l1)
-			return -EINVAL;
-
-		memset(cap, 0, sizeof(*cap));
-		strcpy(cap->driver, "meye");
-		strcpy(cap->card, "meye");
-		sprintf(cap->bus_info, "PCI:%s", pci_name(meye.mchip_dev));
-		cap->version = (MEYE_DRIVER_MAJORVERSION << 8) +
-			       MEYE_DRIVER_MINORVERSION;
-		cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
-				    V4L2_CAP_STREAMING;
-		break;
-	}
-
-	case VIDIOC_ENUMINPUT: {
-		struct v4l2_input *i = arg;
-
-		if (i->index != 0)
-			return -EINVAL;
-		memset(i, 0, sizeof(*i));
-		i->index = 0;
-		strcpy(i->name, "Camera");
-		i->type = V4L2_INPUT_TYPE_CAMERA;
-		break;
-	}
-
-	case VIDIOC_G_INPUT: {
-		int *i = arg;
-
-		*i = 0;
-		break;
-	}
-
-	case VIDIOC_S_INPUT: {
-		int *i = arg;
-
-		if (*i != 0)
-			return -EINVAL;
-		break;
-	}
-
-	case VIDIOC_QUERYCTRL: {
-		struct v4l2_queryctrl *c = arg;
-
-		switch (c->id) {
-
-		case V4L2_CID_BRIGHTNESS:
-			c->type = V4L2_CTRL_TYPE_INTEGER;
-			strcpy(c->name, "Brightness");
-			c->minimum = 0;
-			c->maximum = 63;
-			c->step = 1;
-			c->default_value = 32;
-			c->flags = 0;
-			break;
-		case V4L2_CID_HUE:
-			c->type = V4L2_CTRL_TYPE_INTEGER;
-			strcpy(c->name, "Hue");
-			c->minimum = 0;
-			c->maximum = 63;
-			c->step = 1;
-			c->default_value = 32;
-			c->flags = 0;
-			break;
-		case V4L2_CID_CONTRAST:
-			c->type = V4L2_CTRL_TYPE_INTEGER;
-			strcpy(c->name, "Contrast");
-			c->minimum = 0;
-			c->maximum = 63;
-			c->step = 1;
-			c->default_value = 32;
-			c->flags = 0;
-			break;
-		case V4L2_CID_SATURATION:
-			c->type = V4L2_CTRL_TYPE_INTEGER;
-			strcpy(c->name, "Saturation");
-			c->minimum = 0;
-			c->maximum = 63;
-			c->step = 1;
-			c->default_value = 32;
-			c->flags = 0;
-			break;
-		case V4L2_CID_AGC:
-			c->type = V4L2_CTRL_TYPE_INTEGER;
-			strcpy(c->name, "Agc");
-			c->minimum = 0;
-			c->maximum = 63;
-			c->step = 1;
-			c->default_value = 48;
-			c->flags = 0;
-			break;
-		case V4L2_CID_SHARPNESS:
-			c->type = V4L2_CTRL_TYPE_INTEGER;
-			strcpy(c->name, "Sharpness");
-			c->minimum = 0;
-			c->maximum = 63;
-			c->step = 1;
-			c->default_value = 32;
-			c->flags = 0;
-			break;
-		case V4L2_CID_PICTURE:
-			c->type = V4L2_CTRL_TYPE_INTEGER;
-			strcpy(c->name, "Picture");
-			c->minimum = 0;
-			c->maximum = 63;
-			c->step = 1;
-			c->default_value = 0;
-			c->flags = 0;
-			break;
-		case V4L2_CID_JPEGQUAL:
-			c->type = V4L2_CTRL_TYPE_INTEGER;
-			strcpy(c->name, "JPEG quality");
-			c->minimum = 0;
-			c->maximum = 10;
-			c->step = 1;
-			c->default_value = 8;
-			c->flags = 0;
-			break;
-		case V4L2_CID_FRAMERATE:
-			c->type = V4L2_CTRL_TYPE_INTEGER;
-			strcpy(c->name, "Framerate");
-			c->minimum = 0;
-			c->maximum = 31;
-			c->step = 1;
-			c->default_value = 0;
-			c->flags = 0;
-			break;
-		default:
-			return -EINVAL;
-		}
-		break;
-	}
-
-	case VIDIOC_S_CTRL: {
-		struct v4l2_control *c = arg;
-
-		mutex_lock(&meye.lock);
-		switch (c->id) {
-		case V4L2_CID_BRIGHTNESS:
-			sony_pic_camera_command(
-				SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, c->value);
-			meye.picture.brightness = c->value << 10;
-			break;
-		case V4L2_CID_HUE:
-			sony_pic_camera_command(
-				SONY_PIC_COMMAND_SETCAMERAHUE, c->value);
-			meye.picture.hue = c->value << 10;
-			break;
-		case V4L2_CID_CONTRAST:
-			sony_pic_camera_command(
-				SONY_PIC_COMMAND_SETCAMERACONTRAST, c->value);
-			meye.picture.contrast = c->value << 10;
-			break;
-		case V4L2_CID_SATURATION:
-			sony_pic_camera_command(
-				SONY_PIC_COMMAND_SETCAMERACOLOR, c->value);
-			meye.picture.colour = c->value << 10;
-			break;
-		case V4L2_CID_AGC:
-			sony_pic_camera_command(
-				SONY_PIC_COMMAND_SETCAMERAAGC, c->value);
-			meye.params.agc = c->value;
-			break;
-		case V4L2_CID_SHARPNESS:
-			sony_pic_camera_command(
-				SONY_PIC_COMMAND_SETCAMERASHARPNESS, c->value);
-			meye.params.sharpness = c->value;
-			break;
-		case V4L2_CID_PICTURE:
-			sony_pic_camera_command(
-				SONY_PIC_COMMAND_SETCAMERAPICTURE, c->value);
-			meye.params.picture = c->value;
-			break;
-		case V4L2_CID_JPEGQUAL:
-			meye.params.quality = c->value;
-			break;
-		case V4L2_CID_FRAMERATE:
-			meye.params.framerate = c->value;
-			break;
-		default:
-			mutex_unlock(&meye.lock);
-			return -EINVAL;
-		}
-		mutex_unlock(&meye.lock);
-		break;
-	}
-
-	case VIDIOC_G_CTRL: {
-		struct v4l2_control *c = arg;
-
-		mutex_lock(&meye.lock);
-		switch (c->id) {
-		case V4L2_CID_BRIGHTNESS:
-			c->value = meye.picture.brightness >> 10;
-			break;
-		case V4L2_CID_HUE:
-			c->value = meye.picture.hue >> 10;
-			break;
-		case V4L2_CID_CONTRAST:
-			c->value = meye.picture.contrast >> 10;
-			break;
-		case V4L2_CID_SATURATION:
-			c->value = meye.picture.colour >> 10;
-			break;
-		case V4L2_CID_AGC:
-			c->value = meye.params.agc;
-			break;
-		case V4L2_CID_SHARPNESS:
-			c->value = meye.params.sharpness;
-			break;
-		case V4L2_CID_PICTURE:
-			c->value = meye.params.picture;
-			break;
-		case V4L2_CID_JPEGQUAL:
-			c->value = meye.params.quality;
-			break;
-		case V4L2_CID_FRAMERATE:
-			c->value = meye.params.framerate;
-			break;
-		default:
-			mutex_unlock(&meye.lock);
-			return -EINVAL;
-		}
-		mutex_unlock(&meye.lock);
-		break;
-	}
-
-	case VIDIOC_ENUM_FMT: {
-		struct v4l2_fmtdesc *f = arg;
-
-		if (f->index > 1)
-			return -EINVAL;
-		if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-			return -EINVAL;
-		if (f->index == 0) {
-			/* standard YUV 422 capture */
-			memset(f, 0, sizeof(*f));
-			f->index = 0;
-			f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-			f->flags = 0;
-			strcpy(f->description, "YUV422");
-			f->pixelformat = V4L2_PIX_FMT_YUYV;
-		} else {
-			/* compressed MJPEG capture */
-			memset(f, 0, sizeof(*f));
-			f->index = 1;
-			f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-			f->flags = V4L2_FMT_FLAG_COMPRESSED;
-			strcpy(f->description, "MJPEG");
-			f->pixelformat = V4L2_PIX_FMT_MJPEG;
-		}
-		break;
-	}
-
-	case VIDIOC_TRY_FMT: {
-		struct v4l2_format *f = arg;
-
-		if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-			return -EINVAL;
-		if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV &&
-		    f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
-			return -EINVAL;
-		if (f->fmt.pix.field != V4L2_FIELD_ANY &&
-		    f->fmt.pix.field != V4L2_FIELD_NONE)
-			return -EINVAL;
-		f->fmt.pix.field = V4L2_FIELD_NONE;
-		if (f->fmt.pix.width <= 320) {
-			f->fmt.pix.width = 320;
-			f->fmt.pix.height = 240;
-		} else {
-			f->fmt.pix.width = 640;
-			f->fmt.pix.height = 480;
-		}
-		f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
-		f->fmt.pix.sizeimage = f->fmt.pix.height *
-				       f->fmt.pix.bytesperline;
-		f->fmt.pix.colorspace = 0;
-		f->fmt.pix.priv = 0;
-		break;
-	}
-
-	case VIDIOC_G_FMT: {
-		struct v4l2_format *f = arg;
-
-		if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-			return -EINVAL;
-		memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
-		f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		switch (meye.mchip_mode) {
-		case MCHIP_HIC_MODE_CONT_OUT:
-		default:
-			f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
-			break;
-		case MCHIP_HIC_MODE_CONT_COMP:
-			f->fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
-			break;
-		}
-		f->fmt.pix.field = V4L2_FIELD_NONE;
-		f->fmt.pix.width = mchip_hsize();
-		f->fmt.pix.height = mchip_vsize();
-		f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
-		f->fmt.pix.sizeimage = f->fmt.pix.height *
-				       f->fmt.pix.bytesperline;
-		f->fmt.pix.colorspace = 0;
-		f->fmt.pix.priv = 0;
-		break;
-	}
-
-	case VIDIOC_S_FMT: {
-		struct v4l2_format *f = arg;
-
-		if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-			return -EINVAL;
-		if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV &&
-		    f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
-			return -EINVAL;
-		if (f->fmt.pix.field != V4L2_FIELD_ANY &&
-		    f->fmt.pix.field != V4L2_FIELD_NONE)
-			return -EINVAL;
-		f->fmt.pix.field = V4L2_FIELD_NONE;
-		mutex_lock(&meye.lock);
-		if (f->fmt.pix.width <= 320) {
-			f->fmt.pix.width = 320;
-			f->fmt.pix.height = 240;
-			meye.params.subsample = 1;
-		} else {
-			f->fmt.pix.width = 640;
-			f->fmt.pix.height = 480;
-			meye.params.subsample = 0;
-		}
-		switch (f->fmt.pix.pixelformat) {
-		case V4L2_PIX_FMT_YUYV:
-			meye.mchip_mode = MCHIP_HIC_MODE_CONT_OUT;
-			break;
-		case V4L2_PIX_FMT_MJPEG:
-			meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP;
-			break;
-		}
-		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;
-		f->fmt.pix.colorspace = 0;
-		f->fmt.pix.priv = 0;
-
-		break;
-	}
-
-	case VIDIOC_REQBUFS: {
-		struct v4l2_requestbuffers *req = arg;
-		int i;
-
-		if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-			return -EINVAL;
-		if (req->memory != V4L2_MEMORY_MMAP)
-			return -EINVAL;
-		if (meye.grab_fbuffer && req->count == gbuffers) {
-			/* already allocated, no modifications */
-			break;
-		}
-		mutex_lock(&meye.lock);
-		if (meye.grab_fbuffer) {
-			for (i = 0; i < gbuffers; i++)
-				if (meye.vma_use_count[i]) {
-					mutex_unlock(&meye.lock);
-					return -EINVAL;
-				}
-			rvfree(meye.grab_fbuffer, gbuffers * gbufsize);
-			meye.grab_fbuffer = NULL;
-		}
-		gbuffers = max(2, min((int)req->count, MEYE_MAX_BUFNBRS));
-		req->count = gbuffers;
-		meye.grab_fbuffer = rvmalloc(gbuffers * gbufsize);
-		if (!meye.grab_fbuffer) {
-			printk(KERN_ERR "meye: v4l framebuffer allocation"
-					" failed\n");
-			mutex_unlock(&meye.lock);
-			return -ENOMEM;
-		}
-		for (i = 0; i < gbuffers; i++)
-			meye.vma_use_count[i] = 0;
-		mutex_unlock(&meye.lock);
-		break;
-	}
-
-	case VIDIOC_QUERYBUF: {
-		struct v4l2_buffer *buf = arg;
-		int index = buf->index;
-
-		if (index < 0 || index >= gbuffers)
-			return -EINVAL;
-		memset(buf, 0, sizeof(*buf));
-		buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		buf->index = index;
-		buf->bytesused = meye.grab_buffer[index].size;
-		buf->flags = V4L2_BUF_FLAG_MAPPED;
-		if (meye.grab_buffer[index].state == MEYE_BUF_USING)
-			buf->flags |= V4L2_BUF_FLAG_QUEUED;
-		if (meye.grab_buffer[index].state == MEYE_BUF_DONE)
-			buf->flags |= V4L2_BUF_FLAG_DONE;
-		buf->field = V4L2_FIELD_NONE;
-		buf->timestamp = meye.grab_buffer[index].timestamp;
-		buf->sequence = meye.grab_buffer[index].sequence;
-		buf->memory = V4L2_MEMORY_MMAP;
-		buf->m.offset = index * gbufsize;
-		buf->length = gbufsize;
-		break;
-	}
-
-	case VIDIOC_QBUF: {
-		struct v4l2_buffer *buf = arg;
-
-		if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-			return -EINVAL;
-		if (buf->memory != V4L2_MEMORY_MMAP)
-			return -EINVAL;
-		if (buf->index < 0 || buf->index >= gbuffers)
-			return -EINVAL;
-		if (meye.grab_buffer[buf->index].state != MEYE_BUF_UNUSED)
-			return -EINVAL;
-		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));
-		mutex_unlock(&meye.lock);
-		break;
-	}
-
-	case VIDIOC_DQBUF: {
-		struct v4l2_buffer *buf = arg;
-		int reqnr;
-
-		if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-			return -EINVAL;
-		if (buf->memory != V4L2_MEMORY_MMAP)
-			return -EINVAL;
-
-		mutex_lock(&meye.lock);
-		if (kfifo_len(meye.doneq) == 0 && file->f_flags & O_NONBLOCK) {
+		return -EINVAL;
+	case MEYE_BUF_USING:
+		if (file->f_flags & O_NONBLOCK) {
 			mutex_unlock(&meye.lock);
 			return -EAGAIN;
 		}
 		if (wait_event_interruptible(meye.proc_list,
-					     kfifo_len(meye.doneq) != 0) < 0) {
+			(meye.grab_buffer[*i].state != MEYE_BUF_USING))) {
 			mutex_unlock(&meye.lock);
 			return -EINTR;
 		}
-		if (!kfifo_get(meye.doneq, (unsigned char *)&reqnr,
-			       sizeof(int))) {
-			mutex_unlock(&meye.lock);
-			return -EBUSY;
-		}
-		if (meye.grab_buffer[reqnr].state != MEYE_BUF_DONE) {
-			mutex_unlock(&meye.lock);
-			return -EINVAL;
-		}
-		buf->index = reqnr;
-		buf->bytesused = meye.grab_buffer[reqnr].size;
-		buf->flags = V4L2_BUF_FLAG_MAPPED;
-		buf->field = V4L2_FIELD_NONE;
-		buf->timestamp = meye.grab_buffer[reqnr].timestamp;
-		buf->sequence = meye.grab_buffer[reqnr].sequence;
-		buf->memory = V4L2_MEMORY_MMAP;
-		buf->m.offset = reqnr * gbufsize;
-		buf->length = gbufsize;
-		meye.grab_buffer[reqnr].state = MEYE_BUF_UNUSED;
-		mutex_unlock(&meye.lock);
-		break;
+		/* fall through */
+	case MEYE_BUF_DONE:
+		meye.grab_buffer[*i].state = MEYE_BUF_UNUSED;
+		kfifo_get(meye.doneq, (unsigned char *)&unused, sizeof(int));
+	}
+	*i = meye.grab_buffer[*i].size;
+	mutex_unlock(&meye.lock);
+	return 0;
+}
+
+static int meyeioc_stillcapt(void)
+{
+	if (!meye.grab_fbuffer)
+		return -EINVAL;
+
+	if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED)
+		return -EBUSY;
+
+	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;
+	mutex_unlock(&meye.lock);
+
+	return 0;
+}
+
+static int meyeioc_stilljcapt(int *len)
+{
+	if (!meye.grab_fbuffer)
+		return -EINVAL;
+
+	if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED)
+		return -EBUSY;
+
+	mutex_lock(&meye.lock);
+	meye.grab_buffer[0].state = MEYE_BUF_USING;
+	*len = -1;
+
+	while (*len == -1) {
+		mchip_take_picture();
+		*len = mchip_compress_frame(meye.grab_fbuffer, gbufsize);
 	}
 
-	case VIDIOC_STREAMON: {
-		mutex_lock(&meye.lock);
-		switch (meye.mchip_mode) {
-		case MCHIP_HIC_MODE_CONT_OUT:
-			mchip_continuous_start();
-			break;
-		case MCHIP_HIC_MODE_CONT_COMP:
-			mchip_cont_compression_start();
-			break;
-		default:
-			mutex_unlock(&meye.lock);
-			return -EINVAL;
-		}
-		mutex_unlock(&meye.lock);
+	meye.grab_buffer[0].state = MEYE_BUF_DONE;
+	mutex_unlock(&meye.lock);
+	return 0;
+}
+
+static int vidioc_querycap(struct file *file, void *fh,
+				struct v4l2_capability *cap)
+{
+	memset(cap, 0, sizeof(*cap));
+	strcpy(cap->driver, "meye");
+	strcpy(cap->card, "meye");
+	sprintf(cap->bus_info, "PCI:%s", pci_name(meye.mchip_dev));
+
+	cap->version = (MEYE_DRIVER_MAJORVERSION << 8) +
+		       MEYE_DRIVER_MINORVERSION;
+
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+			    V4L2_CAP_STREAMING;
+
+	return 0;
+}
+
+static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
+{
+	if (i->index != 0)
+		return -EINVAL;
+
+	memset(i, 0, sizeof(*i));
+	i->index = 0;
+	strcpy(i->name, "Camera");
+	i->type = V4L2_INPUT_TYPE_CAMERA;
+
+	return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
+{
+	if (i != 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int vidioc_queryctrl(struct file *file, void *fh,
+				struct v4l2_queryctrl *c)
+{
+	switch (c->id) {
+
+	case V4L2_CID_BRIGHTNESS:
+		c->type = V4L2_CTRL_TYPE_INTEGER;
+		strcpy(c->name, "Brightness");
+		c->minimum = 0;
+		c->maximum = 63;
+		c->step = 1;
+		c->default_value = 32;
+		c->flags = 0;
 		break;
-	}
-
-	case VIDIOC_STREAMOFF: {
-		int i;
-
-		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;
-		mutex_unlock(&meye.lock);
+	case V4L2_CID_HUE:
+		c->type = V4L2_CTRL_TYPE_INTEGER;
+		strcpy(c->name, "Hue");
+		c->minimum = 0;
+		c->maximum = 63;
+		c->step = 1;
+		c->default_value = 32;
+		c->flags = 0;
 		break;
-	}
+	case V4L2_CID_CONTRAST:
+		c->type = V4L2_CTRL_TYPE_INTEGER;
+		strcpy(c->name, "Contrast");
+		c->minimum = 0;
+		c->maximum = 63;
+		c->step = 1;
+		c->default_value = 32;
+		c->flags = 0;
+		break;
+	case V4L2_CID_SATURATION:
+		c->type = V4L2_CTRL_TYPE_INTEGER;
+		strcpy(c->name, "Saturation");
+		c->minimum = 0;
+		c->maximum = 63;
+		c->step = 1;
+		c->default_value = 32;
+		c->flags = 0;
+		break;
+	case V4L2_CID_AGC:
+		c->type = V4L2_CTRL_TYPE_INTEGER;
+		strcpy(c->name, "Agc");
+		c->minimum = 0;
+		c->maximum = 63;
+		c->step = 1;
+		c->default_value = 48;
+		c->flags = 0;
+		break;
+	case V4L2_CID_MEYE_SHARPNESS:
+	case V4L2_CID_SHARPNESS:
+		c->type = V4L2_CTRL_TYPE_INTEGER;
+		strcpy(c->name, "Sharpness");
+		c->minimum = 0;
+		c->maximum = 63;
+		c->step = 1;
+		c->default_value = 32;
 
-	/*
-	 * XXX what about private snapshot ioctls ?
-	 * Do they need to be converted to V4L2 ?
-	*/
-
+		/* Continue to report legacy private SHARPNESS ctrl but
+		 * say it is disabled in preference to ctrl in the spec
+		 */
+		c->flags = (c->id == V4L2_CID_SHARPNESS) ? 0 :
+						V4L2_CTRL_FLAG_DISABLED;
+		break;
+	case V4L2_CID_PICTURE:
+		c->type = V4L2_CTRL_TYPE_INTEGER;
+		strcpy(c->name, "Picture");
+		c->minimum = 0;
+		c->maximum = 63;
+		c->step = 1;
+		c->default_value = 0;
+		c->flags = 0;
+		break;
+	case V4L2_CID_JPEGQUAL:
+		c->type = V4L2_CTRL_TYPE_INTEGER;
+		strcpy(c->name, "JPEG quality");
+		c->minimum = 0;
+		c->maximum = 10;
+		c->step = 1;
+		c->default_value = 8;
+		c->flags = 0;
+		break;
+	case V4L2_CID_FRAMERATE:
+		c->type = V4L2_CTRL_TYPE_INTEGER;
+		strcpy(c->name, "Framerate");
+		c->minimum = 0;
+		c->maximum = 31;
+		c->step = 1;
+		c->default_value = 0;
+		c->flags = 0;
+		break;
 	default:
-		return -ENOIOCTLCMD;
+		return -EINVAL;
 	}
 
 	return 0;
 }
 
-static int meye_ioctl(struct inode *inode, struct file *file,
-		     unsigned int cmd, unsigned long arg)
+static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
 {
-	return video_usercopy(inode, file, cmd, arg, meye_do_ioctl);
+	mutex_lock(&meye.lock);
+	switch (c->id) {
+	case V4L2_CID_BRIGHTNESS:
+		sony_pic_camera_command(
+			SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, c->value);
+		meye.picture.brightness = c->value << 10;
+		break;
+	case V4L2_CID_HUE:
+		sony_pic_camera_command(
+			SONY_PIC_COMMAND_SETCAMERAHUE, c->value);
+		meye.picture.hue = c->value << 10;
+		break;
+	case V4L2_CID_CONTRAST:
+		sony_pic_camera_command(
+			SONY_PIC_COMMAND_SETCAMERACONTRAST, c->value);
+		meye.picture.contrast = c->value << 10;
+		break;
+	case V4L2_CID_SATURATION:
+		sony_pic_camera_command(
+			SONY_PIC_COMMAND_SETCAMERACOLOR, c->value);
+		meye.picture.colour = c->value << 10;
+		break;
+	case V4L2_CID_AGC:
+		sony_pic_camera_command(
+			SONY_PIC_COMMAND_SETCAMERAAGC, c->value);
+		meye.params.agc = c->value;
+		break;
+	case V4L2_CID_SHARPNESS:
+	case V4L2_CID_MEYE_SHARPNESS:
+		sony_pic_camera_command(
+			SONY_PIC_COMMAND_SETCAMERASHARPNESS, c->value);
+		meye.params.sharpness = c->value;
+		break;
+	case V4L2_CID_PICTURE:
+		sony_pic_camera_command(
+			SONY_PIC_COMMAND_SETCAMERAPICTURE, c->value);
+		meye.params.picture = c->value;
+		break;
+	case V4L2_CID_JPEGQUAL:
+		meye.params.quality = c->value;
+		break;
+	case V4L2_CID_FRAMERATE:
+		meye.params.framerate = c->value;
+		break;
+	default:
+		mutex_unlock(&meye.lock);
+		return -EINVAL;
+	}
+	mutex_unlock(&meye.lock);
+
+	return 0;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c)
+{
+	mutex_lock(&meye.lock);
+	switch (c->id) {
+	case V4L2_CID_BRIGHTNESS:
+		c->value = meye.picture.brightness >> 10;
+		break;
+	case V4L2_CID_HUE:
+		c->value = meye.picture.hue >> 10;
+		break;
+	case V4L2_CID_CONTRAST:
+		c->value = meye.picture.contrast >> 10;
+		break;
+	case V4L2_CID_SATURATION:
+		c->value = meye.picture.colour >> 10;
+		break;
+	case V4L2_CID_AGC:
+		c->value = meye.params.agc;
+		break;
+	case V4L2_CID_SHARPNESS:
+	case V4L2_CID_MEYE_SHARPNESS:
+		c->value = meye.params.sharpness;
+		break;
+	case V4L2_CID_PICTURE:
+		c->value = meye.params.picture;
+		break;
+	case V4L2_CID_JPEGQUAL:
+		c->value = meye.params.quality;
+		break;
+	case V4L2_CID_FRAMERATE:
+		c->value = meye.params.framerate;
+		break;
+	default:
+		mutex_unlock(&meye.lock);
+		return -EINVAL;
+	}
+	mutex_unlock(&meye.lock);
+
+	return 0;
+}
+
+static int vidioc_enum_fmt_cap(struct file *file, void *fh,
+				struct v4l2_fmtdesc *f)
+{
+	if (f->index > 1)
+		return -EINVAL;
+
+	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (f->index == 0) {
+		/* standard YUV 422 capture */
+		memset(f, 0, sizeof(*f));
+		f->index = 0;
+		f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		f->flags = 0;
+		strcpy(f->description, "YUV422");
+		f->pixelformat = V4L2_PIX_FMT_YUYV;
+	} else {
+		/* compressed MJPEG capture */
+		memset(f, 0, sizeof(*f));
+		f->index = 1;
+		f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		f->flags = V4L2_FMT_FLAG_COMPRESSED;
+		strcpy(f->description, "MJPEG");
+		f->pixelformat = V4L2_PIX_FMT_MJPEG;
+	}
+
+	return 0;
+}
+
+static int vidioc_try_fmt_cap(struct file *file, void *fh,
+				struct v4l2_format *f)
+{
+	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV &&
+	    f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
+		return -EINVAL;
+
+	if (f->fmt.pix.field != V4L2_FIELD_ANY &&
+	    f->fmt.pix.field != V4L2_FIELD_NONE)
+		return -EINVAL;
+
+	f->fmt.pix.field = V4L2_FIELD_NONE;
+
+	if (f->fmt.pix.width <= 320) {
+		f->fmt.pix.width = 320;
+		f->fmt.pix.height = 240;
+	} else {
+		f->fmt.pix.width = 640;
+		f->fmt.pix.height = 480;
+	}
+
+	f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
+	f->fmt.pix.sizeimage = f->fmt.pix.height *
+			       f->fmt.pix.bytesperline;
+	f->fmt.pix.colorspace = 0;
+	f->fmt.pix.priv = 0;
+
+	return 0;
+}
+
+static int vidioc_g_fmt_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
+	f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	switch (meye.mchip_mode) {
+	case MCHIP_HIC_MODE_CONT_OUT:
+	default:
+		f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+		break;
+	case MCHIP_HIC_MODE_CONT_COMP:
+		f->fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
+		break;
+	}
+
+	f->fmt.pix.field = V4L2_FIELD_NONE;
+	f->fmt.pix.width = mchip_hsize();
+	f->fmt.pix.height = mchip_vsize();
+	f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
+	f->fmt.pix.sizeimage = f->fmt.pix.height *
+			       f->fmt.pix.bytesperline;
+	f->fmt.pix.colorspace = 0;
+	f->fmt.pix.priv = 0;
+
+	return 0;
+}
+
+static int vidioc_s_fmt_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV &&
+	    f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
+		return -EINVAL;
+
+	if (f->fmt.pix.field != V4L2_FIELD_ANY &&
+	    f->fmt.pix.field != V4L2_FIELD_NONE)
+		return -EINVAL;
+
+	f->fmt.pix.field = V4L2_FIELD_NONE;
+	mutex_lock(&meye.lock);
+
+	if (f->fmt.pix.width <= 320) {
+		f->fmt.pix.width = 320;
+		f->fmt.pix.height = 240;
+		meye.params.subsample = 1;
+	} else {
+		f->fmt.pix.width = 640;
+		f->fmt.pix.height = 480;
+		meye.params.subsample = 0;
+	}
+
+	switch (f->fmt.pix.pixelformat) {
+	case V4L2_PIX_FMT_YUYV:
+		meye.mchip_mode = MCHIP_HIC_MODE_CONT_OUT;
+		break;
+	case V4L2_PIX_FMT_MJPEG:
+		meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP;
+		break;
+	}
+
+	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;
+	f->fmt.pix.colorspace = 0;
+	f->fmt.pix.priv = 0;
+
+	return 0;
+}
+
+static int vidioc_reqbufs(struct file *file, void *fh,
+				struct v4l2_requestbuffers *req)
+{
+	int i;
+
+	if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (req->memory != V4L2_MEMORY_MMAP)
+		return -EINVAL;
+
+	if (meye.grab_fbuffer && req->count == gbuffers) {
+		/* already allocated, no modifications */
+		return 0;
+	}
+
+	mutex_lock(&meye.lock);
+	if (meye.grab_fbuffer) {
+		for (i = 0; i < gbuffers; i++)
+			if (meye.vma_use_count[i]) {
+				mutex_unlock(&meye.lock);
+				return -EINVAL;
+			}
+		rvfree(meye.grab_fbuffer, gbuffers * gbufsize);
+		meye.grab_fbuffer = NULL;
+	}
+
+	gbuffers = max(2, min((int)req->count, MEYE_MAX_BUFNBRS));
+	req->count = gbuffers;
+	meye.grab_fbuffer = rvmalloc(gbuffers * gbufsize);
+
+	if (!meye.grab_fbuffer) {
+		printk(KERN_ERR "meye: v4l framebuffer allocation"
+				" failed\n");
+		mutex_unlock(&meye.lock);
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < gbuffers; i++)
+		meye.vma_use_count[i] = 0;
+
+	mutex_unlock(&meye.lock);
+
+	return 0;
+}
+
+static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+{
+	int index = buf->index;
+
+	if (index < 0 || index >= gbuffers)
+		return -EINVAL;
+
+	memset(buf, 0, sizeof(*buf));
+
+	buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	buf->index = index;
+	buf->bytesused = meye.grab_buffer[index].size;
+	buf->flags = V4L2_BUF_FLAG_MAPPED;
+
+	if (meye.grab_buffer[index].state == MEYE_BUF_USING)
+		buf->flags |= V4L2_BUF_FLAG_QUEUED;
+
+	if (meye.grab_buffer[index].state == MEYE_BUF_DONE)
+		buf->flags |= V4L2_BUF_FLAG_DONE;
+
+	buf->field = V4L2_FIELD_NONE;
+	buf->timestamp = meye.grab_buffer[index].timestamp;
+	buf->sequence = meye.grab_buffer[index].sequence;
+	buf->memory = V4L2_MEMORY_MMAP;
+	buf->m.offset = index * gbufsize;
+	buf->length = gbufsize;
+
+	return 0;
+}
+
+static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+{
+	if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (buf->memory != V4L2_MEMORY_MMAP)
+		return -EINVAL;
+
+	if (buf->index < 0 || buf->index >= gbuffers)
+		return -EINVAL;
+
+	if (meye.grab_buffer[buf->index].state != MEYE_BUF_UNUSED)
+		return -EINVAL;
+
+	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));
+	mutex_unlock(&meye.lock);
+
+	return 0;
+}
+
+static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+{
+	int reqnr;
+
+	if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (buf->memory != V4L2_MEMORY_MMAP)
+		return -EINVAL;
+
+	mutex_lock(&meye.lock);
+
+	if (kfifo_len(meye.doneq) == 0 && file->f_flags & O_NONBLOCK) {
+		mutex_unlock(&meye.lock);
+		return -EAGAIN;
+	}
+
+	if (wait_event_interruptible(meye.proc_list,
+				     kfifo_len(meye.doneq) != 0) < 0) {
+		mutex_unlock(&meye.lock);
+		return -EINTR;
+	}
+
+	if (!kfifo_get(meye.doneq, (unsigned char *)&reqnr,
+		       sizeof(int))) {
+		mutex_unlock(&meye.lock);
+		return -EBUSY;
+	}
+
+	if (meye.grab_buffer[reqnr].state != MEYE_BUF_DONE) {
+		mutex_unlock(&meye.lock);
+		return -EINVAL;
+	}
+
+	buf->index = reqnr;
+	buf->bytesused = meye.grab_buffer[reqnr].size;
+	buf->flags = V4L2_BUF_FLAG_MAPPED;
+	buf->field = V4L2_FIELD_NONE;
+	buf->timestamp = meye.grab_buffer[reqnr].timestamp;
+	buf->sequence = meye.grab_buffer[reqnr].sequence;
+	buf->memory = V4L2_MEMORY_MMAP;
+	buf->m.offset = reqnr * gbufsize;
+	buf->length = gbufsize;
+	meye.grab_buffer[reqnr].state = MEYE_BUF_UNUSED;
+	mutex_unlock(&meye.lock);
+
+	return 0;
+}
+
+static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+	mutex_lock(&meye.lock);
+
+	switch (meye.mchip_mode) {
+	case MCHIP_HIC_MODE_CONT_OUT:
+		mchip_continuous_start();
+		break;
+	case MCHIP_HIC_MODE_CONT_COMP:
+		mchip_cont_compression_start();
+		break;
+	default:
+		mutex_unlock(&meye.lock);
+		return -EINVAL;
+	}
+
+	mutex_unlock(&meye.lock);
+
+	return 0;
+}
+
+static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+	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;
+
+	mutex_unlock(&meye.lock);
+	return 0;
+}
+
+static int vidioc_default(struct file *file, void *fh, int cmd, void *arg)
+{
+	switch (cmd) {
+	case MEYEIOC_G_PARAMS:
+		return meyeioc_g_params((struct meye_params *) arg);
+
+	case MEYEIOC_S_PARAMS:
+		return meyeioc_s_params((struct meye_params *) arg);
+
+	case MEYEIOC_QBUF_CAPT:
+		return meyeioc_qbuf_capt((int *) arg);
+
+	case MEYEIOC_SYNC:
+		return meyeioc_sync(file, fh, (int *) arg);
+
+	case MEYEIOC_STILLCAPT:
+		return meyeioc_stillcapt();
+
+	case MEYEIOC_STILLJCAPT:
+		return meyeioc_stilljcapt((int *) arg);
+
+	default:
+		return -EINVAL;
+	}
+
 }
 
 static unsigned int meye_poll(struct file *file, poll_table *wait)
@@ -1752,8 +1687,10 @@
 	.open		= meye_open,
 	.release	= meye_release,
 	.mmap		= meye_mmap,
-	.ioctl		= meye_ioctl,
+	.ioctl		= video_ioctl2,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
+#endif
 	.poll		= meye_poll,
 	.llseek		= no_llseek,
 };
@@ -1765,6 +1702,24 @@
 	.fops		= &meye_fops,
 	.release	= video_device_release,
 	.minor		= -1,
+	.vidioc_querycap	= vidioc_querycap,
+	.vidioc_enum_input	= vidioc_enum_input,
+	.vidioc_g_input		= vidioc_g_input,
+	.vidioc_s_input		= vidioc_s_input,
+	.vidioc_queryctrl	= vidioc_queryctrl,
+	.vidioc_s_ctrl		= vidioc_s_ctrl,
+	.vidioc_g_ctrl		= vidioc_g_ctrl,
+	.vidioc_enum_fmt_cap	= vidioc_enum_fmt_cap,
+	.vidioc_try_fmt_cap	= vidioc_try_fmt_cap,
+	.vidioc_g_fmt_cap	= vidioc_g_fmt_cap,
+	.vidioc_s_fmt_cap	= vidioc_s_fmt_cap,
+	.vidioc_reqbufs		= vidioc_reqbufs,
+	.vidioc_querybuf	= vidioc_querybuf,
+	.vidioc_qbuf		= vidioc_qbuf,
+	.vidioc_dqbuf		= vidioc_dqbuf,
+	.vidioc_streamon	= vidioc_streamon,
+	.vidioc_streamoff	= vidioc_streamoff,
+	.vidioc_default		= vidioc_default,
 };
 
 #ifdef CONFIG_PM
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
index 7a11f31..b73c740 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/video/msp3400-driver.c
@@ -366,7 +366,7 @@
 }
 
 /* ------------------------------------------------------------------------ */
-#ifdef CONFIG_VIDEO_V4L1
+#ifdef CONFIG_VIDEO_ALLOW_V4L1
 static int msp_mode_v4l2_to_v4l1(int rxsubchans, int audmode)
 {
 	if (rxsubchans == V4L2_TUNER_SUB_MONO)
@@ -514,7 +514,7 @@
 	/* --- v4l ioctls --- */
 	/* take care: bttv does userspace copying, we'll get a
 	   kernel pointer here... */
-#ifdef CONFIG_VIDEO_V4L1
+#ifdef CONFIG_VIDEO_ALLOW_V4L1
 	case VIDIOCGAUDIO:
 	{
 		struct video_audio *va = arg;
diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c
index 61ec794..7f55685 100644
--- a/drivers/media/video/msp3400-kthreads.c
+++ b/drivers/media/video/msp3400-kthreads.c
@@ -833,11 +833,6 @@
 		v4l_dbg(1, msp_debug, client, "selected radio modus\n");
 		return 0x0001;
 	}
-
-	if (state->v4l2_std & V4L2_STD_PAL) {
-		v4l_dbg(1, msp_debug, client, "selected PAL modus\n");
-		return 0x7001;
-	}
 	if (state->v4l2_std == V4L2_STD_NTSC_M_JP) {
 		v4l_dbg(1, msp_debug, client, "selected M (EIA-J) modus\n");
 		return 0x4001;
@@ -846,15 +841,15 @@
 		v4l_dbg(1, msp_debug, client, "selected M (A2) modus\n");
 		return 0x0001;
 	}
+	if (state->v4l2_std == V4L2_STD_SECAM_L) {
+		v4l_dbg(1, msp_debug, client, "selected SECAM-L modus\n");
+		return 0x6001;
+	}
 	if (state->v4l2_std & V4L2_STD_MN) {
 		v4l_dbg(1, msp_debug, client, "selected M (BTSC) modus\n");
 		return 0x2001;
 	}
-	if (state->v4l2_std & V4L2_STD_SECAM) {
-		v4l_dbg(1, msp_debug, client, "selected SECAM modus\n");
-		return 0x6001;
-	}
-	return 0x0001;
+	return 0x7001;
 }
 
 static void msp34xxg_set_source(struct i2c_client *client, u16 reg, int in)
diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c
index 74fd6a0..fbcb282 100644
--- a/drivers/media/video/mt20xx.c
+++ b/drivers/media/video/mt20xx.c
@@ -10,12 +10,10 @@
 #include "tuner-i2c.h"
 #include "mt20xx.h"
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
-#define PREFIX "mt20xx"
-
 /* ---------------------------------------------------------------------- */
 
 static unsigned int optimize_vco  = 1;
@@ -24,7 +22,7 @@
 static unsigned int tv_antenna    = 1;
 module_param(tv_antenna,        int, 0644);
 
-static unsigned int radio_antenna = 0;
+static unsigned int radio_antenna;
 module_param(radio_antenna,     int, 0644);
 
 /* ---------------------------------------------------------------------- */
@@ -611,6 +609,7 @@
 
 	priv->i2c_props.addr = i2c_addr;
 	priv->i2c_props.adap = i2c_adap;
+	priv->i2c_props.name = "mt20xx";
 
 	//priv->radio_if2 = 10700 * 1000;	/* 10.7MHz - FM radio */
 
diff --git a/drivers/media/video/mt20xx.h b/drivers/media/video/mt20xx.h
index 5e9c825..aa848e1 100644
--- a/drivers/media/video/mt20xx.h
+++ b/drivers/media/video/mt20xx.h
@@ -29,7 +29,7 @@
 					     struct i2c_adapter* i2c_adap,
 					     u8 i2c_addr)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif
diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
new file mode 100644
index 0000000..3fb5f63
--- /dev/null
+++ b/drivers/media/video/mt9m001.c
@@ -0,0 +1,722 @@
+/*
+ * Driver for MT9M001 CMOS Image Sensor from Micron
+ *
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/log2.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/soc_camera.h>
+
+#ifdef CONFIG_MT9M001_PCA9536_SWITCH
+#include <asm/gpio.h>
+#endif
+
+/* mt9m001 i2c address 0x5d
+ * The platform has to define i2c_board_info
+ * and call i2c_register_board_info() */
+
+/* mt9m001 selected register addresses */
+#define MT9M001_CHIP_VERSION		0x00
+#define MT9M001_ROW_START		0x01
+#define MT9M001_COLUMN_START		0x02
+#define MT9M001_WINDOW_HEIGHT		0x03
+#define MT9M001_WINDOW_WIDTH		0x04
+#define MT9M001_HORIZONTAL_BLANKING	0x05
+#define MT9M001_VERTICAL_BLANKING	0x06
+#define MT9M001_OUTPUT_CONTROL		0x07
+#define MT9M001_SHUTTER_WIDTH		0x09
+#define MT9M001_FRAME_RESTART		0x0b
+#define MT9M001_SHUTTER_DELAY		0x0c
+#define MT9M001_RESET			0x0d
+#define MT9M001_READ_OPTIONS1		0x1e
+#define MT9M001_READ_OPTIONS2		0x20
+#define MT9M001_GLOBAL_GAIN		0x35
+#define MT9M001_CHIP_ENABLE		0xF1
+
+static const struct soc_camera_data_format mt9m001_colour_formats[] = {
+	/* Order important: first natively supported,
+	 * second supported with a GPIO extender */
+	{
+		.name		= "Bayer (sRGB) 10 bit",
+		.depth		= 10,
+		.fourcc		= V4L2_PIX_FMT_SBGGR16,
+		.colorspace	= V4L2_COLORSPACE_SRGB,
+	}, {
+		.name		= "Bayer (sRGB) 8 bit",
+		.depth		= 8,
+		.fourcc		= V4L2_PIX_FMT_SBGGR8,
+		.colorspace	= V4L2_COLORSPACE_SRGB,
+	}
+};
+
+static const struct soc_camera_data_format mt9m001_monochrome_formats[] = {
+	/* Order important - see above */
+	{
+		.name		= "Monochrome 10 bit",
+		.depth		= 10,
+		.fourcc		= V4L2_PIX_FMT_Y16,
+	}, {
+		.name		= "Monochrome 8 bit",
+		.depth		= 8,
+		.fourcc		= V4L2_PIX_FMT_GREY,
+	},
+};
+
+struct mt9m001 {
+	struct i2c_client *client;
+	struct soc_camera_device icd;
+	int model;	/* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */
+	int switch_gpio;
+	unsigned char autoexposure;
+	unsigned char datawidth;
+};
+
+static int reg_read(struct soc_camera_device *icd, const u8 reg)
+{
+	struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+	struct i2c_client *client = mt9m001->client;
+	s32 data = i2c_smbus_read_word_data(client, reg);
+	return data < 0 ? data : swab16(data);
+}
+
+static int reg_write(struct soc_camera_device *icd, const u8 reg,
+		     const u16 data)
+{
+	struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+	return i2c_smbus_write_word_data(mt9m001->client, reg, swab16(data));
+}
+
+static int reg_set(struct soc_camera_device *icd, const u8 reg,
+		   const u16 data)
+{
+	int ret;
+
+	ret = reg_read(icd, reg);
+	if (ret < 0)
+		return ret;
+	return reg_write(icd, reg, ret | data);
+}
+
+static int reg_clear(struct soc_camera_device *icd, const u8 reg,
+		     const u16 data)
+{
+	int ret;
+
+	ret = reg_read(icd, reg);
+	if (ret < 0)
+		return ret;
+	return reg_write(icd, reg, ret & ~data);
+}
+
+static int mt9m001_init(struct soc_camera_device *icd)
+{
+	int ret;
+
+	/* Disable chip, synchronous option update */
+	dev_dbg(icd->vdev->dev, "%s\n", __func__);
+
+	ret = reg_write(icd, MT9M001_RESET, 1);
+	if (ret >= 0)
+		ret = reg_write(icd, MT9M001_RESET, 0);
+	if (ret >= 0)
+		ret = reg_write(icd, MT9M001_OUTPUT_CONTROL, 0);
+
+	return ret >= 0 ? 0 : -EIO;
+}
+
+static int mt9m001_release(struct soc_camera_device *icd)
+{
+	/* Disable the chip */
+	reg_write(icd, MT9M001_OUTPUT_CONTROL, 0);
+	return 0;
+}
+
+static int mt9m001_start_capture(struct soc_camera_device *icd)
+{
+	/* Switch to master "normal" mode */
+	if (reg_write(icd, MT9M001_OUTPUT_CONTROL, 2) < 0)
+		return -EIO;
+	return 0;
+}
+
+static int mt9m001_stop_capture(struct soc_camera_device *icd)
+{
+	/* Stop sensor readout */
+	if (reg_write(icd, MT9M001_OUTPUT_CONTROL, 0) < 0)
+		return -EIO;
+	return 0;
+}
+
+static int bus_switch_request(struct mt9m001 *mt9m001,
+			      struct soc_camera_link *icl)
+{
+#ifdef CONFIG_MT9M001_PCA9536_SWITCH
+	int ret;
+	unsigned int gpio = icl->gpio;
+
+	if (gpio_is_valid(gpio)) {
+		/* We have a data bus switch. */
+		ret = gpio_request(gpio, "mt9m001");
+		if (ret < 0) {
+			dev_err(&mt9m001->client->dev, "Cannot get GPIO %u\n",
+				gpio);
+			return ret;
+		}
+
+		ret = gpio_direction_output(gpio, 0);
+		if (ret < 0) {
+			dev_err(&mt9m001->client->dev,
+				"Cannot set GPIO %u to output\n", gpio);
+			gpio_free(gpio);
+			return ret;
+		}
+	}
+
+	mt9m001->switch_gpio = gpio;
+#else
+	mt9m001->switch_gpio = -EINVAL;
+#endif
+	return 0;
+}
+
+static void bus_switch_release(struct mt9m001 *mt9m001)
+{
+#ifdef CONFIG_MT9M001_PCA9536_SWITCH
+	if (gpio_is_valid(mt9m001->switch_gpio))
+		gpio_free(mt9m001->switch_gpio);
+#endif
+}
+
+static int bus_switch_act(struct mt9m001 *mt9m001, int go8bit)
+{
+#ifdef CONFIG_MT9M001_PCA9536_SWITCH
+	if (!gpio_is_valid(mt9m001->switch_gpio))
+		return -ENODEV;
+
+	gpio_set_value_cansleep(mt9m001->switch_gpio, go8bit);
+	return 0;
+#else
+	return -ENODEV;
+#endif
+}
+
+static int bus_switch_possible(struct mt9m001 *mt9m001)
+{
+#ifdef CONFIG_MT9M001_PCA9536_SWITCH
+	return gpio_is_valid(mt9m001->switch_gpio);
+#else
+	return 0;
+#endif
+}
+
+static int mt9m001_set_bus_param(struct soc_camera_device *icd,
+				 unsigned long flags)
+{
+	struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+	unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK;
+	int ret;
+
+	/* Flags validity verified in test_bus_param */
+
+	if ((mt9m001->datawidth != 10 && (width_flag == SOCAM_DATAWIDTH_10)) ||
+	    (mt9m001->datawidth != 9  && (width_flag == SOCAM_DATAWIDTH_9)) ||
+	    (mt9m001->datawidth != 8  && (width_flag == SOCAM_DATAWIDTH_8))) {
+		/* Well, we actually only can do 10 or 8 bits... */
+		if (width_flag == SOCAM_DATAWIDTH_9)
+			return -EINVAL;
+		ret = bus_switch_act(mt9m001,
+				     width_flag == SOCAM_DATAWIDTH_8);
+		if (ret < 0)
+			return ret;
+
+		mt9m001->datawidth = width_flag == SOCAM_DATAWIDTH_8 ? 8 : 10;
+	}
+
+	return 0;
+}
+
+static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
+{
+	struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+	unsigned int width_flag = SOCAM_DATAWIDTH_10;
+
+	if (bus_switch_possible(mt9m001))
+		width_flag |= SOCAM_DATAWIDTH_8;
+
+	/* MT9M001 has all capture_format parameters fixed */
+	return SOCAM_PCLK_SAMPLE_RISING |
+		SOCAM_HSYNC_ACTIVE_HIGH |
+		SOCAM_VSYNC_ACTIVE_HIGH |
+		SOCAM_MASTER |
+		width_flag;
+}
+
+static int mt9m001_set_fmt_cap(struct soc_camera_device *icd,
+		__u32 pixfmt, struct v4l2_rect *rect)
+{
+	struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+	int ret;
+	const u16 hblank = 9, vblank = 25;
+
+	/* Blanking and start values - default... */
+	ret = reg_write(icd, MT9M001_HORIZONTAL_BLANKING, hblank);
+	if (ret >= 0)
+		ret = reg_write(icd, MT9M001_VERTICAL_BLANKING, vblank);
+
+	/* The caller provides a supported format, as verified per
+	 * call to icd->try_fmt_cap() */
+	if (ret >= 0)
+		ret = reg_write(icd, MT9M001_COLUMN_START, rect->left);
+	if (ret >= 0)
+		ret = reg_write(icd, MT9M001_ROW_START, rect->top);
+	if (ret >= 0)
+		ret = reg_write(icd, MT9M001_WINDOW_WIDTH, rect->width - 1);
+	if (ret >= 0)
+		ret = reg_write(icd, MT9M001_WINDOW_HEIGHT,
+				rect->height + icd->y_skip_top - 1);
+	if (ret >= 0 && mt9m001->autoexposure) {
+		ret = reg_write(icd, MT9M001_SHUTTER_WIDTH,
+				rect->height + icd->y_skip_top + vblank);
+		if (ret >= 0) {
+			const struct v4l2_queryctrl *qctrl =
+				soc_camera_find_qctrl(icd->ops,
+						      V4L2_CID_EXPOSURE);
+			icd->exposure = (524 + (rect->height + icd->y_skip_top +
+						vblank - 1) *
+					 (qctrl->maximum - qctrl->minimum)) /
+				1048 + qctrl->minimum;
+		}
+	}
+
+	return ret < 0 ? ret : 0;
+}
+
+static int mt9m001_try_fmt_cap(struct soc_camera_device *icd,
+			       struct v4l2_format *f)
+{
+	if (f->fmt.pix.height < 32 + icd->y_skip_top)
+		f->fmt.pix.height = 32 + icd->y_skip_top;
+	if (f->fmt.pix.height > 1024 + icd->y_skip_top)
+		f->fmt.pix.height = 1024 + icd->y_skip_top;
+	if (f->fmt.pix.width < 48)
+		f->fmt.pix.width = 48;
+	if (f->fmt.pix.width > 1280)
+		f->fmt.pix.width = 1280;
+	f->fmt.pix.width &= ~0x01; /* has to be even, unsure why was ~3 */
+
+	return 0;
+}
+
+static int mt9m001_get_chip_id(struct soc_camera_device *icd,
+			       struct v4l2_chip_ident *id)
+{
+	struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+
+	if (id->match_type != V4L2_CHIP_MATCH_I2C_ADDR)
+		return -EINVAL;
+
+	if (id->match_chip != mt9m001->client->addr)
+		return -ENODEV;
+
+	id->ident	= mt9m001->model;
+	id->revision	= 0;
+
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mt9m001_get_register(struct soc_camera_device *icd,
+				struct v4l2_register *reg)
+{
+	struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+
+	if (reg->match_type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+		return -EINVAL;
+
+	if (reg->match_chip != mt9m001->client->addr)
+		return -ENODEV;
+
+	reg->val = reg_read(icd, reg->reg);
+
+	if (reg->val > 0xffff)
+		return -EIO;
+
+	return 0;
+}
+
+static int mt9m001_set_register(struct soc_camera_device *icd,
+				struct v4l2_register *reg)
+{
+	struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+
+	if (reg->match_type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+		return -EINVAL;
+
+	if (reg->match_chip != mt9m001->client->addr)
+		return -ENODEV;
+
+	if (reg_write(icd, reg->reg, reg->val) < 0)
+		return -EIO;
+
+	return 0;
+}
+#endif
+
+const struct v4l2_queryctrl mt9m001_controls[] = {
+	{
+		.id		= V4L2_CID_VFLIP,
+		.type		= V4L2_CTRL_TYPE_BOOLEAN,
+		.name		= "Flip Vertically",
+		.minimum	= 0,
+		.maximum	= 1,
+		.step		= 1,
+		.default_value	= 0,
+	}, {
+		.id		= V4L2_CID_GAIN,
+		.type		= V4L2_CTRL_TYPE_INTEGER,
+		.name		= "Gain",
+		.minimum	= 0,
+		.maximum	= 127,
+		.step		= 1,
+		.default_value	= 64,
+		.flags		= V4L2_CTRL_FLAG_SLIDER,
+	}, {
+		.id		= V4L2_CID_EXPOSURE,
+		.type		= V4L2_CTRL_TYPE_INTEGER,
+		.name		= "Exposure",
+		.minimum	= 1,
+		.maximum	= 255,
+		.step		= 1,
+		.default_value	= 255,
+		.flags		= V4L2_CTRL_FLAG_SLIDER,
+	}, {
+		.id		= V4L2_CID_EXPOSURE_AUTO,
+		.type		= V4L2_CTRL_TYPE_BOOLEAN,
+		.name		= "Automatic Exposure",
+		.minimum	= 0,
+		.maximum	= 1,
+		.step		= 1,
+		.default_value	= 1,
+	}
+};
+
+static int mt9m001_video_probe(struct soc_camera_device *);
+static void mt9m001_video_remove(struct soc_camera_device *);
+static int mt9m001_get_control(struct soc_camera_device *, struct v4l2_control *);
+static int mt9m001_set_control(struct soc_camera_device *, struct v4l2_control *);
+
+static struct soc_camera_ops mt9m001_ops = {
+	.owner			= THIS_MODULE,
+	.probe			= mt9m001_video_probe,
+	.remove			= mt9m001_video_remove,
+	.init			= mt9m001_init,
+	.release		= mt9m001_release,
+	.start_capture		= mt9m001_start_capture,
+	.stop_capture		= mt9m001_stop_capture,
+	.set_fmt_cap		= mt9m001_set_fmt_cap,
+	.try_fmt_cap		= mt9m001_try_fmt_cap,
+	.set_bus_param		= mt9m001_set_bus_param,
+	.query_bus_param	= mt9m001_query_bus_param,
+	.controls		= mt9m001_controls,
+	.num_controls		= ARRAY_SIZE(mt9m001_controls),
+	.get_control		= mt9m001_get_control,
+	.set_control		= mt9m001_set_control,
+	.get_chip_id		= mt9m001_get_chip_id,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.get_register		= mt9m001_get_register,
+	.set_register		= mt9m001_set_register,
+#endif
+};
+
+static int mt9m001_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
+{
+	struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+	int data;
+
+	switch (ctrl->id) {
+	case V4L2_CID_VFLIP:
+		data = reg_read(icd, MT9M001_READ_OPTIONS2);
+		if (data < 0)
+			return -EIO;
+		ctrl->value = !!(data & 0x8000);
+		break;
+	case V4L2_CID_EXPOSURE_AUTO:
+		ctrl->value = mt9m001->autoexposure;
+		break;
+	}
+	return 0;
+}
+
+static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
+{
+	struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+	const struct v4l2_queryctrl *qctrl;
+	int data;
+
+	qctrl = soc_camera_find_qctrl(&mt9m001_ops, ctrl->id);
+
+	if (!qctrl)
+		return -EINVAL;
+
+	switch (ctrl->id) {
+	case V4L2_CID_VFLIP:
+		if (ctrl->value)
+			data = reg_set(icd, MT9M001_READ_OPTIONS2, 0x8000);
+		else
+			data = reg_clear(icd, MT9M001_READ_OPTIONS2, 0x8000);
+		if (data < 0)
+			return -EIO;
+		break;
+	case V4L2_CID_GAIN:
+		if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum)
+			return -EINVAL;
+		/* See Datasheet Table 7, Gain settings. */
+		if (ctrl->value <= qctrl->default_value) {
+			/* Pack it into 0..1 step 0.125, register values 0..8 */
+			unsigned long range = qctrl->default_value - qctrl->minimum;
+			data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range;
+
+			dev_dbg(&icd->dev, "Setting gain %d\n", data);
+			data = reg_write(icd, MT9M001_GLOBAL_GAIN, data);
+			if (data < 0)
+				return -EIO;
+		} else {
+			/* Pack it into 1.125..15 variable step, register values 9..67 */
+			/* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */
+			unsigned long range = qctrl->maximum - qctrl->default_value - 1;
+			unsigned long gain = ((ctrl->value - qctrl->default_value - 1) *
+					       111 + range / 2) / range + 9;
+
+			if (gain <= 32)
+				data = gain;
+			else if (gain <= 64)
+				data = ((gain - 32) * 16 + 16) / 32 + 80;
+			else
+				data = ((gain - 64) * 7 + 28) / 56 + 96;
+
+			dev_dbg(&icd->dev, "Setting gain from %d to %d\n",
+				 reg_read(icd, MT9M001_GLOBAL_GAIN), data);
+			data = reg_write(icd, MT9M001_GLOBAL_GAIN, data);
+			if (data < 0)
+				return -EIO;
+		}
+
+		/* Success */
+		icd->gain = ctrl->value;
+		break;
+	case V4L2_CID_EXPOSURE:
+		/* mt9m001 has maximum == default */
+		if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum)
+			return -EINVAL;
+		else {
+			unsigned long range = qctrl->maximum - qctrl->minimum;
+			unsigned long shutter = ((ctrl->value - qctrl->minimum) * 1048 +
+						 range / 2) / range + 1;
+
+			dev_dbg(&icd->dev, "Setting shutter width from %d to %lu\n",
+				 reg_read(icd, MT9M001_SHUTTER_WIDTH), shutter);
+			if (reg_write(icd, MT9M001_SHUTTER_WIDTH, shutter) < 0)
+				return -EIO;
+			icd->exposure = ctrl->value;
+			mt9m001->autoexposure = 0;
+		}
+		break;
+	case V4L2_CID_EXPOSURE_AUTO:
+		if (ctrl->value) {
+			const u16 vblank = 25;
+			if (reg_write(icd, MT9M001_SHUTTER_WIDTH, icd->height +
+				      icd->y_skip_top + vblank) < 0)
+				return -EIO;
+			qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
+			icd->exposure = (524 + (icd->height + icd->y_skip_top + vblank - 1) *
+					 (qctrl->maximum - qctrl->minimum)) /
+				1048 + qctrl->minimum;
+			mt9m001->autoexposure = 1;
+		} else
+			mt9m001->autoexposure = 0;
+		break;
+	}
+	return 0;
+}
+
+/* Interface active, can use i2c. If it fails, it can indeed mean, that
+ * this wasn't our capture interface, so, we wait for the right one */
+static int mt9m001_video_probe(struct soc_camera_device *icd)
+{
+	struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+	s32 data;
+	int ret;
+
+	/* We must have a parent by now. And it cannot be a wrong one.
+	 * So this entire test is completely redundant. */
+	if (!icd->dev.parent ||
+	    to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
+		return -ENODEV;
+
+	/* Enable the chip */
+	data = reg_write(&mt9m001->icd, MT9M001_CHIP_ENABLE, 1);
+	dev_dbg(&icd->dev, "write: %d\n", data);
+
+	/* Read out the chip version register */
+	data = reg_read(icd, MT9M001_CHIP_VERSION);
+
+	/* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */
+	switch (data) {
+	case 0x8411:
+	case 0x8421:
+		mt9m001->model = V4L2_IDENT_MT9M001C12ST;
+		icd->formats = mt9m001_colour_formats;
+		if (mt9m001->client->dev.platform_data)
+			icd->num_formats = ARRAY_SIZE(mt9m001_colour_formats);
+		else
+			icd->num_formats = 1;
+		break;
+	case 0x8431:
+		mt9m001->model = V4L2_IDENT_MT9M001C12STM;
+		icd->formats = mt9m001_monochrome_formats;
+		if (mt9m001->client->dev.platform_data)
+			icd->num_formats = ARRAY_SIZE(mt9m001_monochrome_formats);
+		else
+			icd->num_formats = 1;
+		break;
+	default:
+		ret = -ENODEV;
+		dev_err(&icd->dev,
+			"No MT9M001 chip detected, register read %x\n", data);
+		goto ei2c;
+	}
+
+	dev_info(&icd->dev, "Detected a MT9M001 chip ID %x (%s)\n", data,
+		 data == 0x8431 ? "C12STM" : "C12ST");
+
+	/* Now that we know the model, we can start video */
+	ret = soc_camera_video_start(icd);
+	if (ret)
+		goto eisis;
+
+	return 0;
+
+eisis:
+ei2c:
+	return ret;
+}
+
+static void mt9m001_video_remove(struct soc_camera_device *icd)
+{
+	struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+
+	dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9m001->client->addr,
+		mt9m001->icd.dev.parent, mt9m001->icd.vdev);
+	soc_camera_video_stop(&mt9m001->icd);
+}
+
+static int mt9m001_probe(struct i2c_client *client)
+{
+	struct mt9m001 *mt9m001;
+	struct soc_camera_device *icd;
+	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+	struct soc_camera_link *icl = client->dev.platform_data;
+	int ret;
+
+	if (!icl) {
+		dev_err(&client->dev, "MT9M001 driver needs platform data\n");
+		return -EINVAL;
+	}
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
+		dev_warn(&adapter->dev,
+			 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+		return -EIO;
+	}
+
+	mt9m001 = kzalloc(sizeof(struct mt9m001), GFP_KERNEL);
+	if (!mt9m001)
+		return -ENOMEM;
+
+	mt9m001->client = client;
+	i2c_set_clientdata(client, mt9m001);
+
+	/* Second stage probe - when a capture adapter is there */
+	icd = &mt9m001->icd;
+	icd->ops	= &mt9m001_ops;
+	icd->control	= &client->dev;
+	icd->x_min	= 20;
+	icd->y_min	= 12;
+	icd->x_current	= 20;
+	icd->y_current	= 12;
+	icd->width_min	= 48;
+	icd->width_max	= 1280;
+	icd->height_min	= 32;
+	icd->height_max	= 1024;
+	icd->y_skip_top	= 1;
+	icd->iface	= icl->bus_id;
+	/* Default datawidth - this is the only width this camera (normally)
+	 * supports. It is only with extra logic that it can support
+	 * other widths. Therefore it seems to be a sensible default. */
+	mt9m001->datawidth = 10;
+	/* Simulated autoexposure. If enabled, we calculate shutter width
+	 * ourselves in the driver based on vertical blanking and frame width */
+	mt9m001->autoexposure = 1;
+
+	ret = bus_switch_request(mt9m001, icl);
+	if (ret)
+		goto eswinit;
+
+	ret = soc_camera_device_register(icd);
+	if (ret)
+		goto eisdr;
+
+	return 0;
+
+eisdr:
+	bus_switch_release(mt9m001);
+eswinit:
+	kfree(mt9m001);
+	return ret;
+}
+
+static int mt9m001_remove(struct i2c_client *client)
+{
+	struct mt9m001 *mt9m001 = i2c_get_clientdata(client);
+
+	soc_camera_device_unregister(&mt9m001->icd);
+	bus_switch_release(mt9m001);
+	kfree(mt9m001);
+
+	return 0;
+}
+
+static struct i2c_driver mt9m001_i2c_driver = {
+	.driver = {
+		.name = "mt9m001",
+	},
+	.probe		= mt9m001_probe,
+	.remove		= mt9m001_remove,
+};
+
+static int __init mt9m001_mod_init(void)
+{
+	return i2c_add_driver(&mt9m001_i2c_driver);
+}
+
+static void __exit mt9m001_mod_exit(void)
+{
+	i2c_del_driver(&mt9m001_i2c_driver);
+}
+
+module_init(mt9m001_mod_init);
+module_exit(mt9m001_mod_exit);
+
+MODULE_DESCRIPTION("Micron MT9M001 Camera driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
new file mode 100644
index 0000000..d4b9e27
--- /dev/null
+++ b/drivers/media/video/mt9v022.c
@@ -0,0 +1,844 @@
+/*
+ * Driver for MT9V022 CMOS Image Sensor from Micron
+ *
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/log2.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/soc_camera.h>
+
+#ifdef CONFIG_MT9M001_PCA9536_SWITCH
+#include <asm/gpio.h>
+#endif
+
+/* mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c
+ * The platform has to define i2c_board_info
+ * and call i2c_register_board_info() */
+
+static char *sensor_type;
+module_param(sensor_type, charp, S_IRUGO);
+MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\"\n");
+
+/* mt9v022 selected register addresses */
+#define MT9V022_CHIP_VERSION		0x00
+#define MT9V022_COLUMN_START		0x01
+#define MT9V022_ROW_START		0x02
+#define MT9V022_WINDOW_HEIGHT		0x03
+#define MT9V022_WINDOW_WIDTH		0x04
+#define MT9V022_HORIZONTAL_BLANKING	0x05
+#define MT9V022_VERTICAL_BLANKING	0x06
+#define MT9V022_CHIP_CONTROL		0x07
+#define MT9V022_SHUTTER_WIDTH1		0x08
+#define MT9V022_SHUTTER_WIDTH2		0x09
+#define MT9V022_SHUTTER_WIDTH_CTRL	0x0a
+#define MT9V022_TOTAL_SHUTTER_WIDTH	0x0b
+#define MT9V022_RESET			0x0c
+#define MT9V022_READ_MODE		0x0d
+#define MT9V022_MONITOR_MODE		0x0e
+#define MT9V022_PIXEL_OPERATION_MODE	0x0f
+#define MT9V022_LED_OUT_CONTROL		0x1b
+#define MT9V022_ADC_MODE_CONTROL	0x1c
+#define MT9V022_ANALOG_GAIN		0x34
+#define MT9V022_BLACK_LEVEL_CALIB_CTRL	0x47
+#define MT9V022_PIXCLK_FV_LV		0x74
+#define MT9V022_DIGITAL_TEST_PATTERN	0x7f
+#define MT9V022_AEC_AGC_ENABLE		0xAF
+#define MT9V022_MAX_TOTAL_SHUTTER_WIDTH	0xBD
+
+/* Progressive scan, master, defaults */
+#define MT9V022_CHIP_CONTROL_DEFAULT	0x188
+
+static const struct soc_camera_data_format mt9v022_colour_formats[] = {
+	/* Order important: first natively supported,
+	 * second supported with a GPIO extender */
+	{
+		.name		= "Bayer (sRGB) 10 bit",
+		.depth		= 10,
+		.fourcc		= V4L2_PIX_FMT_SBGGR16,
+		.colorspace	= V4L2_COLORSPACE_SRGB,
+	}, {
+		.name		= "Bayer (sRGB) 8 bit",
+		.depth		= 8,
+		.fourcc		= V4L2_PIX_FMT_SBGGR8,
+		.colorspace	= V4L2_COLORSPACE_SRGB,
+	}
+};
+
+static const struct soc_camera_data_format mt9v022_monochrome_formats[] = {
+	/* Order important - see above */
+	{
+		.name		= "Monochrome 10 bit",
+		.depth		= 10,
+		.fourcc		= V4L2_PIX_FMT_Y16,
+	}, {
+		.name		= "Monochrome 8 bit",
+		.depth		= 8,
+		.fourcc		= V4L2_PIX_FMT_GREY,
+	},
+};
+
+struct mt9v022 {
+	struct i2c_client *client;
+	struct soc_camera_device icd;
+	int model;	/* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */
+	int switch_gpio;
+	u16 chip_control;
+	unsigned char datawidth;
+};
+
+static int reg_read(struct soc_camera_device *icd, const u8 reg)
+{
+	struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+	struct i2c_client *client = mt9v022->client;
+	s32 data = i2c_smbus_read_word_data(client, reg);
+	return data < 0 ? data : swab16(data);
+}
+
+static int reg_write(struct soc_camera_device *icd, const u8 reg,
+		     const u16 data)
+{
+	struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+	return i2c_smbus_write_word_data(mt9v022->client, reg, swab16(data));
+}
+
+static int reg_set(struct soc_camera_device *icd, const u8 reg,
+		   const u16 data)
+{
+	int ret;
+
+	ret = reg_read(icd, reg);
+	if (ret < 0)
+		return ret;
+	return reg_write(icd, reg, ret | data);
+}
+
+static int reg_clear(struct soc_camera_device *icd, const u8 reg,
+		     const u16 data)
+{
+	int ret;
+
+	ret = reg_read(icd, reg);
+	if (ret < 0)
+		return ret;
+	return reg_write(icd, reg, ret & ~data);
+}
+
+static int mt9v022_init(struct soc_camera_device *icd)
+{
+	struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+	int ret;
+
+	/* Almost the default mode: master, parallel, simultaneous, and an
+	 * undocumented bit 0x200, which is present in table 7, but not in 8,
+	 * plus snapshot mode to disable scan for now */
+	mt9v022->chip_control |= 0x10;
+	ret = reg_write(icd, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
+	if (ret >= 0)
+		reg_write(icd, MT9V022_READ_MODE, 0x300);
+
+	/* All defaults */
+	if (ret >= 0)
+		/* AEC, AGC on */
+		ret = reg_set(icd, MT9V022_AEC_AGC_ENABLE, 0x3);
+	if (ret >= 0)
+		ret = reg_write(icd, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 480);
+	if (ret >= 0)
+		/* default - auto */
+		ret = reg_clear(icd, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1);
+	if (ret >= 0)
+		ret = reg_write(icd, MT9V022_DIGITAL_TEST_PATTERN, 0);
+
+	return ret >= 0 ? 0 : -EIO;
+}
+
+static int mt9v022_release(struct soc_camera_device *icd)
+{
+	/* Nothing? */
+	return 0;
+}
+
+static int mt9v022_start_capture(struct soc_camera_device *icd)
+{
+	struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+	/* Switch to master "normal" mode */
+	mt9v022->chip_control &= ~0x10;
+	if (reg_write(icd, MT9V022_CHIP_CONTROL,
+		      mt9v022->chip_control) < 0)
+		return -EIO;
+	return 0;
+}
+
+static int mt9v022_stop_capture(struct soc_camera_device *icd)
+{
+	struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+	/* Switch to snapshot mode */
+	mt9v022->chip_control |= 0x10;
+	if (reg_write(icd, MT9V022_CHIP_CONTROL,
+		      mt9v022->chip_control) < 0)
+		return -EIO;
+	return 0;
+}
+
+static int bus_switch_request(struct mt9v022 *mt9v022, struct soc_camera_link *icl)
+{
+#ifdef CONFIG_MT9V022_PCA9536_SWITCH
+	int ret;
+	unsigned int gpio = icl->gpio;
+
+	if (gpio_is_valid(gpio)) {
+		/* We have a data bus switch. */
+		ret = gpio_request(gpio, "mt9v022");
+		if (ret < 0) {
+			dev_err(&mt9v022->client->dev, "Cannot get GPIO %u\n", gpio);
+			return ret;
+		}
+
+		ret = gpio_direction_output(gpio, 0);
+		if (ret < 0) {
+			dev_err(&mt9v022->client->dev,
+				"Cannot set GPIO %u to output\n", gpio);
+			gpio_free(gpio);
+			return ret;
+		}
+	}
+
+	mt9v022->switch_gpio = gpio;
+#else
+	mt9v022->switch_gpio = -EINVAL;
+#endif
+	return 0;
+}
+
+static void bus_switch_release(struct mt9v022 *mt9v022)
+{
+#ifdef CONFIG_MT9V022_PCA9536_SWITCH
+	if (gpio_is_valid(mt9v022->switch_gpio))
+		gpio_free(mt9v022->switch_gpio);
+#endif
+}
+
+static int bus_switch_act(struct mt9v022 *mt9v022, int go8bit)
+{
+#ifdef CONFIG_MT9V022_PCA9536_SWITCH
+	if (!gpio_is_valid(mt9v022->switch_gpio))
+		return -ENODEV;
+
+	gpio_set_value_cansleep(mt9v022->switch_gpio, go8bit);
+	return 0;
+#else
+	return -ENODEV;
+#endif
+}
+
+static int bus_switch_possible(struct mt9v022 *mt9v022)
+{
+#ifdef CONFIG_MT9V022_PCA9536_SWITCH
+	return gpio_is_valid(mt9v022->switch_gpio);
+#else
+	return 0;
+#endif
+}
+
+static int mt9v022_set_bus_param(struct soc_camera_device *icd,
+				 unsigned long flags)
+{
+	struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+	unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK;
+	int ret;
+	u16 pixclk = 0;
+
+	/* Only one width bit may be set */
+	if (!is_power_of_2(width_flag))
+		return -EINVAL;
+
+	if ((mt9v022->datawidth != 10 && (width_flag == SOCAM_DATAWIDTH_10)) ||
+	    (mt9v022->datawidth != 9  && (width_flag == SOCAM_DATAWIDTH_9)) ||
+	    (mt9v022->datawidth != 8  && (width_flag == SOCAM_DATAWIDTH_8))) {
+		/* Well, we actually only can do 10 or 8 bits... */
+		if (width_flag == SOCAM_DATAWIDTH_9)
+			return -EINVAL;
+
+		ret = bus_switch_act(mt9v022,
+				     width_flag == SOCAM_DATAWIDTH_8);
+		if (ret < 0)
+			return ret;
+
+		mt9v022->datawidth = width_flag == SOCAM_DATAWIDTH_8 ? 8 : 10;
+	}
+
+	if (flags & SOCAM_PCLK_SAMPLE_RISING)
+		pixclk |= 0x10;
+
+	if (!(flags & SOCAM_HSYNC_ACTIVE_HIGH))
+		pixclk |= 0x1;
+
+	if (!(flags & SOCAM_VSYNC_ACTIVE_HIGH))
+		pixclk |= 0x2;
+
+	ret = reg_write(icd, MT9V022_PIXCLK_FV_LV, pixclk);
+	if (ret < 0)
+		return ret;
+
+	if (!(flags & SOCAM_MASTER))
+		mt9v022->chip_control &= ~0x8;
+
+	ret = reg_write(icd, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
+	if (ret < 0)
+		return ret;
+
+	dev_dbg(&icd->dev, "Calculated pixclk 0x%x, chip control 0x%x\n",
+		pixclk, mt9v022->chip_control);
+
+	return 0;
+}
+
+static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
+{
+	struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+	unsigned int width_flag = SOCAM_DATAWIDTH_10;
+
+	if (bus_switch_possible(mt9v022))
+		width_flag |= SOCAM_DATAWIDTH_8;
+
+	return SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING |
+		SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW |
+		SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW |
+		SOCAM_MASTER | SOCAM_SLAVE |
+		width_flag;
+}
+
+static int mt9v022_set_fmt_cap(struct soc_camera_device *icd,
+		__u32 pixfmt, struct v4l2_rect *rect)
+{
+	struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+	int ret;
+
+	/* The caller provides a supported format, as verified per call to
+	 * icd->try_fmt_cap(), datawidth is from our supported format list */
+	switch (pixfmt) {
+	case V4L2_PIX_FMT_GREY:
+	case V4L2_PIX_FMT_Y16:
+		if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM)
+			return -EINVAL;
+		break;
+	case V4L2_PIX_FMT_SBGGR8:
+	case V4L2_PIX_FMT_SBGGR16:
+		if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC)
+			return -EINVAL;
+		break;
+	case 0:
+		/* No format change, only geometry */
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Like in example app. Contradicts the datasheet though */
+	ret = reg_read(icd, MT9V022_AEC_AGC_ENABLE);
+	if (ret >= 0) {
+		if (ret & 1) /* Autoexposure */
+			ret = reg_write(icd, MT9V022_MAX_TOTAL_SHUTTER_WIDTH,
+					rect->height + icd->y_skip_top + 43);
+		else
+			ret = reg_write(icd, MT9V022_TOTAL_SHUTTER_WIDTH,
+					rect->height + icd->y_skip_top + 43);
+	}
+	/* Setup frame format: defaults apart from width and height */
+	if (ret >= 0)
+		ret = reg_write(icd, MT9V022_COLUMN_START, rect->left);
+	if (ret >= 0)
+		ret = reg_write(icd, MT9V022_ROW_START, rect->top);
+	if (ret >= 0)
+		/* Default 94, Phytec driver says:
+		 * "width + horizontal blank >= 660" */
+		ret = reg_write(icd, MT9V022_HORIZONTAL_BLANKING,
+				rect->width > 660 - 43 ? 43 :
+				660 - rect->width);
+	if (ret >= 0)
+		ret = reg_write(icd, MT9V022_VERTICAL_BLANKING, 45);
+	if (ret >= 0)
+		ret = reg_write(icd, MT9V022_WINDOW_WIDTH, rect->width);
+	if (ret >= 0)
+		ret = reg_write(icd, MT9V022_WINDOW_HEIGHT,
+				rect->height + icd->y_skip_top);
+
+	if (ret < 0)
+		return ret;
+
+	dev_dbg(&icd->dev, "Frame %ux%u pixel\n", rect->width, rect->height);
+
+	return 0;
+}
+
+static int mt9v022_try_fmt_cap(struct soc_camera_device *icd,
+			       struct v4l2_format *f)
+{
+	if (f->fmt.pix.height < 32 + icd->y_skip_top)
+		f->fmt.pix.height = 32 + icd->y_skip_top;
+	if (f->fmt.pix.height > 480 + icd->y_skip_top)
+		f->fmt.pix.height = 480 + icd->y_skip_top;
+	if (f->fmt.pix.width < 48)
+		f->fmt.pix.width = 48;
+	if (f->fmt.pix.width > 752)
+		f->fmt.pix.width = 752;
+	f->fmt.pix.width &= ~0x03; /* ? */
+
+	return 0;
+}
+
+static int mt9v022_get_chip_id(struct soc_camera_device *icd,
+			       struct v4l2_chip_ident *id)
+{
+	struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+
+	if (id->match_type != V4L2_CHIP_MATCH_I2C_ADDR)
+		return -EINVAL;
+
+	if (id->match_chip != mt9v022->client->addr)
+		return -ENODEV;
+
+	id->ident	= mt9v022->model;
+	id->revision	= 0;
+
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mt9v022_get_register(struct soc_camera_device *icd,
+				struct v4l2_register *reg)
+{
+	struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+
+	if (reg->match_type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+		return -EINVAL;
+
+	if (reg->match_chip != mt9v022->client->addr)
+		return -ENODEV;
+
+	reg->val = reg_read(icd, reg->reg);
+
+	if (reg->val > 0xffff)
+		return -EIO;
+
+	return 0;
+}
+
+static int mt9v022_set_register(struct soc_camera_device *icd,
+				struct v4l2_register *reg)
+{
+	struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+
+	if (reg->match_type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+		return -EINVAL;
+
+	if (reg->match_chip != mt9v022->client->addr)
+		return -ENODEV;
+
+	if (reg_write(icd, reg->reg, reg->val) < 0)
+		return -EIO;
+
+	return 0;
+}
+#endif
+
+const struct v4l2_queryctrl mt9v022_controls[] = {
+	{
+		.id		= V4L2_CID_VFLIP,
+		.type		= V4L2_CTRL_TYPE_BOOLEAN,
+		.name		= "Flip Vertically",
+		.minimum	= 0,
+		.maximum	= 1,
+		.step		= 1,
+		.default_value	= 0,
+	}, {
+		.id		= V4L2_CID_HFLIP,
+		.type		= V4L2_CTRL_TYPE_BOOLEAN,
+		.name		= "Flip Horizontally",
+		.minimum	= 0,
+		.maximum	= 1,
+		.step		= 1,
+		.default_value	= 0,
+	}, {
+		.id		= V4L2_CID_GAIN,
+		.type		= V4L2_CTRL_TYPE_INTEGER,
+		.name		= "Analog Gain",
+		.minimum	= 64,
+		.maximum	= 127,
+		.step		= 1,
+		.default_value	= 64,
+		.flags		= V4L2_CTRL_FLAG_SLIDER,
+	}, {
+		.id		= V4L2_CID_EXPOSURE,
+		.type		= V4L2_CTRL_TYPE_INTEGER,
+		.name		= "Exposure",
+		.minimum	= 1,
+		.maximum	= 255,
+		.step		= 1,
+		.default_value	= 255,
+		.flags		= V4L2_CTRL_FLAG_SLIDER,
+	}, {
+		.id		= V4L2_CID_AUTOGAIN,
+		.type		= V4L2_CTRL_TYPE_BOOLEAN,
+		.name		= "Automatic Gain",
+		.minimum	= 0,
+		.maximum	= 1,
+		.step		= 1,
+		.default_value	= 1,
+	}, {
+		.id		= V4L2_CID_EXPOSURE_AUTO,
+		.type		= V4L2_CTRL_TYPE_BOOLEAN,
+		.name		= "Automatic Exposure",
+		.minimum	= 0,
+		.maximum	= 1,
+		.step		= 1,
+		.default_value	= 1,
+	}
+};
+
+static int mt9v022_video_probe(struct soc_camera_device *);
+static void mt9v022_video_remove(struct soc_camera_device *);
+static int mt9v022_get_control(struct soc_camera_device *, struct v4l2_control *);
+static int mt9v022_set_control(struct soc_camera_device *, struct v4l2_control *);
+
+static struct soc_camera_ops mt9v022_ops = {
+	.owner			= THIS_MODULE,
+	.probe			= mt9v022_video_probe,
+	.remove			= mt9v022_video_remove,
+	.init			= mt9v022_init,
+	.release		= mt9v022_release,
+	.start_capture		= mt9v022_start_capture,
+	.stop_capture		= mt9v022_stop_capture,
+	.set_fmt_cap		= mt9v022_set_fmt_cap,
+	.try_fmt_cap		= mt9v022_try_fmt_cap,
+	.set_bus_param		= mt9v022_set_bus_param,
+	.query_bus_param	= mt9v022_query_bus_param,
+	.controls		= mt9v022_controls,
+	.num_controls		= ARRAY_SIZE(mt9v022_controls),
+	.get_control		= mt9v022_get_control,
+	.set_control		= mt9v022_set_control,
+	.get_chip_id		= mt9v022_get_chip_id,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.get_register		= mt9v022_get_register,
+	.set_register		= mt9v022_set_register,
+#endif
+};
+
+static int mt9v022_get_control(struct soc_camera_device *icd,
+			       struct v4l2_control *ctrl)
+{
+	int data;
+
+	switch (ctrl->id) {
+	case V4L2_CID_VFLIP:
+		data = reg_read(icd, MT9V022_READ_MODE);
+		if (data < 0)
+			return -EIO;
+		ctrl->value = !!(data & 0x10);
+		break;
+	case V4L2_CID_HFLIP:
+		data = reg_read(icd, MT9V022_READ_MODE);
+		if (data < 0)
+			return -EIO;
+		ctrl->value = !!(data & 0x20);
+		break;
+	case V4L2_CID_EXPOSURE_AUTO:
+		data = reg_read(icd, MT9V022_AEC_AGC_ENABLE);
+		if (data < 0)
+			return -EIO;
+		ctrl->value = !!(data & 0x1);
+		break;
+	case V4L2_CID_AUTOGAIN:
+		data = reg_read(icd, MT9V022_AEC_AGC_ENABLE);
+		if (data < 0)
+			return -EIO;
+		ctrl->value = !!(data & 0x2);
+		break;
+	}
+	return 0;
+}
+
+static int mt9v022_set_control(struct soc_camera_device *icd,
+			       struct v4l2_control *ctrl)
+{
+	int data;
+	const struct v4l2_queryctrl *qctrl;
+
+	qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id);
+
+	if (!qctrl)
+		return -EINVAL;
+
+	switch (ctrl->id) {
+	case V4L2_CID_VFLIP:
+		if (ctrl->value)
+			data = reg_set(icd, MT9V022_READ_MODE, 0x10);
+		else
+			data = reg_clear(icd, MT9V022_READ_MODE, 0x10);
+		if (data < 0)
+			return -EIO;
+		break;
+	case V4L2_CID_HFLIP:
+		if (ctrl->value)
+			data = reg_set(icd, MT9V022_READ_MODE, 0x20);
+		else
+			data = reg_clear(icd, MT9V022_READ_MODE, 0x20);
+		if (data < 0)
+			return -EIO;
+		break;
+	case V4L2_CID_GAIN:
+		/* mt9v022 has minimum == default */
+		if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum)
+			return -EINVAL;
+		else {
+			unsigned long range = qctrl->maximum - qctrl->minimum;
+			/* Datasheet says 16 to 64. autogain only works properly
+			 * after setting gain to maximum 14. Larger values
+			 * produce "white fly" noise effect. On the whole,
+			 * manually setting analog gain does no good. */
+			unsigned long gain = ((ctrl->value - qctrl->minimum) *
+					      10 + range / 2) / range + 4;
+			if (gain >= 32)
+				gain &= ~1;
+			/* The user wants to set gain manually, hope, she
+			 * knows, what she's doing... Switch AGC off. */
+
+			if (reg_clear(icd, MT9V022_AEC_AGC_ENABLE, 0x2) < 0)
+				return -EIO;
+
+			dev_info(&icd->dev, "Setting gain from %d to %lu\n",
+				 reg_read(icd, MT9V022_ANALOG_GAIN), gain);
+			if (reg_write(icd, MT9V022_ANALOG_GAIN, gain) < 0)
+				return -EIO;
+			icd->gain = ctrl->value;
+		}
+		break;
+	case V4L2_CID_EXPOSURE:
+		/* mt9v022 has maximum == default */
+		if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum)
+			return -EINVAL;
+		else {
+			unsigned long range = qctrl->maximum - qctrl->minimum;
+			unsigned long shutter = ((ctrl->value - qctrl->minimum) *
+						 479 + range / 2) / range + 1;
+			/* The user wants to set shutter width manually, hope,
+			 * she knows, what she's doing... Switch AEC off. */
+
+			if (reg_clear(icd, MT9V022_AEC_AGC_ENABLE, 0x1) < 0)
+				return -EIO;
+
+			dev_dbg(&icd->dev, "Shutter width from %d to %lu\n",
+				reg_read(icd, MT9V022_TOTAL_SHUTTER_WIDTH),
+				shutter);
+			if (reg_write(icd, MT9V022_TOTAL_SHUTTER_WIDTH,
+				      shutter) < 0)
+				return -EIO;
+			icd->exposure = ctrl->value;
+		}
+		break;
+	case V4L2_CID_AUTOGAIN:
+		if (ctrl->value)
+			data = reg_set(icd, MT9V022_AEC_AGC_ENABLE, 0x2);
+		else
+			data = reg_clear(icd, MT9V022_AEC_AGC_ENABLE, 0x2);
+		if (data < 0)
+			return -EIO;
+		break;
+	case V4L2_CID_EXPOSURE_AUTO:
+		if (ctrl->value)
+			data = reg_set(icd, MT9V022_AEC_AGC_ENABLE, 0x1);
+		else
+			data = reg_clear(icd, MT9V022_AEC_AGC_ENABLE, 0x1);
+		if (data < 0)
+			return -EIO;
+		break;
+	}
+	return 0;
+}
+
+/* Interface active, can use i2c. If it fails, it can indeed mean, that
+ * this wasn't our capture interface, so, we wait for the right one */
+static int mt9v022_video_probe(struct soc_camera_device *icd)
+{
+	struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+	s32 data;
+	int ret;
+
+	if (!icd->dev.parent ||
+	    to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
+		return -ENODEV;
+
+	/* Read out the chip version register */
+	data = reg_read(icd, MT9V022_CHIP_VERSION);
+
+	/* must be 0x1311 or 0x1313 */
+	if (data != 0x1311 && data != 0x1313) {
+		ret = -ENODEV;
+		dev_info(&icd->dev, "No MT9V022 detected, ID register 0x%x\n",
+			 data);
+		goto ei2c;
+	}
+
+	/* Soft reset */
+	ret = reg_write(icd, MT9V022_RESET, 1);
+	if (ret < 0)
+		goto ei2c;
+	/* 15 clock cycles */
+	udelay(200);
+	if (reg_read(icd, MT9V022_RESET)) {
+		dev_err(&icd->dev, "Resetting MT9V022 failed!\n");
+		goto ei2c;
+	}
+
+	/* Set monochrome or colour sensor type */
+	if (sensor_type && (!strcmp("colour", sensor_type) ||
+			    !strcmp("color", sensor_type))) {
+		ret = reg_write(icd, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11);
+		mt9v022->model = V4L2_IDENT_MT9V022IX7ATC;
+		icd->formats = mt9v022_colour_formats;
+		if (mt9v022->client->dev.platform_data)
+			icd->num_formats = ARRAY_SIZE(mt9v022_colour_formats);
+		else
+			icd->num_formats = 1;
+	} else {
+		ret = reg_write(icd, MT9V022_PIXEL_OPERATION_MODE, 0x11);
+		mt9v022->model = V4L2_IDENT_MT9V022IX7ATM;
+		icd->formats = mt9v022_monochrome_formats;
+		if (mt9v022->client->dev.platform_data)
+			icd->num_formats = ARRAY_SIZE(mt9v022_monochrome_formats);
+		else
+			icd->num_formats = 1;
+	}
+
+	if (ret >= 0)
+		ret = soc_camera_video_start(icd);
+	if (ret < 0)
+		goto eisis;
+
+	dev_info(&icd->dev, "Detected a MT9V022 chip ID %x, %s sensor\n",
+		 data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ?
+		 "monochrome" : "colour");
+
+	return 0;
+
+eisis:
+ei2c:
+	return ret;
+}
+
+static void mt9v022_video_remove(struct soc_camera_device *icd)
+{
+	struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+
+	dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9v022->client->addr,
+		mt9v022->icd.dev.parent, mt9v022->icd.vdev);
+	soc_camera_video_stop(&mt9v022->icd);
+}
+
+static int mt9v022_probe(struct i2c_client *client)
+{
+	struct mt9v022 *mt9v022;
+	struct soc_camera_device *icd;
+	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+	struct soc_camera_link *icl = client->dev.platform_data;
+	int ret;
+
+	if (!icl) {
+		dev_err(&client->dev, "MT9V022 driver needs platform data\n");
+		return -EINVAL;
+	}
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
+		dev_warn(&adapter->dev,
+			 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+		return -EIO;
+	}
+
+	mt9v022 = kzalloc(sizeof(struct mt9v022), GFP_KERNEL);
+	if (!mt9v022)
+		return -ENOMEM;
+
+	mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT;
+	mt9v022->client = client;
+	i2c_set_clientdata(client, mt9v022);
+
+	icd = &mt9v022->icd;
+	icd->ops	= &mt9v022_ops;
+	icd->control	= &client->dev;
+	icd->x_min	= 1;
+	icd->y_min	= 4;
+	icd->x_current	= 1;
+	icd->y_current	= 4;
+	icd->width_min	= 48;
+	icd->width_max	= 752;
+	icd->height_min	= 32;
+	icd->height_max	= 480;
+	icd->y_skip_top	= 1;
+	icd->iface	= icl->bus_id;
+	/* Default datawidth - this is the only width this camera (normally)
+	 * supports. It is only with extra logic that it can support
+	 * other widths. Therefore it seems to be a sensible default. */
+	mt9v022->datawidth = 10;
+
+	ret = bus_switch_request(mt9v022, icl);
+	if (ret)
+		goto eswinit;
+
+	ret = soc_camera_device_register(icd);
+	if (ret)
+		goto eisdr;
+
+	return 0;
+
+eisdr:
+	bus_switch_release(mt9v022);
+eswinit:
+	kfree(mt9v022);
+	return ret;
+}
+
+static int mt9v022_remove(struct i2c_client *client)
+{
+	struct mt9v022 *mt9v022 = i2c_get_clientdata(client);
+
+	soc_camera_device_unregister(&mt9v022->icd);
+	bus_switch_release(mt9v022);
+	kfree(mt9v022);
+
+	return 0;
+}
+
+static struct i2c_driver mt9v022_i2c_driver = {
+	.driver = {
+		.name = "mt9v022",
+	},
+	.probe		= mt9v022_probe,
+	.remove		= mt9v022_remove,
+};
+
+static int __init mt9v022_mod_init(void)
+{
+	return i2c_add_driver(&mt9v022_i2c_driver);
+}
+
+static void __exit mt9v022_mod_exit(void)
+{
+	i2c_del_driver(&mt9v022_i2c_driver);
+}
+
+module_init(mt9v022_mod_init);
+module_exit(mt9v022_mod_exit);
+
+MODULE_DESCRIPTION("Micron MT9V022 Camera driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
index cb5a510..f68e91f 100644
--- a/drivers/media/video/mxb.c
+++ b/drivers/media/video/mxb.c
@@ -38,7 +38,7 @@
 #define MXB_BOARD_CAN_DO_VBI(dev)   (dev->revision != 0)
 
 /* global variable */
-static int mxb_num = 0;
+static int mxb_num;
 
 /* initial frequence the tuner will be tuned to.
    in verden (lower saxony, germany) 4148 is a
@@ -47,7 +47,7 @@
 module_param(freq, int, 0644);
 MODULE_PARM_DESC(freq, "initial frequency the tuner will be tuned to while setup");
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
 
diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c
index 6590058..eafb0c7 100644
--- a/drivers/media/video/ov511.c
+++ b/drivers/media/video/ov511.c
@@ -4659,7 +4659,9 @@
 	.read =		ov51x_v4l1_read,
 	.mmap =		ov51x_v4l1_mmap,
 	.ioctl =	ov51x_v4l1_ioctl,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl = v4l_compat_ioctl32,
+#endif
 	.llseek =	no_llseek,
 };
 
@@ -5831,7 +5833,7 @@
 		goto error;
 
 	memcpy(ov->vdev, &vdev_template, sizeof(*ov->vdev));
-	ov->vdev->dev = &dev->dev;
+	ov->vdev->dev = &intf->dev;
 	video_set_drvdata(ov->vdev, ov);
 
 	for (i = 0; i < OV511_MAX_UNIT_VIDEO; i++) {
diff --git a/drivers/media/video/ov511.h b/drivers/media/video/ov511.h
index 18c6422..1010e51 100644
--- a/drivers/media/video/ov511.h
+++ b/drivers/media/video/ov511.h
@@ -12,7 +12,7 @@
 #ifdef OV511_DEBUG
 	#define PDEBUG(level, fmt, args...) \
 		if (debug >= (level)) info("[%s:%d] " fmt, \
-		__FUNCTION__, __LINE__ , ## args)
+		__func__, __LINE__ , ## args)
 #else
 	#define PDEBUG(level, fmt, args...) do {} while(0)
 #endif
diff --git a/drivers/media/video/ovcamchip/ovcamchip_priv.h b/drivers/media/video/ovcamchip/ovcamchip_priv.h
index 50c7763..9afa4fe 100644
--- a/drivers/media/video/ovcamchip/ovcamchip_priv.h
+++ b/drivers/media/video/ovcamchip/ovcamchip_priv.h
@@ -24,11 +24,11 @@
 
 #define PDEBUG(level, fmt, args...) \
 	if (ovcamchip_debug >= (level))	pr_debug("[%s:%d] " fmt "\n", \
-		__FUNCTION__, __LINE__ , ## args)
+		__func__, __LINE__ , ## args)
 
 #define DDEBUG(level, dev, fmt, args...) \
 	if (ovcamchip_debug >= (level))	dev_dbg(dev, "[%s:%d] " fmt "\n", \
-		__FUNCTION__, __LINE__ , ## args)
+		__func__, __LINE__ , ## args)
 
 /* Number of times to retry chip detection. Increase this if you are getting
  * "Failed to init camera chip" */
diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c
index 6820c2a..51b1461 100644
--- a/drivers/media/video/pms.c
+++ b/drivers/media/video/pms.c
@@ -57,11 +57,11 @@
 	u8 hits;
 };
 
-static int i2c_count 		= 0;
+static int i2c_count;
 static struct i2c_info i2cinfo[64];
 
 static int decoder 		= PHILIPS2;
-static int standard 		= 0;	/* 0 - auto 1 - ntsc 2 - pal 3 - secam */
+static int standard;	/* 0 - auto 1 - ntsc 2 - pal 3 - secam */
 
 /*
  *	I/O ports and Shared Memory
@@ -885,7 +885,9 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl          = pms_ioctl,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
+#endif
 	.read           = pms_read,
 	.llseek         = no_llseek,
 };
diff --git a/drivers/media/video/pvrusb2/Kconfig b/drivers/media/video/pvrusb2/Kconfig
index 6fc1b8b..a8da90f 100644
--- a/drivers/media/video/pvrusb2/Kconfig
+++ b/drivers/media/video/pvrusb2/Kconfig
@@ -58,6 +58,30 @@
 
 	  Note: This feature is experimental and subject to change.
 
+config VIDEO_PVRUSB2_DVB
+	bool "pvrusb2 DVB support (EXPERIMENTAL)"
+	default n
+	depends on VIDEO_PVRUSB2 && DVB_CORE && EXPERIMENTAL
+	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+	select DVB_S5H1409 if !DVB_FE_CUSTOMISE
+	select DVB_TDA10048 if !DVB_FE_CUSTOMIZE
+	select DVB_TDA18271 if !DVB_FE_CUSTOMIZE
+	select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+	select TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
+	---help---
+
+	  This option enables compilation of a DVB interface for the
+	  pvrusb2 driver.  Currently this is very very experimental.
+	  It is also limiting - the DVB interface can only access the
+	  digital side of hybrid devices, and there are going to be
+	  issues if you attempt to mess with the V4L side at the same
+	  time.  Don't turn this on unless you know what you are
+	  doing.
+
+	  If you are in doubt, say N.
+
+	  Note: This feature is very experimental and might break
+
 config VIDEO_PVRUSB2_DEBUGIFC
 	bool "pvrusb2 debug interface"
 	depends on VIDEO_PVRUSB2_SYSFS
diff --git a/drivers/media/video/pvrusb2/Makefile b/drivers/media/video/pvrusb2/Makefile
index 47284e5..5b3083c 100644
--- a/drivers/media/video/pvrusb2/Makefile
+++ b/drivers/media/video/pvrusb2/Makefile
@@ -1,5 +1,6 @@
 obj-pvrusb2-sysfs-$(CONFIG_VIDEO_PVRUSB2_SYSFS) := pvrusb2-sysfs.o
 obj-pvrusb2-debugifc-$(CONFIG_VIDEO_PVRUSB2_DEBUGIFC) := pvrusb2-debugifc.o
+obj-pvrusb2-dvb-$(CONFIG_VIDEO_PVRUSB2_DVB) := pvrusb2-dvb.o
 
 pvrusb2-objs	:= pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \
 		   pvrusb2-audio.o pvrusb2-i2c-chips-v4l2.o \
@@ -9,6 +10,11 @@
 		   pvrusb2-ctrl.o pvrusb2-std.o pvrusb2-devattr.o \
 		   pvrusb2-context.o pvrusb2-io.o pvrusb2-ioread.o \
 		   pvrusb2-cx2584x-v4l.o pvrusb2-wm8775.o \
+		   $(obj-pvrusb2-dvb-y) \
 		   $(obj-pvrusb2-sysfs-y) $(obj-pvrusb2-debugifc-y)
 
 obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2.o
+
+EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c
index 160437b..b5db6a5 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-context.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-context.c
@@ -23,39 +23,193 @@
 #include "pvrusb2-ioread.h"
 #include "pvrusb2-hdw.h"
 #include "pvrusb2-debug.h"
+#include <linux/wait.h>
+#include <linux/kthread.h>
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 
+static struct pvr2_context *pvr2_context_exist_first;
+static struct pvr2_context *pvr2_context_exist_last;
+static struct pvr2_context *pvr2_context_notify_first;
+static struct pvr2_context *pvr2_context_notify_last;
+static DEFINE_MUTEX(pvr2_context_mutex);
+static DECLARE_WAIT_QUEUE_HEAD(pvr2_context_sync_data);
+static DECLARE_WAIT_QUEUE_HEAD(pvr2_context_cleanup_data);
+static int pvr2_context_cleanup_flag;
+static int pvr2_context_cleaned_flag;
+static struct task_struct *pvr2_context_thread_ptr;
+
+
+static void pvr2_context_set_notify(struct pvr2_context *mp, int fl)
+{
+	int signal_flag = 0;
+	mutex_lock(&pvr2_context_mutex);
+	if (fl) {
+		if (!mp->notify_flag) {
+			signal_flag = (pvr2_context_notify_first == NULL);
+			mp->notify_prev = pvr2_context_notify_last;
+			mp->notify_next = NULL;
+			pvr2_context_notify_last = mp;
+			if (mp->notify_prev) {
+				mp->notify_prev->notify_next = mp;
+			} else {
+				pvr2_context_notify_first = mp;
+			}
+			mp->notify_flag = !0;
+		}
+	} else {
+		if (mp->notify_flag) {
+			mp->notify_flag = 0;
+			if (mp->notify_next) {
+				mp->notify_next->notify_prev = mp->notify_prev;
+			} else {
+				pvr2_context_notify_last = mp->notify_prev;
+			}
+			if (mp->notify_prev) {
+				mp->notify_prev->notify_next = mp->notify_next;
+			} else {
+				pvr2_context_notify_first = mp->notify_next;
+			}
+		}
+	}
+	mutex_unlock(&pvr2_context_mutex);
+	if (signal_flag) wake_up(&pvr2_context_sync_data);
+}
+
 
 static void pvr2_context_destroy(struct pvr2_context *mp)
 {
-	pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr_main id=%p",mp);
+	pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (destroy)",mp);
 	if (mp->hdw) pvr2_hdw_destroy(mp->hdw);
+	pvr2_context_set_notify(mp, 0);
+	mutex_lock(&pvr2_context_mutex);
+	if (mp->exist_next) {
+		mp->exist_next->exist_prev = mp->exist_prev;
+	} else {
+		pvr2_context_exist_last = mp->exist_prev;
+	}
+	if (mp->exist_prev) {
+		mp->exist_prev->exist_next = mp->exist_next;
+	} else {
+		pvr2_context_exist_first = mp->exist_next;
+	}
+	if (!pvr2_context_exist_first) {
+		/* Trigger wakeup on control thread in case it is waiting
+		   for an exit condition. */
+		wake_up(&pvr2_context_sync_data);
+	}
+	mutex_unlock(&pvr2_context_mutex);
 	kfree(mp);
 }
 
 
-static void pvr2_context_state_check(struct pvr2_context *mp)
+static void pvr2_context_notify(struct pvr2_context *mp)
 {
-	if (mp->init_flag) return;
+	pvr2_context_set_notify(mp,!0);
+}
 
-	switch (pvr2_hdw_get_state(mp->hdw)) {
-	case PVR2_STATE_WARM: break;
-	case PVR2_STATE_ERROR: break;
-	case PVR2_STATE_READY: break;
-	case PVR2_STATE_RUN: break;
-	default: return;
+
+static void pvr2_context_check(struct pvr2_context *mp)
+{
+	struct pvr2_channel *ch1, *ch2;
+	pvr2_trace(PVR2_TRACE_CTXT,
+		   "pvr2_context %p (notify)", mp);
+	if (!mp->initialized_flag && !mp->disconnect_flag) {
+		mp->initialized_flag = !0;
+		pvr2_trace(PVR2_TRACE_CTXT,
+			   "pvr2_context %p (initialize)", mp);
+		/* Finish hardware initialization */
+		if (pvr2_hdw_initialize(mp->hdw,
+					(void (*)(void *))pvr2_context_notify,
+					mp)) {
+			mp->video_stream.stream =
+				pvr2_hdw_get_video_stream(mp->hdw);
+			/* Trigger interface initialization.  By doing this
+			   here initialization runs in our own safe and
+			   cozy thread context. */
+			if (mp->setup_func) mp->setup_func(mp);
+		} else {
+			pvr2_trace(PVR2_TRACE_CTXT,
+				   "pvr2_context %p (thread skipping setup)",
+				   mp);
+			/* Even though initialization did not succeed,
+			   we're still going to continue anyway.  We need
+			   to do this in order to await the expected
+			   disconnect (which we will detect in the normal
+			   course of operation). */
+		}
 	}
 
-	pvr2_context_enter(mp); do {
-		mp->init_flag = !0;
-		mp->video_stream.stream = pvr2_hdw_get_video_stream(mp->hdw);
-		if (mp->setup_func) {
-			mp->setup_func(mp);
+	for (ch1 = mp->mc_first; ch1; ch1 = ch2) {
+		ch2 = ch1->mc_next;
+		if (ch1->check_func) ch1->check_func(ch1);
+	}
+
+	if (mp->disconnect_flag && !mp->mc_first) {
+		/* Go away... */
+		pvr2_context_destroy(mp);
+		return;
+	}
+}
+
+
+static int pvr2_context_shutok(void)
+{
+	return pvr2_context_cleanup_flag && (pvr2_context_exist_first == NULL);
+}
+
+
+static int pvr2_context_thread_func(void *foo)
+{
+	struct pvr2_context *mp;
+
+	pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread start");
+
+	do {
+		while ((mp = pvr2_context_notify_first) != NULL) {
+			pvr2_context_set_notify(mp, 0);
+			pvr2_context_check(mp);
 		}
-	} while (0); pvr2_context_exit(mp);
- }
+		wait_event_interruptible(
+			pvr2_context_sync_data,
+			((pvr2_context_notify_first != NULL) ||
+			 pvr2_context_shutok()));
+	} while (!pvr2_context_shutok());
+
+	pvr2_context_cleaned_flag = !0;
+	wake_up(&pvr2_context_cleanup_data);
+
+	pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread cleaned up");
+
+	wait_event_interruptible(
+		pvr2_context_sync_data,
+		kthread_should_stop());
+
+	pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread end");
+
+	return 0;
+}
+
+
+int pvr2_context_global_init(void)
+{
+	pvr2_context_thread_ptr = kthread_run(pvr2_context_thread_func,
+					      0,
+					      "pvrusb2-context");
+	return (pvr2_context_thread_ptr ? 0 : -ENOMEM);
+}
+
+
+void pvr2_context_global_done(void)
+{
+	pvr2_context_cleanup_flag = !0;
+	wake_up(&pvr2_context_sync_data);
+	wait_event_interruptible(
+		pvr2_context_cleanup_data,
+		pvr2_context_cleaned_flag);
+	kthread_stop(pvr2_context_thread_ptr);
+}
 
 
 struct pvr2_context *pvr2_context_create(
@@ -66,67 +220,75 @@
 	struct pvr2_context *mp = NULL;
 	mp = kzalloc(sizeof(*mp),GFP_KERNEL);
 	if (!mp) goto done;
-	pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_main id=%p",mp);
+	pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (create)",mp);
 	mp->setup_func = setup_func;
 	mutex_init(&mp->mutex);
+	mutex_lock(&pvr2_context_mutex);
+	mp->exist_prev = pvr2_context_exist_last;
+	mp->exist_next = NULL;
+	pvr2_context_exist_last = mp;
+	if (mp->exist_prev) {
+		mp->exist_prev->exist_next = mp;
+	} else {
+		pvr2_context_exist_first = mp;
+	}
+	mutex_unlock(&pvr2_context_mutex);
 	mp->hdw = pvr2_hdw_create(intf,devid);
 	if (!mp->hdw) {
 		pvr2_context_destroy(mp);
 		mp = NULL;
 		goto done;
 	}
-	pvr2_hdw_set_state_callback(mp->hdw,
-				    (void (*)(void *))pvr2_context_state_check,
-				    mp);
-	pvr2_context_state_check(mp);
+	pvr2_context_set_notify(mp, !0);
  done:
 	return mp;
 }
 
 
-void pvr2_context_enter(struct pvr2_context *mp)
+static void pvr2_context_reset_input_limits(struct pvr2_context *mp)
 {
-	mutex_lock(&mp->mutex);
-	pvr2_trace(PVR2_TRACE_CREG,"pvr2_context_enter(id=%p)",mp);
+	unsigned int tmsk,mmsk;
+	struct pvr2_channel *cp;
+	struct pvr2_hdw *hdw = mp->hdw;
+	mmsk = pvr2_hdw_get_input_available(hdw);
+	tmsk = mmsk;
+	for (cp = mp->mc_first; cp; cp = cp->mc_next) {
+		if (!cp->input_mask) continue;
+		tmsk &= cp->input_mask;
+	}
+	pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk);
+	pvr2_hdw_commit_ctl(hdw);
 }
 
 
-void pvr2_context_exit(struct pvr2_context *mp)
+static void pvr2_context_enter(struct pvr2_context *mp)
+{
+	mutex_lock(&mp->mutex);
+}
+
+
+static void pvr2_context_exit(struct pvr2_context *mp)
 {
 	int destroy_flag = 0;
 	if (!(mp->mc_first || !mp->disconnect_flag)) {
 		destroy_flag = !0;
 	}
-	pvr2_trace(PVR2_TRACE_CREG,"pvr2_context_exit(id=%p) outside",mp);
 	mutex_unlock(&mp->mutex);
-	if (destroy_flag) pvr2_context_destroy(mp);
-}
-
-
-static void pvr2_context_run_checks(struct pvr2_context *mp)
-{
-	struct pvr2_channel *ch1,*ch2;
-	for (ch1 = mp->mc_first; ch1; ch1 = ch2) {
-		ch2 = ch1->mc_next;
-		if (ch1->check_func) {
-			ch1->check_func(ch1);
-		}
-	}
+	if (destroy_flag) pvr2_context_notify(mp);
 }
 
 
 void pvr2_context_disconnect(struct pvr2_context *mp)
 {
-	pvr2_context_enter(mp); do {
-		pvr2_hdw_disconnect(mp->hdw);
-		mp->disconnect_flag = !0;
-		pvr2_context_run_checks(mp);
-	} while (0); pvr2_context_exit(mp);
+	pvr2_hdw_disconnect(mp->hdw);
+	mp->disconnect_flag = !0;
+	pvr2_context_notify(mp);
 }
 
 
 void pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp)
 {
+	pvr2_context_enter(mp);
 	cp->hdw = mp->hdw;
 	cp->mc_head = mp;
 	cp->mc_next = NULL;
@@ -137,6 +299,7 @@
 		mp->mc_first = cp;
 	}
 	mp->mc_last = cp;
+	pvr2_context_exit(mp);
 }
 
 
@@ -152,7 +315,10 @@
 void pvr2_channel_done(struct pvr2_channel *cp)
 {
 	struct pvr2_context *mp = cp->mc_head;
+	pvr2_context_enter(mp);
+	cp->input_mask = 0;
 	pvr2_channel_disclaim_stream(cp);
+	pvr2_context_reset_input_limits(mp);
 	if (cp->mc_next) {
 		cp->mc_next->mc_prev = cp->mc_prev;
 	} else {
@@ -164,6 +330,58 @@
 		mp->mc_first = cp->mc_next;
 	}
 	cp->hdw = NULL;
+	pvr2_context_exit(mp);
+}
+
+
+int pvr2_channel_limit_inputs(struct pvr2_channel *cp,unsigned int cmsk)
+{
+	unsigned int tmsk,mmsk;
+	int ret = 0;
+	struct pvr2_channel *p2;
+	struct pvr2_hdw *hdw = cp->hdw;
+
+	mmsk = pvr2_hdw_get_input_available(hdw);
+	cmsk &= mmsk;
+	if (cmsk == cp->input_mask) {
+		/* No change; nothing to do */
+		return 0;
+	}
+
+	pvr2_context_enter(cp->mc_head);
+	do {
+		if (!cmsk) {
+			cp->input_mask = 0;
+			pvr2_context_reset_input_limits(cp->mc_head);
+			break;
+		}
+		tmsk = mmsk;
+		for (p2 = cp->mc_head->mc_first; p2; p2 = p2->mc_next) {
+			if (p2 == cp) continue;
+			if (!p2->input_mask) continue;
+			tmsk &= p2->input_mask;
+		}
+		if (!(tmsk & cmsk)) {
+			ret = -EPERM;
+			break;
+		}
+		tmsk &= cmsk;
+		if ((ret = pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk)) != 0) {
+			/* Internal failure changing allowed list; probably
+			   should not happen, but react if it does. */
+			break;
+		}
+		cp->input_mask = cmsk;
+		pvr2_hdw_commit_ctl(hdw);
+	} while (0);
+	pvr2_context_exit(cp->mc_head);
+	return ret;
+}
+
+
+unsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *cp)
+{
+	return cp->input_mask;
 }
 
 
@@ -173,7 +391,7 @@
 	int code = 0;
 	pvr2_context_enter(cp->mc_head); do {
 		if (sp == cp->stream) break;
-		if (sp->user) {
+		if (sp && sp->user) {
 			code = -EBUSY;
 			break;
 		}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.h b/drivers/media/video/pvrusb2/pvrusb2-context.h
index a04187a..745e270 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-context.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-context.h
@@ -30,7 +30,6 @@
 struct pvr2_context;        /* All central state */
 struct pvr2_channel;        /* One I/O pathway to a user */
 struct pvr2_context_stream; /* Wrapper for a stream */
-struct pvr2_crit_reg;       /* Critical region pointer */
 struct pvr2_ioread;         /* Low level stream structure */
 
 struct pvr2_context_stream {
@@ -41,11 +40,16 @@
 struct pvr2_context {
 	struct pvr2_channel *mc_first;
 	struct pvr2_channel *mc_last;
+	struct pvr2_context *exist_next;
+	struct pvr2_context *exist_prev;
+	struct pvr2_context *notify_next;
+	struct pvr2_context *notify_prev;
 	struct pvr2_hdw *hdw;
 	struct pvr2_context_stream video_stream;
 	struct mutex mutex;
+	int notify_flag;
+	int initialized_flag;
 	int disconnect_flag;
-	int init_flag;
 
 	/* Called after pvr2_context initialization is complete */
 	void (*setup_func)(struct pvr2_context *);
@@ -58,12 +62,10 @@
 	struct pvr2_channel *mc_prev;
 	struct pvr2_context_stream *stream;
 	struct pvr2_hdw *hdw;
+	unsigned int input_mask;
 	void (*check_func)(struct pvr2_channel *);
 };
 
-void pvr2_context_enter(struct pvr2_context *);
-void pvr2_context_exit(struct pvr2_context *);
-
 struct pvr2_context *pvr2_context_create(struct usb_interface *intf,
 					 const struct usb_device_id *devid,
 					 void (*setup_func)(struct pvr2_context *));
@@ -71,11 +73,15 @@
 
 void pvr2_channel_init(struct pvr2_channel *,struct pvr2_context *);
 void pvr2_channel_done(struct pvr2_channel *);
+int pvr2_channel_limit_inputs(struct pvr2_channel *,unsigned int);
+unsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *);
 int pvr2_channel_claim_stream(struct pvr2_channel *,
 			      struct pvr2_context_stream *);
 struct pvr2_ioread *pvr2_channel_create_mpeg_stream(
 	struct pvr2_context_stream *);
 
+int pvr2_context_global_init(void);
+void pvr2_context_global_done(void);
 
 #endif /* __PVRUSB2_CONTEXT_H */
 /*
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
index 5a3e8d2..91a42f2 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
@@ -30,6 +30,9 @@
 {
 	if (cptr->info->check_value) {
 		if (!cptr->info->check_value(cptr,val)) return -ERANGE;
+	} else if (cptr->info->type == pvr2_ctl_enum) {
+		if (val < 0) return -ERANGE;
+		if (val >= cptr->info->def.type_enum.count) return -ERANGE;
 	} else {
 		int lim;
 		lim = cptr->info->def.type_int.min_value;
@@ -63,13 +66,10 @@
 		if (cptr->info->set_value) {
 			if (cptr->info->type == pvr2_ctl_bitmask) {
 				mask &= cptr->info->def.type_bitmask.valid_bits;
-			} else if (cptr->info->type == pvr2_ctl_int) {
+			} else if ((cptr->info->type == pvr2_ctl_int)||
+				   (cptr->info->type == pvr2_ctl_enum)) {
 				ret = pvr2_ctrl_range_check(cptr,val);
 				if (ret < 0) break;
-			} else if (cptr->info->type == pvr2_ctl_enum) {
-				if (val >= cptr->info->def.type_enum.count) {
-					break;
-				}
 			} else if (cptr->info->type != pvr2_ctl_bool) {
 				break;
 			}
@@ -204,8 +204,7 @@
 		if (cptr->info->type == pvr2_ctl_enum) {
 			const char **names;
 			names = cptr->info->def.type_enum.value_names;
-			if ((val >= 0) &&
-			    (val < cptr->info->def.type_enum.count)) {
+			if (pvr2_ctrl_range_check(cptr,val) == 0) {
 				if (names[val]) {
 					*blen = scnprintf(
 						bptr,bmax,"%s",
@@ -528,10 +527,8 @@
 				ptr,len,valptr,
 				cptr->info->def.type_enum.value_names,
 				cptr->info->def.type_enum.count);
-			if ((ret >= 0) &&
-			    ((*valptr < 0) ||
-			     (*valptr >= cptr->info->def.type_enum.count))) {
-				ret = -ERANGE;
+			if (ret >= 0) {
+				ret = pvr2_ctrl_range_check(cptr,*valptr);
 			}
 			if (maskptr) *maskptr = ~0;
 		} else if (cptr->info->type == pvr2_ctl_bitmask) {
diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
index ffdc45c..97350b0 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
@@ -84,7 +84,9 @@
 		.vid = CX25840_COMPOSITE2,
 		.aud = CX25840_AUDIO5,
 	},
-	[PVR2_CVAL_INPUT_RADIO] = { /* Treat the same as composite */
+	[PVR2_CVAL_INPUT_RADIO] = {
+		/* line-in is used for radio and composite.  A GPIO is
+		   used to switch between the two choices. */
 		.vid = CX25840_COMPOSITE1,
 		.aud = CX25840_AUDIO_SERIAL,
 	},
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debug.h b/drivers/media/video/pvrusb2/pvrusb2-debug.h
index fca49d8..11537dd 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-debug.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-debug.h
@@ -39,7 +39,7 @@
 #define PVR2_TRACE_EEPROM     (1 << 10) /* eeprom parsing / report */
 #define PVR2_TRACE_STRUCT     (1 << 11) /* internal struct creation */
 #define PVR2_TRACE_OPEN_CLOSE (1 << 12) /* application open / close */
-#define PVR2_TRACE_CREG       (1 << 13) /* Main critical region entry / exit */
+#define PVR2_TRACE_CTXT       (1 << 13) /* Main context tracking */
 #define PVR2_TRACE_SYSFS      (1 << 14) /* Sysfs driven I/O */
 #define PVR2_TRACE_FIRMWARE   (1 << 15) /* firmware upload actions */
 #define PVR2_TRACE_CHIPS      (1 << 16) /* chip broadcast operation */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
index b068743..b53121c 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
@@ -164,6 +164,8 @@
 	int ccnt;
 	int ret;
 	u32 gpio_dir,gpio_in,gpio_out;
+	struct pvr2_stream_stats stats;
+	struct pvr2_stream *sp;
 
 	ret = pvr2_hdw_is_hsm(hdw);
 	ccnt = scnprintf(buf,acnt,"USB link speed: %s\n",
@@ -182,6 +184,24 @@
 			 pvr2_hdw_get_streaming(hdw) ? "on" : "off");
 	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 
+
+	sp = pvr2_hdw_get_video_stream(hdw);
+	if (sp) {
+		pvr2_stream_get_stats(sp, &stats, 0);
+		ccnt = scnprintf(
+			buf,acnt,
+			"Bytes streamed=%u"
+			" URBs: queued=%u idle=%u ready=%u"
+			" processed=%u failed=%u\n",
+			stats.bytes_processed,
+			stats.buffers_in_queue,
+			stats.buffers_in_idle,
+			stats.buffers_in_ready,
+			stats.buffers_processed,
+			stats.buffers_failed);
+		bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+	}
+
 	return bcnt;
 }
 
@@ -220,6 +240,10 @@
 			return pvr2_hdw_cmd_decoder_reset(hdw);
 		} else if (debugifc_match_keyword(wptr,wlen,"worker")) {
 			return pvr2_hdw_untrip(hdw);
+		} else if (debugifc_match_keyword(wptr,wlen,"usbstats")) {
+			pvr2_stream_get_stats(pvr2_hdw_get_video_stream(hdw),
+					      NULL, !0);
+			return 0;
 		}
 		return -EINVAL;
 	} else if (debugifc_match_keyword(wptr,wlen,"cpufw")) {
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
index fe9991c..2dd06a9 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
@@ -32,7 +32,15 @@
 /* This is needed in order to pull in tuner type ids... */
 #include <linux/i2c.h>
 #include <media/tuner.h>
-
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+#include "pvrusb2-hdw-internal.h"
+#include "lgdt330x.h"
+#include "s5h1409.h"
+#include "tda10048.h"
+#include "tda18271.h"
+#include "tda8290.h"
+#include "tuner-simple.h"
+#endif
 
 
 /*------------------------------------------------------------------------*/
@@ -49,14 +57,19 @@
 };
 
 static const struct pvr2_device_desc pvr2_device_29xxx = {
-		.description = "WinTV PVR USB2 Model Category 29xxxx",
+		.description = "WinTV PVR USB2 Model Category 29xxx",
 		.shortname = "29xxx",
 		.client_modules.lst = pvr2_client_29xxx,
 		.client_modules.cnt = ARRAY_SIZE(pvr2_client_29xxx),
 		.fx2_firmware.lst = pvr2_fw1_names_29xxx,
 		.fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_29xxx),
 		.flag_has_hauppauge_rom = !0,
+		.flag_has_analogtuner = !0,
+		.flag_has_fmradio = !0,
+		.flag_has_composite = !0,
+		.flag_has_svideo = !0,
 		.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+		.led_scheme = PVR2_LED_SCHEME_HAUPPAUGE,
 };
 
 
@@ -75,7 +88,7 @@
 };
 
 static const struct pvr2_device_desc pvr2_device_24xxx = {
-		.description = "WinTV PVR USB2 Model Category 24xxxx",
+		.description = "WinTV PVR USB2 Model Category 24xxx",
 		.shortname = "24xxx",
 		.client_modules.lst = pvr2_client_24xxx,
 		.client_modules.cnt = ARRAY_SIZE(pvr2_client_24xxx),
@@ -85,7 +98,12 @@
 		.flag_has_wm8775 = !0,
 		.flag_has_hauppauge_rom = !0,
 		.flag_has_hauppauge_custom_ir = !0,
+		.flag_has_analogtuner = !0,
+		.flag_has_fmradio = !0,
+		.flag_has_composite = !0,
+		.flag_has_svideo = !0,
 		.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+		.led_scheme = PVR2_LED_SCHEME_HAUPPAUGE,
 };
 
 
@@ -105,6 +123,30 @@
 		.client_modules.cnt = ARRAY_SIZE(pvr2_client_gotview_2),
 		.flag_has_cx25840 = !0,
 		.default_tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+		.flag_has_analogtuner = !0,
+		.flag_has_fmradio = !0,
+		.flag_has_composite = !0,
+		.flag_has_svideo = !0,
+		.signal_routing_scheme = PVR2_ROUTING_SCHEME_GOTVIEW,
+};
+
+
+
+/*------------------------------------------------------------------------*/
+/* GOTVIEW USB2.0 DVD Deluxe */
+
+/* (same module list as gotview_2) */
+
+static const struct pvr2_device_desc pvr2_device_gotview_2d = {
+		.description = "Gotview USB 2.0 DVD Deluxe",
+		.shortname = "gv2d",
+		.client_modules.lst = pvr2_client_gotview_2,
+		.client_modules.cnt = ARRAY_SIZE(pvr2_client_gotview_2),
+		.flag_has_cx25840 = !0,
+		.default_tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+		.flag_has_analogtuner = !0,
+		.flag_has_composite = !0,
+		.flag_has_svideo = !0,
 		.signal_routing_scheme = PVR2_ROUTING_SCHEME_GOTVIEW,
 };
 
@@ -114,6 +156,38 @@
 /*------------------------------------------------------------------------*/
 /* OnAir Creator */
 
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+static struct lgdt330x_config pvr2_lgdt3303_config = {
+	.demod_address       = 0x0e,
+	.demod_chip          = LGDT3303,
+	.clock_polarity_flip = 1,
+};
+
+static int pvr2_lgdt3303_attach(struct pvr2_dvb_adapter *adap)
+{
+	adap->fe = dvb_attach(lgdt330x_attach, &pvr2_lgdt3303_config,
+			      &adap->channel.hdw->i2c_adap);
+	if (adap->fe)
+		return 0;
+
+	return -EIO;
+}
+
+static int pvr2_lgh06xf_attach(struct pvr2_dvb_adapter *adap)
+{
+	dvb_attach(simple_tuner_attach, adap->fe,
+		   &adap->channel.hdw->i2c_adap, 0x61,
+		   TUNER_LG_TDVS_H06XF);
+
+	return 0;
+}
+
+struct pvr2_dvb_props pvr2_onair_creator_fe_props = {
+	.frontend_attach = pvr2_lgdt3303_attach,
+	.tuner_attach    = pvr2_lgh06xf_attach,
+};
+#endif
+
 static const char *pvr2_client_onair_creator[] = {
 	"saa7115",
 	"tuner",
@@ -126,7 +200,16 @@
 		.client_modules.lst = pvr2_client_onair_creator,
 		.client_modules.cnt = ARRAY_SIZE(pvr2_client_onair_creator),
 		.default_tuner_type = TUNER_LG_TDVS_H06XF,
+		.flag_has_analogtuner = !0,
+		.flag_has_composite = !0,
+		.flag_has_svideo = !0,
+		.flag_digital_requires_cx23416 = !0,
 		.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+		.digital_control_scheme = PVR2_DIGITAL_SCHEME_ONAIR,
+		.default_std_mask = V4L2_STD_NTSC_M,
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+		.dvb_props = &pvr2_onair_creator_fe_props,
+#endif
 };
 #endif
 
@@ -136,6 +219,37 @@
 /*------------------------------------------------------------------------*/
 /* OnAir USB 2.0 */
 
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+static struct lgdt330x_config pvr2_lgdt3302_config = {
+	.demod_address       = 0x0e,
+	.demod_chip          = LGDT3302,
+};
+
+static int pvr2_lgdt3302_attach(struct pvr2_dvb_adapter *adap)
+{
+	adap->fe = dvb_attach(lgdt330x_attach, &pvr2_lgdt3302_config,
+			      &adap->channel.hdw->i2c_adap);
+	if (adap->fe)
+		return 0;
+
+	return -EIO;
+}
+
+static int pvr2_fcv1236d_attach(struct pvr2_dvb_adapter *adap)
+{
+	dvb_attach(simple_tuner_attach, adap->fe,
+		   &adap->channel.hdw->i2c_adap, 0x61,
+		   TUNER_PHILIPS_FCV1236D);
+
+	return 0;
+}
+
+struct pvr2_dvb_props pvr2_onair_usb2_fe_props = {
+	.frontend_attach = pvr2_lgdt3302_attach,
+	.tuner_attach    = pvr2_fcv1236d_attach,
+};
+#endif
+
 static const char *pvr2_client_onair_usb2[] = {
 	"saa7115",
 	"tuner",
@@ -147,8 +261,17 @@
 		.shortname = "oa2",
 		.client_modules.lst = pvr2_client_onair_usb2,
 		.client_modules.cnt = ARRAY_SIZE(pvr2_client_onair_usb2),
-		.default_tuner_type = TUNER_PHILIPS_ATSC,
+		.default_tuner_type = TUNER_PHILIPS_FCV1236D,
+		.flag_has_analogtuner = !0,
+		.flag_has_composite = !0,
+		.flag_has_svideo = !0,
+		.flag_digital_requires_cx23416 = !0,
 		.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+		.digital_control_scheme = PVR2_DIGITAL_SCHEME_ONAIR,
+		.default_std_mask = V4L2_STD_NTSC_M,
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+		.dvb_props = &pvr2_onair_usb2_fe_props,
+#endif
 };
 #endif
 
@@ -157,6 +280,50 @@
 /*------------------------------------------------------------------------*/
 /* Hauppauge PVR-USB2 Model 73xxx */
 
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+static struct tda10048_config hauppauge_tda10048_config = {
+	.demod_address  = 0x10 >> 1,
+	.output_mode    = TDA10048_PARALLEL_OUTPUT,
+	.fwbulkwritelen = TDA10048_BULKWRITE_50,
+	.inversion      = TDA10048_INVERSION_ON,
+};
+
+static struct tda829x_config tda829x_no_probe = {
+	.probe_tuner = TDA829X_DONT_PROBE,
+};
+
+static struct tda18271_config hauppauge_tda18271_dvb_config = {
+	.gate    = TDA18271_GATE_ANALOG,
+};
+
+static int pvr2_tda10048_attach(struct pvr2_dvb_adapter *adap)
+{
+	adap->fe = dvb_attach(tda10048_attach, &hauppauge_tda10048_config,
+			      &adap->channel.hdw->i2c_adap);
+	if (adap->fe)
+		return 0;
+
+	return -EIO;
+}
+
+static int pvr2_73xxx_tda18271_8295_attach(struct pvr2_dvb_adapter *adap)
+{
+	dvb_attach(tda829x_attach, adap->fe,
+		   &adap->channel.hdw->i2c_adap, 0x42,
+		   &tda829x_no_probe);
+	dvb_attach(tda18271_attach, adap->fe, 0x60,
+		   &adap->channel.hdw->i2c_adap,
+		   &hauppauge_tda18271_dvb_config);
+
+	return 0;
+}
+
+struct pvr2_dvb_props pvr2_73xxx_dvb_props = {
+	.frontend_attach = pvr2_tda10048_attach,
+	.tuner_attach    = pvr2_73xxx_tda18271_8295_attach,
+};
+#endif
+
 static const char *pvr2_client_73xxx[] = {
 	"cx25840",
 	"tuner",
@@ -167,7 +334,7 @@
 };
 
 static const struct pvr2_device_desc pvr2_device_73xxx = {
-		.description = "WinTV PVR USB2 Model Category 73xxxx",
+		.description = "WinTV PVR USB2 Model Category 73xxx",
 		.shortname = "73xxx",
 		.client_modules.lst = pvr2_client_73xxx,
 		.client_modules.cnt = ARRAY_SIZE(pvr2_client_73xxx),
@@ -175,15 +342,14 @@
 		.fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_73xxx),
 		.flag_has_cx25840 = !0,
 		.flag_has_hauppauge_rom = !0,
-#if 0
 		.flag_has_analogtuner = !0,
 		.flag_has_composite = !0,
 		.flag_has_svideo = !0,
 		.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
 		.digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE,
 		.led_scheme = PVR2_LED_SCHEME_HAUPPAUGE,
-#else
-		.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+		.dvb_props = &pvr2_73xxx_dvb_props,
 #endif
 };
 
@@ -192,6 +358,56 @@
 /*------------------------------------------------------------------------*/
 /* Hauppauge PVR-USB2 Model 75xxx */
 
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+static struct s5h1409_config pvr2_s5h1409_config = {
+	.demod_address = 0x32 >> 1,
+	.output_mode   = S5H1409_PARALLEL_OUTPUT,
+	.gpio          = S5H1409_GPIO_OFF,
+	.qam_if        = 4000,
+	.inversion     = S5H1409_INVERSION_ON,
+	.status_mode   = S5H1409_DEMODLOCKING,
+};
+
+static struct tda18271_std_map hauppauge_tda18271_std_map = {
+	.atsc_6   = { .if_freq = 5380, .agc_mode = 3, .std = 3,
+		      .if_lvl = 6, .rfagc_top = 0x37, },
+	.qam_6    = { .if_freq = 4000, .agc_mode = 3, .std = 0,
+		      .if_lvl = 6, .rfagc_top = 0x37, },
+};
+
+static struct tda18271_config hauppauge_tda18271_config = {
+	.std_map = &hauppauge_tda18271_std_map,
+	.gate    = TDA18271_GATE_ANALOG,
+};
+
+static int pvr2_s5h1409_attach(struct pvr2_dvb_adapter *adap)
+{
+	adap->fe = dvb_attach(s5h1409_attach, &pvr2_s5h1409_config,
+			      &adap->channel.hdw->i2c_adap);
+	if (adap->fe)
+		return 0;
+
+	return -EIO;
+}
+
+static int pvr2_tda18271_8295_attach(struct pvr2_dvb_adapter *adap)
+{
+	dvb_attach(tda829x_attach, adap->fe,
+		   &adap->channel.hdw->i2c_adap, 0x42,
+		   &tda829x_no_probe);
+	dvb_attach(tda18271_attach, adap->fe, 0x60,
+		   &adap->channel.hdw->i2c_adap,
+		   &hauppauge_tda18271_config);
+
+	return 0;
+}
+
+struct pvr2_dvb_props pvr2_750xx_dvb_props = {
+	.frontend_attach = pvr2_s5h1409_attach,
+	.tuner_attach    = pvr2_tda18271_8295_attach,
+};
+#endif
+
 static const char *pvr2_client_75xxx[] = {
 	"cx25840",
 	"tuner",
@@ -201,17 +417,43 @@
 		"v4l-pvrusb2-73xxx-01.fw",
 };
 
-static const struct pvr2_device_desc pvr2_device_75xxx = {
-		.description = "WinTV PVR USB2 Model Category 75xxxx",
-		.shortname = "75xxx",
+static const struct pvr2_device_desc pvr2_device_750xx = {
+		.description = "WinTV PVR USB2 Model Category 750xx",
+		.shortname = "750xx",
 		.client_modules.lst = pvr2_client_75xxx,
 		.client_modules.cnt = ARRAY_SIZE(pvr2_client_75xxx),
 		.fx2_firmware.lst = pvr2_fw1_names_75xxx,
 		.fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_75xxx),
 		.flag_has_cx25840 = !0,
 		.flag_has_hauppauge_rom = !0,
+		.flag_has_analogtuner = !0,
+		.flag_has_composite = !0,
+		.flag_has_svideo = !0,
 		.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+		.digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE,
 		.default_std_mask = V4L2_STD_NTSC_M,
+		.led_scheme = PVR2_LED_SCHEME_HAUPPAUGE,
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+		.dvb_props = &pvr2_750xx_dvb_props,
+#endif
+};
+
+static const struct pvr2_device_desc pvr2_device_751xx = {
+		.description = "WinTV PVR USB2 Model Category 751xx",
+		.shortname = "751xx",
+		.client_modules.lst = pvr2_client_75xxx,
+		.client_modules.cnt = ARRAY_SIZE(pvr2_client_75xxx),
+		.fx2_firmware.lst = pvr2_fw1_names_75xxx,
+		.fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_75xxx),
+		.flag_has_cx25840 = !0,
+		.flag_has_hauppauge_rom = !0,
+		.flag_has_analogtuner = !0,
+		.flag_has_composite = !0,
+		.flag_has_svideo = !0,
+		.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+		.digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE,
+		.default_std_mask = V4L2_STD_NTSC_M,
+		.led_scheme = PVR2_LED_SCHEME_HAUPPAUGE,
 };
 
 
@@ -225,6 +467,8 @@
 	  .driver_info = (kernel_ulong_t)&pvr2_device_24xxx},
 	{ USB_DEVICE(0x1164, 0x0622),
 	  .driver_info = (kernel_ulong_t)&pvr2_device_gotview_2},
+	{ USB_DEVICE(0x1164, 0x0602),
+	  .driver_info = (kernel_ulong_t)&pvr2_device_gotview_2d},
 #ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR
 	{ USB_DEVICE(0x11ba, 0x1003),
 	  .driver_info = (kernel_ulong_t)&pvr2_device_onair_creator},
@@ -236,9 +480,9 @@
 	{ USB_DEVICE(0x2040, 0x7300),
 	  .driver_info = (kernel_ulong_t)&pvr2_device_73xxx},
 	{ USB_DEVICE(0x2040, 0x7500),
-	  .driver_info = (kernel_ulong_t)&pvr2_device_75xxx},
+	  .driver_info = (kernel_ulong_t)&pvr2_device_750xx},
 	{ USB_DEVICE(0x2040, 0x7501),
-	  .driver_info = (kernel_ulong_t)&pvr2_device_75xxx},
+	  .driver_info = (kernel_ulong_t)&pvr2_device_751xx},
 	{ }
 };
 
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/drivers/media/video/pvrusb2/pvrusb2-devattr.h
index 64b467f..c2e2b06 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-devattr.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.h
@@ -23,6 +23,9 @@
 
 #include <linux/mod_devicetable.h>
 #include <linux/videodev2.h>
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+#include "pvrusb2-dvb.h"
+#endif
 
 /*
 
@@ -39,6 +42,13 @@
 #define PVR2_ROUTING_SCHEME_HAUPPAUGE 0
 #define PVR2_ROUTING_SCHEME_GOTVIEW 1
 
+#define PVR2_DIGITAL_SCHEME_NONE 0
+#define PVR2_DIGITAL_SCHEME_HAUPPAUGE 1
+#define PVR2_DIGITAL_SCHEME_ONAIR 2
+
+#define PVR2_LED_SCHEME_NONE 0
+#define PVR2_LED_SCHEME_HAUPPAUGE 1
+
 /* This describes a particular hardware type (except for the USB device ID
    which must live in a separate structure due to environmental
    constraints).  See the top of pvrusb2-hdw.c for where this is
@@ -58,40 +68,64 @@
 	   was initialized from internal ROM. */
 	struct pvr2_string_table fx2_firmware;
 
-	/* Signal routing scheme used by device, contains one of
-	   PVR2_ROUTING_SCHEME_XXX.  Schemes have to be defined as we
-	   encounter them.  This is an arbitrary integer scheme id; its
-	   meaning is contained entirely within the driver and is
-	   interpreted by logic which must send commands to the chip-level
-	   drivers (search for things which touch this field). */
-	unsigned int signal_routing_scheme;
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+	/* callback functions to handle attachment of digital tuner & demod */
+	struct pvr2_dvb_props *dvb_props;
 
-	/* V4L tuner type ID to use with this device (only used if the
-	   driver could not discover the type any other way). */
-	int default_tuner_type;
-
+#endif
 	/* Initial standard bits to use for this device, if not zero.
 	   Anything set here is also implied as an available standard.
 	   Note: This is ignored if overridden on the module load line via
 	   the video_std module option. */
 	v4l2_std_id default_std_mask;
 
+	/* V4L tuner type ID to use with this device (only used if the
+	   driver could not discover the type any other way). */
+	int default_tuner_type;
+
+	/* Signal routing scheme used by device, contains one of
+	   PVR2_ROUTING_SCHEME_XXX.  Schemes have to be defined as we
+	   encounter them.  This is an arbitrary integer scheme id; its
+	   meaning is contained entirely within the driver and is
+	   interpreted by logic which must send commands to the chip-level
+	   drivers (search for things which touch this field). */
+	unsigned char signal_routing_scheme;
+
+	/* Indicates scheme for controlling device's LED (if any).  The
+	   driver will turn on the LED when streaming is underway.  This
+	   contains one of PVR2_LED_SCHEME_XXX. */
+	unsigned char led_scheme;
+
+	/* Control scheme to use if there is a digital tuner.  This
+	   contains one of PVR2_DIGITAL_SCHEME_XXX.  This is an arbitrary
+	   integer scheme id; its meaning is contained entirely within the
+	   driver and is interpreted by logic which must control the
+	   streaming pathway (search for things which touch this field). */
+	unsigned char digital_control_scheme;
+
 	/* If set, we don't bother trying to load cx23416 firmware. */
-	char flag_skip_cx23416_firmware;
+	int flag_skip_cx23416_firmware:1;
+
+	/* If set, the encoder must be healthy in order for digital mode to
+	   work (otherwise we assume that digital streaming will work even
+	   if we fail to locate firmware for the encoder).  If the device
+	   doesn't support digital streaming then this flag has no
+	   effect. */
+	int flag_digital_requires_cx23416:1;
 
 	/* Device has a hauppauge eeprom which we can interrogate. */
-	char flag_has_hauppauge_rom;
+	int flag_has_hauppauge_rom:1;
 
 	/* Device does not require a powerup command to be issued. */
-	char flag_no_powerup;
+	int flag_no_powerup:1;
 
 	/* Device has a cx25840 - this enables special additional logic to
 	   handle it. */
-	char flag_has_cx25840;
+	int flag_has_cx25840:1;
 
 	/* Device has a wm8775 - this enables special additional logic to
 	   ensure that it is found. */
-	char flag_has_wm8775;
+	int flag_has_wm8775:1;
 
 	/* Device has IR hardware that can be faked into looking like a
 	   normal Hauppauge i2c IR receiver.  This is currently very
@@ -101,7 +135,15 @@
 	   to virtualize the presence of the non-existant IR receiver chip and
 	   implement the virtual receiver in terms of appropriate FX2
 	   commands. */
-	char flag_has_hauppauge_custom_ir;
+	int flag_has_hauppauge_custom_ir:1;
+
+	/* These bits define which kinds of sources the device can handle.
+	   Note: Digital tuner presence is inferred by the
+	   digital_control_scheme enumeration. */
+	int flag_has_fmradio:1;       /* Has FM radio receiver */
+	int flag_has_analogtuner:1;   /* Has analog tuner */
+	int flag_has_composite:1;     /* Has composite input */
+	int flag_has_svideo:1;        /* Has s-video input */
 };
 
 extern struct usb_device_id pvr2_device_table[];
diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/drivers/media/video/pvrusb2/pvrusb2-dvb.c
new file mode 100644
index 0000000..2e64f98
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.c
@@ -0,0 +1,425 @@
+/*
+ *  pvrusb2-dvb.c - linux-dvb api interface to the pvrusb2 driver.
+ *
+ *  Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU 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/kthread.h>
+#include <linux/freezer.h>
+#include "dvbdev.h"
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-hdw.h"
+#include "pvrusb2-io.h"
+#include "pvrusb2-dvb.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int pvr2_dvb_feed_func(struct pvr2_dvb_adapter *adap)
+{
+	int ret;
+	unsigned int count;
+	struct pvr2_buffer *bp;
+	struct pvr2_stream *stream;
+
+	printk(KERN_DEBUG "dvb thread started\n");
+	set_freezable();
+
+	stream = adap->channel.stream->stream;
+
+	for (;;) {
+		if (kthread_should_stop()) break;
+
+		/* Not sure about this... */
+		try_to_freeze();
+
+		bp = pvr2_stream_get_ready_buffer(stream);
+		if (bp != NULL) {
+			count = pvr2_buffer_get_count(bp);
+			if (count) {
+				dvb_dmx_swfilter(
+					&adap->demux,
+					adap->buffer_storage[
+					    pvr2_buffer_get_id(bp)],
+					count);
+			} else {
+				ret = pvr2_buffer_get_status(bp);
+				if (ret < 0) break;
+			}
+			ret = pvr2_buffer_queue(bp);
+			if (ret < 0) break;
+
+			/* Since we know we did something to a buffer,
+			   just go back and try again.  No point in
+			   blocking unless we really ran out of
+			   buffers to process. */
+			continue;
+		}
+
+
+		/* Wait until more buffers become available or we're
+		   told not to wait any longer. */
+		ret = wait_event_interruptible(
+		    adap->buffer_wait_data,
+		    (pvr2_stream_get_ready_count(stream) > 0) ||
+		    kthread_should_stop());
+		if (ret < 0) break;
+	}
+
+	/* If we get here and ret is < 0, then an error has occurred.
+	   Probably would be a good idea to communicate that to DVB core... */
+
+	printk(KERN_DEBUG "dvb thread stopped\n");
+
+	return 0;
+}
+
+static int pvr2_dvb_feed_thread(void *data)
+{
+	int stat = pvr2_dvb_feed_func(data);
+	/* from videobuf-dvb.c: */
+	while (!kthread_should_stop()) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule();
+	}
+	return stat;
+}
+
+static void pvr2_dvb_notify(struct pvr2_dvb_adapter *adap)
+{
+	wake_up(&adap->buffer_wait_data);
+}
+
+static void pvr2_dvb_stream_end(struct pvr2_dvb_adapter *adap)
+{
+	unsigned int idx;
+	struct pvr2_stream *stream;
+
+	if (adap->thread) {
+		kthread_stop(adap->thread);
+		adap->thread = NULL;
+	}
+
+	if (adap->channel.stream) {
+		stream = adap->channel.stream->stream;
+	} else {
+		stream = NULL;
+	}
+	if (stream) {
+		pvr2_hdw_set_streaming(adap->channel.hdw, 0);
+		pvr2_stream_set_callback(stream, NULL, NULL);
+		pvr2_stream_kill(stream);
+		pvr2_stream_set_buffer_count(stream, 0);
+		pvr2_channel_claim_stream(&adap->channel, NULL);
+	}
+
+	if (adap->stream_run) {
+		for (idx = 0; idx < PVR2_DVB_BUFFER_COUNT; idx++) {
+			if (!(adap->buffer_storage[idx])) continue;
+			kfree(adap->buffer_storage[idx]);
+			adap->buffer_storage[idx] = 0;
+		}
+		adap->stream_run = 0;
+	}
+}
+
+static int pvr2_dvb_stream_do_start(struct pvr2_dvb_adapter *adap)
+{
+	struct pvr2_context *pvr = adap->channel.mc_head;
+	unsigned int idx;
+	int ret;
+	struct pvr2_buffer *bp;
+	struct pvr2_stream *stream = 0;
+
+	if (adap->stream_run) return -EIO;
+
+	ret = pvr2_channel_claim_stream(&adap->channel, &pvr->video_stream);
+	/* somebody else already has the stream */
+	if (ret < 0) return ret;
+
+	stream = adap->channel.stream->stream;
+
+	for (idx = 0; idx < PVR2_DVB_BUFFER_COUNT; idx++) {
+		adap->buffer_storage[idx] = kmalloc(PVR2_DVB_BUFFER_SIZE,
+						    GFP_KERNEL);
+		if (!(adap->buffer_storage[idx])) return -ENOMEM;
+	}
+
+	pvr2_stream_set_callback(pvr->video_stream.stream,
+				 (pvr2_stream_callback) pvr2_dvb_notify, adap);
+
+	ret = pvr2_stream_set_buffer_count(stream, PVR2_DVB_BUFFER_COUNT);
+	if (ret < 0) return ret;
+
+	for (idx = 0; idx < PVR2_DVB_BUFFER_COUNT; idx++) {
+		bp = pvr2_stream_get_buffer(stream, idx);
+		pvr2_buffer_set_buffer(bp,
+				       adap->buffer_storage[idx],
+				       PVR2_DVB_BUFFER_SIZE);
+	}
+
+	ret = pvr2_hdw_set_streaming(adap->channel.hdw, 1);
+	if (ret < 0) return ret;
+
+	while ((bp = pvr2_stream_get_idle_buffer(stream)) != 0) {
+		ret = pvr2_buffer_queue(bp);
+		if (ret < 0) return ret;
+	}
+
+	adap->thread = kthread_run(pvr2_dvb_feed_thread, adap, "pvrusb2-dvb");
+
+	if (IS_ERR(adap->thread)) {
+		ret = PTR_ERR(adap->thread);
+		adap->thread = NULL;
+		return ret;
+	}
+
+	adap->stream_run = !0;
+
+	return 0;
+}
+
+static int pvr2_dvb_stream_start(struct pvr2_dvb_adapter *adap)
+{
+	int ret = pvr2_dvb_stream_do_start(adap);
+	if (ret < 0) pvr2_dvb_stream_end(adap);
+	return ret;
+}
+
+static int pvr2_dvb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
+{
+	struct pvr2_dvb_adapter *adap = dvbdmxfeed->demux->priv;
+	int ret = 0;
+
+	if (adap == NULL) return -ENODEV;
+
+	mutex_lock(&adap->lock);
+	do {
+		if (onoff) {
+			if (!adap->feedcount) {
+				printk(KERN_DEBUG "start feeding\n");
+				ret = pvr2_dvb_stream_start(adap);
+				if (ret < 0) break;
+			}
+			(adap->feedcount)++;
+		} else if (adap->feedcount > 0) {
+			(adap->feedcount)--;
+			if (!adap->feedcount) {
+				printk(KERN_DEBUG "stop feeding\n");
+				pvr2_dvb_stream_end(adap);
+			}
+		}
+	} while (0);
+	mutex_unlock(&adap->lock);
+
+	return ret;
+}
+
+static int pvr2_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	printk(KERN_DEBUG "start pid: 0x%04x, feedtype: %d\n",
+	       dvbdmxfeed->pid, dvbdmxfeed->type);
+	return pvr2_dvb_ctrl_feed(dvbdmxfeed, 1);
+}
+
+static int pvr2_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	printk(KERN_DEBUG "stop pid: 0x%04x, feedtype: %d\n",
+	       dvbdmxfeed->pid, dvbdmxfeed->type);
+	return pvr2_dvb_ctrl_feed(dvbdmxfeed, 0);
+}
+
+static int pvr2_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
+{
+	struct pvr2_dvb_adapter *adap = fe->dvb->priv;
+	return pvr2_channel_limit_inputs(
+	    &adap->channel,
+	    (acquire ? (1 << PVR2_CVAL_INPUT_DTV) : 0));
+}
+
+static int pvr2_dvb_adapter_init(struct pvr2_dvb_adapter *adap)
+{
+	int ret;
+
+	ret = dvb_register_adapter(&adap->dvb_adap, "pvrusb2-dvb",
+				   THIS_MODULE/*&hdw->usb_dev->owner*/,
+				   &adap->channel.hdw->usb_dev->dev,
+				   adapter_nr);
+	if (ret < 0) {
+		err("dvb_register_adapter failed: error %d", ret);
+		goto err;
+	}
+	adap->dvb_adap.priv = adap;
+
+	adap->demux.dmx.capabilities = DMX_TS_FILTERING |
+				       DMX_SECTION_FILTERING |
+				       DMX_MEMORY_BASED_FILTERING;
+	adap->demux.priv             = adap;
+	adap->demux.filternum        = 256;
+	adap->demux.feednum          = 256;
+	adap->demux.start_feed       = pvr2_dvb_start_feed;
+	adap->demux.stop_feed        = pvr2_dvb_stop_feed;
+	adap->demux.write_to_decoder = NULL;
+
+	ret = dvb_dmx_init(&adap->demux);
+	if (ret < 0) {
+		err("dvb_dmx_init failed: error %d", ret);
+		goto err_dmx;
+	}
+
+	adap->dmxdev.filternum       = adap->demux.filternum;
+	adap->dmxdev.demux           = &adap->demux.dmx;
+	adap->dmxdev.capabilities    = 0;
+
+	ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap);
+	if (ret < 0) {
+		err("dvb_dmxdev_init failed: error %d", ret);
+		goto err_dmx_dev;
+	}
+
+	dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx);
+
+	return 0;
+
+err_dmx_dev:
+	dvb_dmx_release(&adap->demux);
+err_dmx:
+	dvb_unregister_adapter(&adap->dvb_adap);
+err:
+	return ret;
+}
+
+static int pvr2_dvb_adapter_exit(struct pvr2_dvb_adapter *adap)
+{
+	printk(KERN_DEBUG "unregistering DVB devices\n");
+	dvb_net_release(&adap->dvb_net);
+	adap->demux.dmx.close(&adap->demux.dmx);
+	dvb_dmxdev_release(&adap->dmxdev);
+	dvb_dmx_release(&adap->demux);
+	dvb_unregister_adapter(&adap->dvb_adap);
+	return 0;
+}
+
+static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap)
+{
+	struct pvr2_hdw *hdw = adap->channel.hdw;
+	struct pvr2_dvb_props *dvb_props = hdw->hdw_desc->dvb_props;
+	int ret = 0;
+
+	if (dvb_props == NULL) {
+		err("fe_props not defined!");
+		return -EINVAL;
+	}
+
+	ret = pvr2_channel_limit_inputs(
+	    &adap->channel,
+	    (1 << PVR2_CVAL_INPUT_DTV));
+	if (ret) {
+		err("failed to grab control of dtv input (code=%d)",
+		    ret);
+		return ret;
+	}
+
+	if (dvb_props->frontend_attach == NULL) {
+		err("frontend_attach not defined!");
+		ret = -EINVAL;
+		goto done;
+	}
+
+	if ((dvb_props->frontend_attach(adap) == 0) && (adap->fe)) {
+
+		if (dvb_register_frontend(&adap->dvb_adap, adap->fe)) {
+			err("frontend registration failed!");
+			dvb_frontend_detach(adap->fe);
+			adap->fe = NULL;
+			ret = -ENODEV;
+			goto done;
+		}
+
+		if (dvb_props->tuner_attach)
+			dvb_props->tuner_attach(adap);
+
+		if (adap->fe->ops.analog_ops.standby)
+			adap->fe->ops.analog_ops.standby(adap->fe);
+
+		/* Ensure all frontends negotiate bus access */
+		adap->fe->ops.ts_bus_ctrl = pvr2_dvb_bus_ctrl;
+
+	} else {
+		err("no frontend was attached!");
+		ret = -ENODEV;
+		return ret;
+	}
+
+ done:
+	pvr2_channel_limit_inputs(&adap->channel, 0);
+	return ret;
+}
+
+static int pvr2_dvb_frontend_exit(struct pvr2_dvb_adapter *adap)
+{
+	if (adap->fe != NULL) {
+		dvb_unregister_frontend(adap->fe);
+		dvb_frontend_detach(adap->fe);
+	}
+	return 0;
+}
+
+static void pvr2_dvb_destroy(struct pvr2_dvb_adapter *adap)
+{
+	pvr2_dvb_stream_end(adap);
+	pvr2_dvb_frontend_exit(adap);
+	pvr2_dvb_adapter_exit(adap);
+	pvr2_channel_done(&adap->channel);
+	kfree(adap);
+}
+
+static void pvr2_dvb_internal_check(struct pvr2_channel *chp)
+{
+	struct pvr2_dvb_adapter *adap;
+	adap = container_of(chp, struct pvr2_dvb_adapter, channel);
+	if (!adap->channel.mc_head->disconnect_flag) return;
+	pvr2_dvb_destroy(adap);
+}
+
+struct pvr2_dvb_adapter *pvr2_dvb_create(struct pvr2_context *pvr)
+{
+	int ret = 0;
+	struct pvr2_dvb_adapter *adap;
+	if (!pvr->hdw->hdw_desc->dvb_props) {
+		/* Device lacks a digital interface so don't set up
+		   the DVB side of the driver either.  For now. */
+		return NULL;
+	}
+	adap = kzalloc(sizeof(*adap), GFP_KERNEL);
+	if (!adap) return adap;
+	pvr2_channel_init(&adap->channel, pvr);
+	adap->channel.check_func = pvr2_dvb_internal_check;
+	init_waitqueue_head(&adap->buffer_wait_data);
+	mutex_init(&adap->lock);
+	ret = pvr2_dvb_adapter_init(adap);
+	if (ret < 0) goto fail1;
+	ret = pvr2_dvb_frontend_init(adap);
+	if (ret < 0) goto fail2;
+	return adap;
+
+fail2:
+	pvr2_dvb_adapter_exit(adap);
+fail1:
+	pvr2_channel_done(&adap->channel);
+	return NULL;
+}
+
diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.h b/drivers/media/video/pvrusb2/pvrusb2-dvb.h
new file mode 100644
index 0000000..884ff91
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.h
@@ -0,0 +1,41 @@
+#ifndef __PVRUSB2_DVB_H__
+#define __PVRUSB2_DVB_H__
+
+#include "dvb_frontend.h"
+#include "dvb_demux.h"
+#include "dvb_net.h"
+#include "dmxdev.h"
+#include "pvrusb2-context.h"
+
+#define PVR2_DVB_BUFFER_COUNT 32
+#define PVR2_DVB_BUFFER_SIZE PAGE_ALIGN(0x4000)
+
+struct pvr2_dvb_adapter {
+	struct pvr2_channel	channel;
+
+	struct dvb_adapter	dvb_adap;
+	struct dmxdev		dmxdev;
+	struct dvb_demux	demux;
+	struct dvb_net		dvb_net;
+	struct dvb_frontend	*fe;
+
+	int			feedcount;
+	int			max_feed_count;
+
+	struct task_struct	*thread;
+	struct mutex		lock;
+
+	unsigned int		stream_run:1;
+
+	wait_queue_head_t	buffer_wait_data;
+	char			*buffer_storage[PVR2_DVB_BUFFER_COUNT];
+};
+
+struct pvr2_dvb_props {
+	int (*frontend_attach) (struct pvr2_dvb_adapter *);
+	int (*tuner_attach) (struct pvr2_dvb_adapter *);
+};
+
+struct pvr2_dvb_adapter *pvr2_dvb_create(struct pvr2_context *pvr);
+
+#endif /* __PVRUSB2_DVB_H__ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
index 6406287..c46d367 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-encoder.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
@@ -278,11 +278,20 @@
 			ret = -EBUSY;
 		}
 		if (ret) {
+			del_timer_sync(&hdw->encoder_run_timer);
 			hdw->state_encoder_ok = 0;
 			pvr2_trace(PVR2_TRACE_STBITS,
 				   "State bit %s <-- %s",
 				   "state_encoder_ok",
 				   (hdw->state_encoder_ok ? "true" : "false"));
+			if (hdw->state_encoder_runok) {
+				hdw->state_encoder_runok = 0;
+				pvr2_trace(PVR2_TRACE_STBITS,
+				   "State bit %s <-- %s",
+					   "state_encoder_runok",
+					   (hdw->state_encoder_runok ?
+					    "true" : "false"));
+			}
 			pvr2_trace(
 				PVR2_TRACE_ERROR_LEGS,
 				"Giving up on command."
@@ -480,10 +489,6 @@
 	/* unmask some interrupts */
 	pvr2_write_register(hdw, 0x0048, 0xbfffffff);
 
-	/* change some GPIO data */
-	pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000481);
-	pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
-
 	pvr2_encoder_vcmd(hdw,CX2341X_ENC_MUTE_VIDEO,1,
 			  hdw->input_val == PVR2_CVAL_INPUT_RADIO ? 1 : 0);
 
@@ -526,12 +531,6 @@
 		break;
 	}
 
-	/* change some GPIO data */
-	/* Note: Bit d7 of dir appears to control the LED.  So we shut it
-	   off here. */
-	pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000401);
-	pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
-
 	return status;
 }
 
diff --git a/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h b/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h
index ffbc6d0..abaada3 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h
@@ -22,32 +22,41 @@
 #ifndef _PVRUSB2_FX2_CMD_H_
 #define _PVRUSB2_FX2_CMD_H_
 
-#define FX2CMD_MEM_WRITE_DWORD  0x01
-#define FX2CMD_MEM_READ_DWORD   0x02
+#define FX2CMD_MEM_WRITE_DWORD  0x01u
+#define FX2CMD_MEM_READ_DWORD   0x02u
 
-#define FX2CMD_MEM_READ_64BYTES 0x28
+#define FX2CMD_MEM_READ_64BYTES 0x28u
 
-#define FX2CMD_REG_WRITE        0x04
-#define FX2CMD_REG_READ         0x05
-#define FX2CMD_MEMSEL           0x06
+#define FX2CMD_REG_WRITE        0x04u
+#define FX2CMD_REG_READ         0x05u
+#define FX2CMD_MEMSEL           0x06u
 
-#define FX2CMD_I2C_WRITE        0x08
-#define FX2CMD_I2C_READ         0x09
+#define FX2CMD_I2C_WRITE        0x08u
+#define FX2CMD_I2C_READ         0x09u
 
-#define FX2CMD_GET_USB_SPEED    0x0b
+#define FX2CMD_GET_USB_SPEED    0x0bu
 
-#define FX2CMD_STREAMING_ON     0x36
-#define FX2CMD_STREAMING_OFF    0x37
+#define FX2CMD_STREAMING_ON     0x36u
+#define FX2CMD_STREAMING_OFF    0x37u
 
-#define FX2CMD_FWPOST1          0x52
+#define FX2CMD_FWPOST1          0x52u
 
-#define FX2CMD_POWER_OFF        0xdc
-#define FX2CMD_POWER_ON         0xde
+#define FX2CMD_POWER_OFF        0xdcu
+#define FX2CMD_POWER_ON         0xdeu
 
-#define FX2CMD_DEEP_RESET       0xdd
+#define FX2CMD_DEEP_RESET       0xddu
 
-#define FX2CMD_GET_EEPROM_ADDR  0xeb
-#define FX2CMD_GET_IR_CODE      0xec
+#define FX2CMD_GET_EEPROM_ADDR  0xebu
+#define FX2CMD_GET_IR_CODE      0xecu
+
+#define FX2CMD_HCW_DEMOD_RESETIN       0xf0u
+#define FX2CMD_HCW_DTV_STREAMING_ON    0xf1u
+#define FX2CMD_HCW_DTV_STREAMING_OFF   0xf2u
+
+#define FX2CMD_ONAIR_DTV_STREAMING_ON  0xa0u
+#define FX2CMD_ONAIR_DTV_STREAMING_OFF 0xa1u
+#define FX2CMD_ONAIR_DTV_POWER_ON      0xa2u
+#define FX2CMD_ONAIR_DTV_POWER_OFF     0xa3u
 
 #endif /* _PVRUSB2_FX2_CMD_H_ */
 
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index d7a216b..a3fe251 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -163,6 +163,11 @@
 #define FW1_STATE_RELOAD 3
 #define FW1_STATE_OK 4
 
+/* What state the device is in if it is a hybrid */
+#define PVR2_PATHWAY_UNKNOWN 0
+#define PVR2_PATHWAY_ANALOG 1
+#define PVR2_PATHWAY_DIGITAL 2
+
 typedef int (*pvr2_i2c_func)(struct pvr2_hdw *,u8,u8 *,u16,u8 *, u16);
 #define PVR2_I2C_FUNC_CNT 128
 
@@ -182,7 +187,6 @@
 	struct workqueue_struct *workqueue;
 	struct work_struct workpoll;     /* Update driver state */
 	struct work_struct worki2csync;  /* Update i2c clients */
-	struct work_struct workinit;     /* Driver initialization sequence */
 
 	/* Video spigot */
 	struct pvr2_stream *vid_stream;
@@ -229,17 +233,19 @@
 
 	/* Bits of state that describe what is going on with various parts
 	   of the driver. */
+	int state_pathway_ok;         /* Pathway config is ok */
 	int state_encoder_ok;         /* Encoder is operational */
 	int state_encoder_run;        /* Encoder is running */
 	int state_encoder_config;     /* Encoder is configured */
 	int state_encoder_waitok;     /* Encoder pre-wait done */
+	int state_encoder_runok;      /* Encoder has run for >= .25 sec */
 	int state_decoder_run;        /* Decoder is running */
 	int state_usbstream_run;      /* FX2 is streaming */
 	int state_decoder_quiescent;  /* Decoder idle for > 50msec */
 	int state_pipeline_config;    /* Pipeline is configured */
-	int state_pipeline_req;                /* Somebody wants to stream */
-	int state_pipeline_pause;              /* Pipeline must be paused */
-	int state_pipeline_idle;               /* Pipeline not running */
+	int state_pipeline_req;       /* Somebody wants to stream */
+	int state_pipeline_pause;     /* Pipeline must be paused */
+	int state_pipeline_idle;      /* Pipeline not running */
 
 	/* This is the master state of the driver.  It is the combined
 	   result of other bits of state.  Examining this will indicate the
@@ -247,6 +253,9 @@
 	   PVR2_STATE_xxxx */
 	unsigned int master_state;
 
+	/* True if device led is currently on */
+	int led_on;
+
 	/* True if states must be re-evaluated */
 	int state_stale;
 
@@ -259,6 +268,9 @@
 	/* Timer for measuring encoder pre-wait time */
 	struct timer_list encoder_wait_timer;
 
+	/* Timer for measuring encoder minimum run time */
+	struct timer_list encoder_run_timer;
+
 	/* Place to block while waiting for state changes */
 	wait_queue_head_t state_wait_data;
 
@@ -267,6 +279,7 @@
 	int flag_disconnected;  /* flag_ok == 0 due to disconnect */
 	int flag_init_ok;       /* true if structure is fully initialized */
 	int fw1_state;          /* current situation with fw1 */
+	int pathway_state;      /* one of PVR2_PATHWAY_xxx */
 	int flag_decoder_missed;/* We've noticed missing decoder */
 	int flag_tripped;       /* Indicates overall failure to start */
 
@@ -323,6 +336,11 @@
 	int v4l_minor_number_vbi;
 	int v4l_minor_number_radio;
 
+	/* Bit mask of PVR2_CVAL_INPUT choices which are valid for the hardware */
+	unsigned int input_avail_mask;
+	/* Bit mask of PVR2_CVAL_INPUT choices which are currenly allowed */
+	unsigned int input_allowed_mask;
+
 	/* Location of eeprom or a negative number if none */
 	int eeprom_addr;
 
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 2404053..0a86888 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -43,13 +43,13 @@
 static struct pvr2_hdw *unit_pointers[PVR_NUM] = {[ 0 ... PVR_NUM-1 ] = NULL};
 static DEFINE_MUTEX(pvr2_unit_mtx);
 
-static int ctlchg = 0;
+static int ctlchg;
 static int initusbreset = 1;
-static int procreload = 0;
+static int procreload;
 static int tuner[PVR_NUM] = { [0 ... PVR_NUM-1] = -1 };
 static int tolerance[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 };
 static int video_std[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 };
-static int init_pause_msec = 0;
+static int init_pause_msec;
 
 module_param(ctlchg, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(ctlchg, "0=optimize ctl change 1=always accept new ctl value");
@@ -182,6 +182,7 @@
 
 static const char *control_values_input[] = {
 	[PVR2_CVAL_INPUT_TV]        = "television",  /*xawtv needs this name*/
+	[PVR2_CVAL_INPUT_DTV]       = "dtv",
 	[PVR2_CVAL_INPUT_RADIO]     = "radio",
 	[PVR2_CVAL_INPUT_SVIDEO]    = "s-video",
 	[PVR2_CVAL_INPUT_COMPOSITE] = "composite",
@@ -215,12 +216,45 @@
 };
 
 
+struct pvr2_fx2cmd_descdef {
+	unsigned char id;
+	unsigned char *desc;
+};
+
+static const struct pvr2_fx2cmd_descdef pvr2_fx2cmd_desc[] = {
+	{FX2CMD_MEM_WRITE_DWORD, "write encoder dword"},
+	{FX2CMD_MEM_READ_DWORD, "read encoder dword"},
+	{FX2CMD_MEM_READ_64BYTES, "read encoder 64bytes"},
+	{FX2CMD_REG_WRITE, "write encoder register"},
+	{FX2CMD_REG_READ, "read encoder register"},
+	{FX2CMD_MEMSEL, "encoder memsel"},
+	{FX2CMD_I2C_WRITE, "i2c write"},
+	{FX2CMD_I2C_READ, "i2c read"},
+	{FX2CMD_GET_USB_SPEED, "get USB speed"},
+	{FX2CMD_STREAMING_ON, "stream on"},
+	{FX2CMD_STREAMING_OFF, "stream off"},
+	{FX2CMD_FWPOST1, "fwpost1"},
+	{FX2CMD_POWER_OFF, "power off"},
+	{FX2CMD_POWER_ON, "power on"},
+	{FX2CMD_DEEP_RESET, "deep reset"},
+	{FX2CMD_GET_EEPROM_ADDR, "get rom addr"},
+	{FX2CMD_GET_IR_CODE, "get IR code"},
+	{FX2CMD_HCW_DEMOD_RESETIN, "hcw demod resetin"},
+	{FX2CMD_HCW_DTV_STREAMING_ON, "hcw dtv stream on"},
+	{FX2CMD_HCW_DTV_STREAMING_OFF, "hcw dtv stream off"},
+	{FX2CMD_ONAIR_DTV_STREAMING_ON, "onair dtv stream on"},
+	{FX2CMD_ONAIR_DTV_STREAMING_OFF, "onair dtv stream off"},
+	{FX2CMD_ONAIR_DTV_POWER_ON, "onair dtv power on"},
+	{FX2CMD_ONAIR_DTV_POWER_OFF, "onair dtv power off"},
+};
+
+
+static int pvr2_hdw_set_input(struct pvr2_hdw *hdw,int v);
 static void pvr2_hdw_state_sched(struct pvr2_hdw *);
 static int pvr2_hdw_state_eval(struct pvr2_hdw *);
 static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long);
 static void pvr2_hdw_worker_i2c(struct work_struct *work);
 static void pvr2_hdw_worker_poll(struct work_struct *work);
-static void pvr2_hdw_worker_init(struct work_struct *work);
 static int pvr2_hdw_wait(struct pvr2_hdw *,int state);
 static int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *);
 static void pvr2_hdw_state_log_state(struct pvr2_hdw *);
@@ -231,6 +265,8 @@
 static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw);
 static void pvr2_hdw_quiescent_timeout(unsigned long);
 static void pvr2_hdw_encoder_wait_timeout(unsigned long);
+static void pvr2_hdw_encoder_run_timeout(unsigned long);
+static int pvr2_issue_simple_cmd(struct pvr2_hdw *,u32);
 static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
 				unsigned int timeout,int probe_fl,
 				void *write_data,unsigned int write_len,
@@ -367,26 +403,14 @@
 	return 0;
 }
 
+static int ctrl_check_input(struct pvr2_ctrl *cptr,int v)
+{
+	return ((1 << v) & cptr->hdw->input_allowed_mask) != 0;
+}
+
 static int ctrl_set_input(struct pvr2_ctrl *cptr,int m,int v)
 {
-	struct pvr2_hdw *hdw = cptr->hdw;
-
-	if (hdw->input_val != v) {
-		hdw->input_val = v;
-		hdw->input_dirty = !0;
-	}
-
-	/* Handle side effects - if we switch to a mode that needs the RF
-	   tuner, then select the right frequency choice as well and mark
-	   it dirty. */
-	if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
-		hdw->freqSelector = 0;
-		hdw->freqDirty = !0;
-	} else if (hdw->input_val == PVR2_CVAL_INPUT_TV) {
-		hdw->freqSelector = 1;
-		hdw->freqDirty = !0;
-	}
-	return 0;
+	return pvr2_hdw_set_input(cptr->hdw,v);
 }
 
 static int ctrl_isdirty_input(struct pvr2_ctrl *cptr)
@@ -803,6 +827,7 @@
 		.name = "input",
 		.internal_id = PVR2_CID_INPUT,
 		.default_value = PVR2_CVAL_INPUT_TV,
+		.check_value = ctrl_check_input,
 		DEFREF(input),
 		DEFENUM(control_values_input),
 	},{
@@ -982,7 +1007,7 @@
 
 /* Set the currently tuned frequency and account for all possible
    driver-core side effects of this action. */
-void pvr2_hdw_set_cur_freq(struct pvr2_hdw *hdw,unsigned long val)
+static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *hdw,unsigned long val)
 {
 	if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
 		if (hdw->freqSelector) {
@@ -1195,6 +1220,14 @@
 	   time we configure the encoder, then we'll fully configure it. */
 	hdw->enc_cur_valid = 0;
 
+	/* Encoder is about to be reset so note that as far as we're
+	   concerned now, the encoder has never been run. */
+	del_timer_sync(&hdw->encoder_run_timer);
+	if (hdw->state_encoder_runok) {
+		hdw->state_encoder_runok = 0;
+		trace_stbit("state_encoder_runok",hdw->state_encoder_runok);
+	}
+
 	/* First prepare firmware loading */
 	ret |= pvr2_write_register(hdw, 0x0048, 0xffffffff); /*interrupt mask*/
 	ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000088); /*gpio dir*/
@@ -1212,19 +1245,14 @@
 	ret |= pvr2_write_register(hdw, 0xaa04, 0x00057810); /*unknown*/
 	ret |= pvr2_write_register(hdw, 0xaa10, 0x00148500); /*unknown*/
 	ret |= pvr2_write_register(hdw, 0xaa18, 0x00840000); /*unknown*/
-	LOCK_TAKE(hdw->ctl_lock); do {
-		hdw->cmd_buffer[0] = FX2CMD_FWPOST1;
-		ret |= pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
-		hdw->cmd_buffer[0] = FX2CMD_MEMSEL;
-		hdw->cmd_buffer[1] = 0;
-		ret |= pvr2_send_request(hdw,hdw->cmd_buffer,2,NULL,0);
-	} while (0); LOCK_GIVE(hdw->ctl_lock);
+	ret |= pvr2_issue_simple_cmd(hdw,FX2CMD_FWPOST1);
+	ret |= pvr2_issue_simple_cmd(hdw,FX2CMD_MEMSEL | (1 << 8) | (0 << 16));
 
 	if (ret) {
 		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
 			   "firmware2 upload prep failed, ret=%d",ret);
 		release_firmware(fw_entry);
-		return ret;
+		goto done;
 	}
 
 	/* Now send firmware */
@@ -1237,7 +1265,8 @@
 			   " must be a multiple of %zu bytes",
 			   fw_files[fwidx],sizeof(u32));
 		release_firmware(fw_entry);
-		return -1;
+		ret = -EINVAL;
+		goto done;
 	}
 
 	fw_ptr = kmalloc(FIRMWARE_CHUNK_SIZE, GFP_KERNEL);
@@ -1245,7 +1274,8 @@
 		release_firmware(fw_entry);
 		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
 			   "failed to allocate memory for firmware2 upload");
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto done;
 	}
 
 	pipe = usb_sndbulkpipe(hdw->usb_dev, PVR2_FIRMWARE_ENDPOINT);
@@ -1276,23 +1306,27 @@
 	if (ret) {
 		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
 			   "firmware2 upload transfer failure");
-		return ret;
+		goto done;
 	}
 
 	/* Finish upload */
 
 	ret |= pvr2_write_register(hdw, 0x9054, 0xffffffff); /*reset hw blocks*/
 	ret |= pvr2_write_register(hdw, 0x9058, 0xffffffe8); /*VPU ctrl*/
-	LOCK_TAKE(hdw->ctl_lock); do {
-		hdw->cmd_buffer[0] = FX2CMD_MEMSEL;
-		hdw->cmd_buffer[1] = 0;
-		ret |= pvr2_send_request(hdw,hdw->cmd_buffer,2,NULL,0);
-	} while (0); LOCK_GIVE(hdw->ctl_lock);
+	ret |= pvr2_issue_simple_cmd(hdw,FX2CMD_MEMSEL | (1 << 8) | (0 << 16));
 
 	if (ret) {
 		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
 			   "firmware2 upload post-proc failure");
 	}
+
+ done:
+	if (hdw->hdw_desc->signal_routing_scheme ==
+	    PVR2_ROUTING_SCHEME_GOTVIEW) {
+		/* Ensure that GPIO 11 is set to output for GOTVIEW
+		   hardware. */
+		pvr2_hdw_gpio_chg_dir(hdw,(1 << 11),~0);
+	}
 	return ret;
 }
 
@@ -1364,11 +1398,6 @@
 }
 
 
-const char *pvr2_hdw_get_state_name(unsigned int id)
-{
-	if (id >= ARRAY_SIZE(pvr2_state_names)) return NULL;
-	return pvr2_state_names[id];
-}
 
 
 int pvr2_hdw_get_streaming(struct pvr2_hdw *hdw)
@@ -1495,7 +1524,7 @@
    default - which can always be overridden explicitly - and if the user
    has otherwise named a default then that default will always be used in
    place of this table. */
-const static struct pvr2_std_hack std_eeprom_maps[] = {
+static const struct pvr2_std_hack std_eeprom_maps[] = {
 	{	/* PAL(B/G) */
 		.pat = V4L2_STD_B|V4L2_STD_GH,
 		.std = V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_PAL_G,
@@ -1712,6 +1741,13 @@
 
 	if (!pvr2_hdw_dev_ok(hdw)) return;
 
+	if (hdw->hdw_desc->signal_routing_scheme ==
+	    PVR2_ROUTING_SCHEME_GOTVIEW) {
+		/* Ensure that GPIO 11 is set to output for GOTVIEW
+		   hardware. */
+		pvr2_hdw_gpio_chg_dir(hdw,(1 << 11),~0);
+	}
+
 	pvr2_hdw_commit_setup(hdw);
 
 	hdw->vid_stream = pvr2_stream_create();
@@ -1805,12 +1841,37 @@
 }
 
 
-/* Create and return a structure for interacting with the underlying
-   hardware */
+/* Perform second stage initialization.  Set callback pointer first so that
+   we can avoid a possible initialization race (if the kernel thread runs
+   before the callback has been set). */
+int pvr2_hdw_initialize(struct pvr2_hdw *hdw,
+			void (*callback_func)(void *),
+			void *callback_data)
+{
+	LOCK_TAKE(hdw->big_lock); do {
+		if (hdw->flag_disconnected) {
+			/* Handle a race here: If we're already
+			   disconnected by this point, then give up.  If we
+			   get past this then we'll remain connected for
+			   the duration of initialization since the entire
+			   initialization sequence is now protected by the
+			   big_lock. */
+			break;
+		}
+		hdw->state_data = callback_data;
+		hdw->state_func = callback_func;
+		pvr2_hdw_setup(hdw);
+	} while (0); LOCK_GIVE(hdw->big_lock);
+	return hdw->flag_init_ok;
+}
+
+
+/* Create, set up, and return a structure for interacting with the
+   underlying hardware.  */
 struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
 				 const struct usb_device_id *devid)
 {
-	unsigned int idx,cnt1,cnt2;
+	unsigned int idx,cnt1,cnt2,m;
 	struct pvr2_hdw *hdw;
 	int valid_std_mask;
 	struct pvr2_ctrl *cptr;
@@ -1834,6 +1895,10 @@
 	hdw->encoder_wait_timer.data = (unsigned long)hdw;
 	hdw->encoder_wait_timer.function = pvr2_hdw_encoder_wait_timeout;
 
+	init_timer(&hdw->encoder_run_timer);
+	hdw->encoder_run_timer.data = (unsigned long)hdw;
+	hdw->encoder_run_timer.function = pvr2_hdw_encoder_run_timeout;
+
 	hdw->master_state = PVR2_STATE_DEAD;
 
 	init_waitqueue_head(&hdw->state_wait_data);
@@ -1841,6 +1906,26 @@
 	hdw->tuner_signal_stale = !0;
 	cx2341x_fill_defaults(&hdw->enc_ctl_state);
 
+	/* Calculate which inputs are OK */
+	m = 0;
+	if (hdw_desc->flag_has_analogtuner) m |= 1 << PVR2_CVAL_INPUT_TV;
+	if (hdw_desc->digital_control_scheme != PVR2_DIGITAL_SCHEME_NONE) {
+		m |= 1 << PVR2_CVAL_INPUT_DTV;
+	}
+	if (hdw_desc->flag_has_svideo) m |= 1 << PVR2_CVAL_INPUT_SVIDEO;
+	if (hdw_desc->flag_has_composite) m |= 1 << PVR2_CVAL_INPUT_COMPOSITE;
+	if (hdw_desc->flag_has_fmradio) m |= 1 << PVR2_CVAL_INPUT_RADIO;
+	hdw->input_avail_mask = m;
+	hdw->input_allowed_mask = hdw->input_avail_mask;
+
+	/* If not a hybrid device, pathway_state never changes.  So
+	   initialize it here to what it should forever be. */
+	if (!(hdw->input_avail_mask & (1 << PVR2_CVAL_INPUT_DTV))) {
+		hdw->pathway_state = PVR2_PATHWAY_ANALOG;
+	} else if (!(hdw->input_avail_mask & (1 << PVR2_CVAL_INPUT_TV))) {
+		hdw->pathway_state = PVR2_PATHWAY_DIGITAL;
+	}
+
 	hdw->control_cnt = CTRLDEF_COUNT;
 	hdw->control_cnt += MPEGDEF_COUNT;
 	hdw->controls = kzalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt,
@@ -1858,6 +1943,15 @@
 		cptr = hdw->controls + idx;
 		cptr->info = control_defs+idx;
 	}
+
+	/* Ensure that default input choice is a valid one. */
+	m = hdw->input_avail_mask;
+	if (m) for (idx = 0; idx < (sizeof(m) << 3); idx++) {
+		if (!((1 << idx) & m)) continue;
+		hdw->input_val = idx;
+		break;
+	}
+
 	/* Define and configure additional controls from cx2341x module. */
 	hdw->mpeg_ctrl_info = kzalloc(
 		sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT, GFP_KERNEL);
@@ -1981,7 +2075,6 @@
 	hdw->workqueue = create_singlethread_workqueue(hdw->name);
 	INIT_WORK(&hdw->workpoll,pvr2_hdw_worker_poll);
 	INIT_WORK(&hdw->worki2csync,pvr2_hdw_worker_i2c);
-	INIT_WORK(&hdw->workinit,pvr2_hdw_worker_init);
 
 	pvr2_trace(PVR2_TRACE_INIT,"Driver unit number is %d, name is %s",
 		   hdw->unit_number,hdw->name);
@@ -2003,11 +2096,11 @@
 	mutex_init(&hdw->ctl_lock_mutex);
 	mutex_init(&hdw->big_lock_mutex);
 
-	queue_work(hdw->workqueue,&hdw->workinit);
 	return hdw;
  fail:
 	if (hdw) {
 		del_timer_sync(&hdw->quiescent_timer);
+		del_timer_sync(&hdw->encoder_run_timer);
 		del_timer_sync(&hdw->encoder_wait_timer);
 		if (hdw->workqueue) {
 			flush_workqueue(hdw->workqueue);
@@ -2064,13 +2157,14 @@
 {
 	if (!hdw) return;
 	pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_destroy: hdw=%p",hdw);
-	del_timer_sync(&hdw->quiescent_timer);
-	del_timer_sync(&hdw->encoder_wait_timer);
 	if (hdw->workqueue) {
 		flush_workqueue(hdw->workqueue);
 		destroy_workqueue(hdw->workqueue);
 		hdw->workqueue = NULL;
 	}
+	del_timer_sync(&hdw->quiescent_timer);
+	del_timer_sync(&hdw->encoder_run_timer);
+	del_timer_sync(&hdw->encoder_wait_timer);
 	if (hdw->fw_buffer) {
 		kfree(hdw->fw_buffer);
 		hdw->fw_buffer = NULL;
@@ -2352,6 +2446,18 @@
 		}
 	}
 
+	if (hdw->input_dirty && hdw->state_pathway_ok &&
+	    (((hdw->input_val == PVR2_CVAL_INPUT_DTV) ?
+	      PVR2_PATHWAY_DIGITAL : PVR2_PATHWAY_ANALOG) !=
+	     hdw->pathway_state)) {
+		/* Change of mode being asked for... */
+		hdw->state_pathway_ok = 0;
+		trace_stbit("state_pathway_ok",hdw->state_pathway_ok);
+	}
+	if (!hdw->state_pathway_ok) {
+		/* Can't commit anything until pathway is ok. */
+		return 0;
+	}
 	/* If any of the below has changed, then we can't do the update
 	   while the pipeline is running.  Pipeline must be paused first
 	   and decoder -> encoder connection be made quiescent before we
@@ -2405,12 +2511,28 @@
 		hdw->active_stream_type = hdw->desired_stream_type;
 	}
 
+	if (hdw->hdw_desc->signal_routing_scheme ==
+	    PVR2_ROUTING_SCHEME_GOTVIEW) {
+		u32 b;
+		/* Handle GOTVIEW audio switching */
+		pvr2_hdw_gpio_get_out(hdw,&b);
+		if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+			/* Set GPIO 11 */
+			pvr2_hdw_gpio_chg_out(hdw,(1 << 11),~0);
+		} else {
+			/* Clear GPIO 11 */
+			pvr2_hdw_gpio_chg_out(hdw,(1 << 11),0);
+		}
+	}
+
 	/* Now execute i2c core update */
 	pvr2_i2c_core_sync(hdw);
 
-	if (hdw->state_encoder_run) {
-		/* If encoder isn't running, then this will get worked out
-		   later when we start the encoder. */
+	if ((hdw->pathway_state == PVR2_PATHWAY_ANALOG) &&
+	    hdw->state_encoder_run) {
+		/* If encoder isn't running or it can't be touched, then
+		   this will get worked out later when we start the
+		   encoder. */
 		if (pvr2_encoder_adjust(hdw) < 0) return !0;
 	}
 
@@ -2453,15 +2575,6 @@
 }
 
 
-static void pvr2_hdw_worker_init(struct work_struct *work)
-{
-	struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,workinit);
-	LOCK_TAKE(hdw->big_lock); do {
-		pvr2_hdw_setup(hdw);
-	} while (0); LOCK_GIVE(hdw->big_lock);
-}
-
-
 static int pvr2_hdw_wait(struct pvr2_hdw *hdw,int state)
 {
 	return wait_event_interruptible(
@@ -2471,17 +2584,6 @@
 }
 
 
-void pvr2_hdw_set_state_callback(struct pvr2_hdw *hdw,
-				 void (*callback_func)(void *),
-				 void *callback_data)
-{
-	LOCK_TAKE(hdw->big_lock); do {
-		hdw->state_data = callback_data;
-		hdw->state_func = callback_func;
-	} while (0); LOCK_GIVE(hdw->big_lock);
-}
-
-
 /* Return name for this driver instance */
 const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw)
 {
@@ -3050,6 +3152,67 @@
 				    read_data,read_len);
 }
 
+
+static int pvr2_issue_simple_cmd(struct pvr2_hdw *hdw,u32 cmdcode)
+{
+	int ret;
+	unsigned int cnt = 1;
+	unsigned int args = 0;
+	LOCK_TAKE(hdw->ctl_lock);
+	hdw->cmd_buffer[0] = cmdcode & 0xffu;
+	args = (cmdcode >> 8) & 0xffu;
+	args = (args > 2) ? 2 : args;
+	if (args) {
+		cnt += args;
+		hdw->cmd_buffer[1] = (cmdcode >> 16) & 0xffu;
+		if (args > 1) {
+			hdw->cmd_buffer[2] = (cmdcode >> 24) & 0xffu;
+		}
+	}
+	if (pvrusb2_debug & PVR2_TRACE_INIT) {
+		unsigned int idx;
+		unsigned int ccnt,bcnt;
+		char tbuf[50];
+		cmdcode &= 0xffu;
+		bcnt = 0;
+		ccnt = scnprintf(tbuf+bcnt,
+				 sizeof(tbuf)-bcnt,
+				 "Sending FX2 command 0x%x",cmdcode);
+		bcnt += ccnt;
+		for (idx = 0; idx < ARRAY_SIZE(pvr2_fx2cmd_desc); idx++) {
+			if (pvr2_fx2cmd_desc[idx].id == cmdcode) {
+				ccnt = scnprintf(tbuf+bcnt,
+						 sizeof(tbuf)-bcnt,
+						 " \"%s\"",
+						 pvr2_fx2cmd_desc[idx].desc);
+				bcnt += ccnt;
+				break;
+			}
+		}
+		if (args) {
+			ccnt = scnprintf(tbuf+bcnt,
+					 sizeof(tbuf)-bcnt,
+					 " (%u",hdw->cmd_buffer[1]);
+			bcnt += ccnt;
+			if (args > 1) {
+				ccnt = scnprintf(tbuf+bcnt,
+						 sizeof(tbuf)-bcnt,
+						 ",%u",hdw->cmd_buffer[2]);
+				bcnt += ccnt;
+			}
+			ccnt = scnprintf(tbuf+bcnt,
+					 sizeof(tbuf)-bcnt,
+					 ")");
+			bcnt += ccnt;
+		}
+		pvr2_trace(PVR2_TRACE_INIT,"%.*s",bcnt,tbuf);
+	}
+	ret = pvr2_send_request(hdw,hdw->cmd_buffer,cnt,NULL,0);
+	LOCK_GIVE(hdw->ctl_lock);
+	return ret;
+}
+
+
 int pvr2_write_register(struct pvr2_hdw *hdw, u16 reg, u32 data)
 {
 	int ret;
@@ -3157,25 +3320,19 @@
 
 int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *hdw)
 {
-	int status;
-	LOCK_TAKE(hdw->ctl_lock); do {
-		pvr2_trace(PVR2_TRACE_INIT,"Requesting uproc hard reset");
-		hdw->cmd_buffer[0] = FX2CMD_DEEP_RESET;
-		status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
-	} while (0); LOCK_GIVE(hdw->ctl_lock);
-	return status;
+	return pvr2_issue_simple_cmd(hdw,FX2CMD_DEEP_RESET);
 }
 
 
 int pvr2_hdw_cmd_powerup(struct pvr2_hdw *hdw)
 {
-	int status;
-	LOCK_TAKE(hdw->ctl_lock); do {
-		pvr2_trace(PVR2_TRACE_INIT,"Requesting powerup");
-		hdw->cmd_buffer[0] = FX2CMD_POWER_ON;
-		status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
-	} while (0); LOCK_GIVE(hdw->ctl_lock);
-	return status;
+	return pvr2_issue_simple_cmd(hdw,FX2CMD_POWER_ON);
+}
+
+
+int pvr2_hdw_cmd_powerdown(struct pvr2_hdw *hdw)
+{
+	return pvr2_issue_simple_cmd(hdw,FX2CMD_POWER_OFF);
 }
 
 
@@ -3200,16 +3357,173 @@
 }
 
 
+static int pvr2_hdw_cmd_hcw_demod_reset(struct pvr2_hdw *hdw, int onoff)
+{
+	hdw->flag_ok = !0;
+	return pvr2_issue_simple_cmd(hdw,
+				     FX2CMD_HCW_DEMOD_RESETIN |
+				     (1 << 8) |
+				     ((onoff ? 1 : 0) << 16));
+}
+
+
+static int pvr2_hdw_cmd_onair_fe_power_ctrl(struct pvr2_hdw *hdw, int onoff)
+{
+	hdw->flag_ok = !0;
+	return pvr2_issue_simple_cmd(hdw,(onoff ?
+					  FX2CMD_ONAIR_DTV_POWER_ON :
+					  FX2CMD_ONAIR_DTV_POWER_OFF));
+}
+
+
+static int pvr2_hdw_cmd_onair_digital_path_ctrl(struct pvr2_hdw *hdw,
+						int onoff)
+{
+	return pvr2_issue_simple_cmd(hdw,(onoff ?
+					  FX2CMD_ONAIR_DTV_STREAMING_ON :
+					  FX2CMD_ONAIR_DTV_STREAMING_OFF));
+}
+
+
+static void pvr2_hdw_cmd_modeswitch(struct pvr2_hdw *hdw,int digitalFl)
+{
+	int cmode;
+	/* Compare digital/analog desired setting with current setting.  If
+	   they don't match, fix it... */
+	cmode = (digitalFl ? PVR2_PATHWAY_DIGITAL : PVR2_PATHWAY_ANALOG);
+	if (cmode == hdw->pathway_state) {
+		/* They match; nothing to do */
+		return;
+	}
+
+	switch (hdw->hdw_desc->digital_control_scheme) {
+	case PVR2_DIGITAL_SCHEME_HAUPPAUGE:
+		pvr2_hdw_cmd_hcw_demod_reset(hdw,digitalFl);
+		if (cmode == PVR2_PATHWAY_ANALOG) {
+			/* If moving to analog mode, also force the decoder
+			   to reset.  If no decoder is attached, then it's
+			   ok to ignore this because if/when the decoder
+			   attaches, it will reset itself at that time. */
+			pvr2_hdw_cmd_decoder_reset(hdw);
+		}
+		break;
+	case PVR2_DIGITAL_SCHEME_ONAIR:
+		/* Supposedly we should always have the power on whether in
+		   digital or analog mode.  But for now do what appears to
+		   work... */
+		pvr2_hdw_cmd_onair_fe_power_ctrl(hdw,digitalFl);
+		break;
+	default: break;
+	}
+
+	pvr2_hdw_untrip_unlocked(hdw);
+	hdw->pathway_state = cmode;
+}
+
+
+void pvr2_led_ctrl_hauppauge(struct pvr2_hdw *hdw, int onoff)
+{
+	/* change some GPIO data
+	 *
+	 * note: bit d7 of dir appears to control the LED,
+	 * so we shut it off here.
+	 *
+	 */
+	if (onoff) {
+		pvr2_hdw_gpio_chg_dir(hdw, 0xffffffff, 0x00000481);
+	} else {
+		pvr2_hdw_gpio_chg_dir(hdw, 0xffffffff, 0x00000401);
+	}
+	pvr2_hdw_gpio_chg_out(hdw, 0xffffffff, 0x00000000);
+}
+
+
+typedef void (*led_method_func)(struct pvr2_hdw *,int);
+
+static led_method_func led_methods[] = {
+	[PVR2_LED_SCHEME_HAUPPAUGE] = pvr2_led_ctrl_hauppauge,
+};
+
+
+/* Toggle LED */
+static void pvr2_led_ctrl(struct pvr2_hdw *hdw,int onoff)
+{
+	unsigned int scheme_id;
+	led_method_func fp;
+
+	if ((!onoff) == (!hdw->led_on)) return;
+
+	hdw->led_on = onoff != 0;
+
+	scheme_id = hdw->hdw_desc->led_scheme;
+	if (scheme_id < ARRAY_SIZE(led_methods)) {
+		fp = led_methods[scheme_id];
+	} else {
+		fp = NULL;
+	}
+
+	if (fp) (*fp)(hdw,onoff);
+}
+
+
 /* Stop / start video stream transport */
 static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl)
 {
-	int status;
-	LOCK_TAKE(hdw->ctl_lock); do {
-		hdw->cmd_buffer[0] =
-			(runFl ? FX2CMD_STREAMING_ON : FX2CMD_STREAMING_OFF);
-		status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
-	} while (0); LOCK_GIVE(hdw->ctl_lock);
-	return status;
+	int ret;
+
+	/* If we're in analog mode, then just issue the usual analog
+	   command. */
+	if (hdw->pathway_state == PVR2_PATHWAY_ANALOG) {
+		return pvr2_issue_simple_cmd(hdw,
+					     (runFl ?
+					      FX2CMD_STREAMING_ON :
+					      FX2CMD_STREAMING_OFF));
+		/*Note: Not reached */
+	}
+
+	if (hdw->pathway_state != PVR2_PATHWAY_DIGITAL) {
+		/* Whoops, we don't know what mode we're in... */
+		return -EINVAL;
+	}
+
+	/* To get here we have to be in digital mode.  The mechanism here
+	   is unfortunately different for different vendors.  So we switch
+	   on the device's digital scheme attribute in order to figure out
+	   what to do. */
+	switch (hdw->hdw_desc->digital_control_scheme) {
+	case PVR2_DIGITAL_SCHEME_HAUPPAUGE:
+		return pvr2_issue_simple_cmd(hdw,
+					     (runFl ?
+					      FX2CMD_HCW_DTV_STREAMING_ON :
+					      FX2CMD_HCW_DTV_STREAMING_OFF));
+	case PVR2_DIGITAL_SCHEME_ONAIR:
+		ret = pvr2_issue_simple_cmd(hdw,
+					    (runFl ?
+					     FX2CMD_STREAMING_ON :
+					     FX2CMD_STREAMING_OFF));
+		if (ret) return ret;
+		return pvr2_hdw_cmd_onair_digital_path_ctrl(hdw,runFl);
+	default:
+		return -EINVAL;
+	}
+}
+
+
+/* Evaluate whether or not state_pathway_ok can change */
+static int state_eval_pathway_ok(struct pvr2_hdw *hdw)
+{
+	if (hdw->state_pathway_ok) {
+		/* Nothing to do if pathway is already ok */
+		return 0;
+	}
+	if (!hdw->state_pipeline_idle) {
+		/* Not allowed to change anything if pipeline is not idle */
+		return 0;
+	}
+	pvr2_hdw_cmd_modeswitch(hdw,hdw->input_val == PVR2_CVAL_INPUT_DTV);
+	hdw->state_pathway_ok = !0;
+	trace_stbit("state_pathway_ok",hdw->state_pathway_ok);
+	return !0;
 }
 
 
@@ -3222,6 +3536,12 @@
 	if (hdw->state_encoder_config) return 0;
 	if (hdw->state_decoder_run) return 0;
 	if (hdw->state_usbstream_run) return 0;
+	if (hdw->pathway_state == PVR2_PATHWAY_DIGITAL) {
+		if (!hdw->hdw_desc->flag_digital_requires_cx23416) return 0;
+	} else if (hdw->pathway_state != PVR2_PATHWAY_ANALOG) {
+		return 0;
+	}
+
 	if (pvr2_upload_firmware2(hdw) < 0) {
 		hdw->flag_tripped = !0;
 		trace_stbit("flag_tripped",hdw->flag_tripped);
@@ -3247,7 +3567,9 @@
 		/* paranoia - solve race if timer just completed */
 		del_timer_sync(&hdw->encoder_wait_timer);
 	} else {
-		if (!hdw->state_encoder_ok ||
+		if (!hdw->state_pathway_ok ||
+		    (hdw->pathway_state != PVR2_PATHWAY_ANALOG) ||
+		    !hdw->state_encoder_ok ||
 		    !hdw->state_pipeline_idle ||
 		    hdw->state_pipeline_pause ||
 		    !hdw->state_pipeline_req ||
@@ -3296,20 +3618,116 @@
 }
 
 
+/* Return true if the encoder should not be running. */
+static int state_check_disable_encoder_run(struct pvr2_hdw *hdw)
+{
+	if (!hdw->state_encoder_ok) {
+		/* Encoder isn't healthy at the moment, so stop it. */
+		return !0;
+	}
+	if (!hdw->state_pathway_ok) {
+		/* Mode is not understood at the moment (i.e. it wants to
+		   change), so encoder must be stopped. */
+		return !0;
+	}
+
+	switch (hdw->pathway_state) {
+	case PVR2_PATHWAY_ANALOG:
+		if (!hdw->state_decoder_run) {
+			/* We're in analog mode and the decoder is not
+			   running; thus the encoder should be stopped as
+			   well. */
+			return !0;
+		}
+		break;
+	case PVR2_PATHWAY_DIGITAL:
+		if (hdw->state_encoder_runok) {
+			/* This is a funny case.  We're in digital mode so
+			   really the encoder should be stopped.  However
+			   if it really is running, only kill it after
+			   runok has been set.  This gives a chance for the
+			   onair quirk to function (encoder must run
+			   briefly first, at least once, before onair
+			   digital streaming can work). */
+			return !0;
+		}
+		break;
+	default:
+		/* Unknown mode; so encoder should be stopped. */
+		return !0;
+	}
+
+	/* If we get here, we haven't found a reason to stop the
+	   encoder. */
+	return 0;
+}
+
+
+/* Return true if the encoder should be running. */
+static int state_check_enable_encoder_run(struct pvr2_hdw *hdw)
+{
+	if (!hdw->state_encoder_ok) {
+		/* Don't run the encoder if it isn't healthy... */
+		return 0;
+	}
+	if (!hdw->state_pathway_ok) {
+		/* Don't run the encoder if we don't (yet) know what mode
+		   we need to be in... */
+		return 0;
+	}
+
+	switch (hdw->pathway_state) {
+	case PVR2_PATHWAY_ANALOG:
+		if (hdw->state_decoder_run) {
+			/* In analog mode, if the decoder is running, then
+			   run the encoder. */
+			return !0;
+		}
+		break;
+	case PVR2_PATHWAY_DIGITAL:
+		if ((hdw->hdw_desc->digital_control_scheme ==
+		     PVR2_DIGITAL_SCHEME_ONAIR) &&
+		    !hdw->state_encoder_runok) {
+			/* This is a quirk.  OnAir hardware won't stream
+			   digital until the encoder has been run at least
+			   once, for a minimal period of time (empiricially
+			   measured to be 1/4 second).  So if we're on
+			   OnAir hardware and the encoder has never been
+			   run at all, then start the encoder.  Normal
+			   state machine logic in the driver will
+			   automatically handle the remaining bits. */
+			return !0;
+		}
+		break;
+	default:
+		/* For completeness (unknown mode; encoder won't run ever) */
+		break;
+	}
+	/* If we get here, then we haven't found any reason to run the
+	   encoder, so don't run it. */
+	return 0;
+}
+
+
 /* Evaluate whether or not state_encoder_run can change */
 static int state_eval_encoder_run(struct pvr2_hdw *hdw)
 {
 	if (hdw->state_encoder_run) {
+		if (!state_check_disable_encoder_run(hdw)) return 0;
 		if (hdw->state_encoder_ok) {
-			if (hdw->state_decoder_run) return 0;
+			del_timer_sync(&hdw->encoder_run_timer);
 			if (pvr2_encoder_stop(hdw) < 0) return !0;
 		}
 		hdw->state_encoder_run = 0;
 	} else {
-		if (!hdw->state_encoder_ok) return 0;
-		if (!hdw->state_decoder_run) return 0;
+		if (!state_check_enable_encoder_run(hdw)) return 0;
 		if (pvr2_encoder_start(hdw) < 0) return !0;
 		hdw->state_encoder_run = !0;
+		if (!hdw->state_encoder_runok) {
+			hdw->encoder_run_timer.expires =
+				jiffies + (HZ*250/1000);
+			add_timer(&hdw->encoder_run_timer);
+		}
 	}
 	trace_stbit("state_encoder_run",hdw->state_encoder_run);
 	return !0;
@@ -3338,13 +3756,27 @@
 }
 
 
+/* Timeout function for encoder run timer. */
+static void pvr2_hdw_encoder_run_timeout(unsigned long data)
+{
+	struct pvr2_hdw *hdw = (struct pvr2_hdw *)data;
+	if (!hdw->state_encoder_runok) {
+		hdw->state_encoder_runok = !0;
+		trace_stbit("state_encoder_runok",hdw->state_encoder_runok);
+		hdw->state_stale = !0;
+		queue_work(hdw->workqueue,&hdw->workpoll);
+	}
+}
+
+
 /* Evaluate whether or not state_decoder_run can change */
 static int state_eval_decoder_run(struct pvr2_hdw *hdw)
 {
 	if (hdw->state_decoder_run) {
 		if (hdw->state_encoder_ok) {
 			if (hdw->state_pipeline_req &&
-			    !hdw->state_pipeline_pause) return 0;
+			    !hdw->state_pipeline_pause &&
+			    hdw->state_pathway_ok) return 0;
 		}
 		if (!hdw->flag_decoder_missed) {
 			pvr2_decoder_enable(hdw,0);
@@ -3377,7 +3809,9 @@
 			   hopefully further stabilize the encoder. */
 			return 0;
 		}
-		if (!hdw->state_pipeline_req ||
+		if (!hdw->state_pathway_ok ||
+		    (hdw->pathway_state != PVR2_PATHWAY_ANALOG) ||
+		    !hdw->state_pipeline_req ||
 		    hdw->state_pipeline_pause ||
 		    !hdw->state_pipeline_config ||
 		    !hdw->state_encoder_config ||
@@ -3398,16 +3832,43 @@
 static int state_eval_usbstream_run(struct pvr2_hdw *hdw)
 {
 	if (hdw->state_usbstream_run) {
-		if (hdw->state_encoder_ok) {
-			if (hdw->state_encoder_run) return 0;
+		int fl = !0;
+		if (hdw->pathway_state == PVR2_PATHWAY_ANALOG) {
+			fl = (hdw->state_encoder_ok &&
+			      hdw->state_encoder_run);
+		} else if ((hdw->pathway_state == PVR2_PATHWAY_DIGITAL) &&
+			   (hdw->hdw_desc->flag_digital_requires_cx23416)) {
+			fl = hdw->state_encoder_ok;
+		}
+		if (fl &&
+		    hdw->state_pipeline_req &&
+		    !hdw->state_pipeline_pause &&
+		    hdw->state_pathway_ok) {
+			return 0;
 		}
 		pvr2_hdw_cmd_usbstream(hdw,0);
 		hdw->state_usbstream_run = 0;
 	} else {
-		if (!hdw->state_encoder_ok ||
-		    !hdw->state_encoder_run ||
-		    !hdw->state_pipeline_req ||
-		    hdw->state_pipeline_pause) return 0;
+		if (!hdw->state_pipeline_req ||
+		    hdw->state_pipeline_pause ||
+		    !hdw->state_pathway_ok) return 0;
+		if (hdw->pathway_state == PVR2_PATHWAY_ANALOG) {
+			if (!hdw->state_encoder_ok ||
+			    !hdw->state_encoder_run) return 0;
+		} else if ((hdw->pathway_state == PVR2_PATHWAY_DIGITAL) &&
+			   (hdw->hdw_desc->flag_digital_requires_cx23416)) {
+			if (!hdw->state_encoder_ok) return 0;
+			if (hdw->state_encoder_run) return 0;
+			if (hdw->hdw_desc->digital_control_scheme ==
+			    PVR2_DIGITAL_SCHEME_ONAIR) {
+				/* OnAir digital receivers won't stream
+				   unless the analog encoder has run first.
+				   Why?  I have no idea.  But don't even
+				   try until we know the analog side is
+				   known to have run. */
+				if (!hdw->state_encoder_runok) return 0;
+			}
+		}
 		if (pvr2_hdw_cmd_usbstream(hdw,!0) < 0) return 0;
 		hdw->state_usbstream_run = !0;
 	}
@@ -3453,7 +3914,8 @@
 typedef int (*state_eval_func)(struct pvr2_hdw *);
 
 /* Set of functions to be run to evaluate various states in the driver. */
-const static state_eval_func eval_funcs[] = {
+static const state_eval_func eval_funcs[] = {
+	state_eval_pathway_ok,
 	state_eval_pipeline_config,
 	state_eval_encoder_ok,
 	state_eval_encoder_config,
@@ -3501,6 +3963,34 @@
 }
 
 
+static unsigned int print_input_mask(unsigned int msk,
+				     char *buf,unsigned int acnt)
+{
+	unsigned int idx,ccnt;
+	unsigned int tcnt = 0;
+	for (idx = 0; idx < ARRAY_SIZE(control_values_input); idx++) {
+		if (!((1 << idx) & msk)) continue;
+		ccnt = scnprintf(buf+tcnt,
+				 acnt-tcnt,
+				 "%s%s",
+				 (tcnt ? ", " : ""),
+				 control_values_input[idx]);
+		tcnt += ccnt;
+	}
+	return tcnt;
+}
+
+
+static const char *pvr2_pathway_state_name(int id)
+{
+	switch (id) {
+	case PVR2_PATHWAY_ANALOG: return "analog";
+	case PVR2_PATHWAY_DIGITAL: return "digital";
+	default: return "unknown";
+	}
+}
+
+
 static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which,
 					     char *buf,unsigned int acnt)
 {
@@ -3508,13 +3998,15 @@
 	case 0:
 		return scnprintf(
 			buf,acnt,
-			"driver:%s%s%s%s%s",
+			"driver:%s%s%s%s%s <mode=%s>",
 			(hdw->flag_ok ? " <ok>" : " <fail>"),
 			(hdw->flag_init_ok ? " <init>" : " <uninitialized>"),
 			(hdw->flag_disconnected ? " <disconnected>" :
 			 " <connected>"),
 			(hdw->flag_tripped ? " <tripped>" : ""),
-			(hdw->flag_decoder_missed ? " <no decoder>" : ""));
+			(hdw->flag_decoder_missed ? " <no decoder>" : ""),
+			pvr2_pathway_state_name(hdw->pathway_state));
+
 	case 1:
 		return scnprintf(
 			buf,acnt,
@@ -3527,7 +4019,7 @@
 	case 2:
 		return scnprintf(
 			buf,acnt,
-			"worker:%s%s%s%s%s%s",
+			"worker:%s%s%s%s%s%s%s",
 			(hdw->state_decoder_run ?
 			 " <decode:run>" :
 			 (hdw->state_decoder_quiescent ?
@@ -3537,20 +4029,65 @@
 			(hdw->state_encoder_ok ?
 			 "" : " <encode:init>"),
 			(hdw->state_encoder_run ?
-			 " <encode:run>" : " <encode:stop>"),
+			 (hdw->state_encoder_runok ?
+			  " <encode:run>" :
+			  " <encode:firstrun>") :
+			 (hdw->state_encoder_runok ?
+			  " <encode:stop>" :
+			  " <encode:virgin>")),
 			(hdw->state_encoder_config ?
 			 " <encode:configok>" :
 			 (hdw->state_encoder_waitok ?
-			  "" : " <encode:wait>")),
+			  "" : " <encode:waitok>")),
 			(hdw->state_usbstream_run ?
-			 " <usb:run>" : " <usb:stop>"));
-		break;
+			 " <usb:run>" : " <usb:stop>"),
+			(hdw->state_pathway_ok ?
+			 " <pathway:ok>" : ""));
 	case 3:
 		return scnprintf(
 			buf,acnt,
 			"state: %s",
 			pvr2_get_state_name(hdw->master_state));
-		break;
+	case 4: {
+		unsigned int tcnt = 0;
+		unsigned int ccnt;
+
+		ccnt = scnprintf(buf,
+				 acnt,
+				 "Hardware supported inputs: ");
+		tcnt += ccnt;
+		tcnt += print_input_mask(hdw->input_avail_mask,
+					 buf+tcnt,
+					 acnt-tcnt);
+		if (hdw->input_avail_mask != hdw->input_allowed_mask) {
+			ccnt = scnprintf(buf+tcnt,
+					 acnt-tcnt,
+					 "; allowed inputs: ");
+			tcnt += ccnt;
+			tcnt += print_input_mask(hdw->input_allowed_mask,
+						 buf+tcnt,
+						 acnt-tcnt);
+		}
+		return tcnt;
+	}
+	case 5: {
+		struct pvr2_stream_stats stats;
+		if (!hdw->vid_stream) break;
+		pvr2_stream_get_stats(hdw->vid_stream,
+				      &stats,
+				      0);
+		return scnprintf(
+			buf,acnt,
+			"Bytes streamed=%u"
+			" URBs: queued=%u idle=%u ready=%u"
+			" processed=%u failed=%u",
+			stats.bytes_processed,
+			stats.buffers_in_queue,
+			stats.buffers_in_idle,
+			stats.buffers_in_ready,
+			stats.buffers_processed,
+			stats.buffers_failed);
+	}
 	default: break;
 	}
 	return 0;
@@ -3596,6 +4133,7 @@
 	unsigned int st;
 	int state_updated = 0;
 	int callback_flag = 0;
+	int analog_mode;
 
 	pvr2_trace(PVR2_TRACE_STBITS,
 		   "Drive state check START");
@@ -3606,18 +4144,23 @@
 	/* Process all state and get back over disposition */
 	state_updated = pvr2_hdw_state_update(hdw);
 
+	analog_mode = (hdw->pathway_state != PVR2_PATHWAY_DIGITAL);
+
 	/* Update master state based upon all other states. */
 	if (!hdw->flag_ok) {
 		st = PVR2_STATE_DEAD;
 	} else if (hdw->fw1_state != FW1_STATE_OK) {
 		st = PVR2_STATE_COLD;
-	} else if (!hdw->state_encoder_ok) {
+	} else if ((analog_mode ||
+		    hdw->hdw_desc->flag_digital_requires_cx23416) &&
+		   !hdw->state_encoder_ok) {
 		st = PVR2_STATE_WARM;
-	} else if (hdw->flag_tripped || hdw->flag_decoder_missed) {
+	} else if (hdw->flag_tripped ||
+		   (analog_mode && hdw->flag_decoder_missed)) {
 		st = PVR2_STATE_ERROR;
-	} else if (hdw->state_encoder_run &&
-		   hdw->state_decoder_run &&
-		   hdw->state_usbstream_run) {
+	} else if (hdw->state_usbstream_run &&
+		   (!analog_mode ||
+		    (hdw->state_encoder_run && hdw->state_decoder_run))) {
 		st = PVR2_STATE_RUN;
 	} else {
 		st = PVR2_STATE_READY;
@@ -3627,6 +4170,7 @@
 			   "Device state change from %s to %s",
 			   pvr2_get_state_name(hdw->master_state),
 			   pvr2_get_state_name(st));
+		pvr2_led_ctrl(hdw,st == PVR2_STATE_RUN);
 		hdw->master_state = st;
 		state_updated = !0;
 		callback_flag = !0;
@@ -3656,47 +4200,6 @@
 }
 
 
-void pvr2_hdw_get_debug_info_unlocked(const struct pvr2_hdw *hdw,
-				      struct pvr2_hdw_debug_info *ptr)
-{
-	ptr->big_lock_held = hdw->big_lock_held;
-	ptr->ctl_lock_held = hdw->ctl_lock_held;
-	ptr->flag_disconnected = hdw->flag_disconnected;
-	ptr->flag_init_ok = hdw->flag_init_ok;
-	ptr->flag_ok = hdw->flag_ok;
-	ptr->fw1_state = hdw->fw1_state;
-	ptr->flag_decoder_missed = hdw->flag_decoder_missed;
-	ptr->flag_tripped = hdw->flag_tripped;
-	ptr->state_encoder_ok = hdw->state_encoder_ok;
-	ptr->state_encoder_run = hdw->state_encoder_run;
-	ptr->state_decoder_run = hdw->state_decoder_run;
-	ptr->state_usbstream_run = hdw->state_usbstream_run;
-	ptr->state_decoder_quiescent = hdw->state_decoder_quiescent;
-	ptr->state_pipeline_config = hdw->state_pipeline_config;
-	ptr->state_pipeline_req = hdw->state_pipeline_req;
-	ptr->state_pipeline_pause = hdw->state_pipeline_pause;
-	ptr->state_pipeline_idle = hdw->state_pipeline_idle;
-	ptr->cmd_debug_state = hdw->cmd_debug_state;
-	ptr->cmd_code = hdw->cmd_debug_code;
-	ptr->cmd_debug_write_len = hdw->cmd_debug_write_len;
-	ptr->cmd_debug_read_len = hdw->cmd_debug_read_len;
-	ptr->cmd_debug_timeout = hdw->ctl_timeout_flag;
-	ptr->cmd_debug_write_pend = hdw->ctl_write_pend_flag;
-	ptr->cmd_debug_read_pend = hdw->ctl_read_pend_flag;
-	ptr->cmd_debug_rstatus = hdw->ctl_read_urb->status;
-	ptr->cmd_debug_wstatus = hdw->ctl_read_urb->status;
-}
-
-
-void pvr2_hdw_get_debug_info_locked(struct pvr2_hdw *hdw,
-				    struct pvr2_hdw_debug_info *ptr)
-{
-	LOCK_TAKE(hdw->ctl_lock); do {
-		pvr2_hdw_get_debug_info_unlocked(hdw,ptr);
-	} while(0); LOCK_GIVE(hdw->ctl_lock);
-}
-
-
 int pvr2_hdw_gpio_get_dir(struct pvr2_hdw *hdw,u32 *dp)
 {
 	return pvr2_read_register(hdw,PVR2_GPIO_DIR,dp);
@@ -3756,6 +4259,80 @@
 }
 
 
+unsigned int pvr2_hdw_get_input_available(struct pvr2_hdw *hdw)
+{
+	return hdw->input_avail_mask;
+}
+
+
+unsigned int pvr2_hdw_get_input_allowed(struct pvr2_hdw *hdw)
+{
+	return hdw->input_allowed_mask;
+}
+
+
+static int pvr2_hdw_set_input(struct pvr2_hdw *hdw,int v)
+{
+	if (hdw->input_val != v) {
+		hdw->input_val = v;
+		hdw->input_dirty = !0;
+	}
+
+	/* Handle side effects - if we switch to a mode that needs the RF
+	   tuner, then select the right frequency choice as well and mark
+	   it dirty. */
+	if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+		hdw->freqSelector = 0;
+		hdw->freqDirty = !0;
+	} else if ((hdw->input_val == PVR2_CVAL_INPUT_TV) ||
+		   (hdw->input_val == PVR2_CVAL_INPUT_DTV)) {
+		hdw->freqSelector = 1;
+		hdw->freqDirty = !0;
+	}
+	return 0;
+}
+
+
+int pvr2_hdw_set_input_allowed(struct pvr2_hdw *hdw,
+			       unsigned int change_mask,
+			       unsigned int change_val)
+{
+	int ret = 0;
+	unsigned int nv,m,idx;
+	LOCK_TAKE(hdw->big_lock);
+	do {
+		nv = hdw->input_allowed_mask & ~change_mask;
+		nv |= (change_val & change_mask);
+		nv &= hdw->input_avail_mask;
+		if (!nv) {
+			/* No legal modes left; return error instead. */
+			ret = -EPERM;
+			break;
+		}
+		hdw->input_allowed_mask = nv;
+		if ((1 << hdw->input_val) & hdw->input_allowed_mask) {
+			/* Current mode is still in the allowed mask, so
+			   we're done. */
+			break;
+		}
+		/* Select and switch to a mode that is still in the allowed
+		   mask */
+		if (!hdw->input_allowed_mask) {
+			/* Nothing legal; give up */
+			break;
+		}
+		m = hdw->input_allowed_mask;
+		for (idx = 0; idx < (sizeof(m) << 3); idx++) {
+			if (!((1 << idx) & m)) continue;
+			pvr2_hdw_set_input(hdw,idx);
+			break;
+		}
+	} while (0);
+	LOCK_GIVE(hdw->big_lock);
+	return ret;
+}
+
+
 /* Find I2C address of eeprom */
 static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw)
 {
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
index 3ad7a13..20295e0 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
@@ -40,9 +40,10 @@
 
 /* Legal values for the INPUT state variable */
 #define PVR2_CVAL_INPUT_TV 0
-#define PVR2_CVAL_INPUT_SVIDEO 1
+#define PVR2_CVAL_INPUT_DTV 1
 #define PVR2_CVAL_INPUT_COMPOSITE 2
-#define PVR2_CVAL_INPUT_RADIO 3
+#define PVR2_CVAL_INPUT_SVIDEO 3
+#define PVR2_CVAL_INPUT_RADIO 4
 
 enum pvr2_config {
 	pvr2_config_empty,    /* No configuration */
@@ -90,9 +91,6 @@
 /* Translate configuration enum to a string label */
 const char *pvr2_config_get_name(enum pvr2_config);
 
-/* Translate a master state enum to a string label */
-const char *pvr2_hdw_get_state_name(unsigned int);
-
 struct pvr2_hdw;
 
 /* Create and return a structure for interacting with the underlying
@@ -100,14 +98,15 @@
 struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
 				 const struct usb_device_id *devid);
 
+/* Perform second stage initialization, passing in a notification callback
+   for when the master state changes. */
+int pvr2_hdw_initialize(struct pvr2_hdw *,
+			void (*callback_func)(void *),
+			void *callback_data);
+
 /* Destroy hardware interaction structure */
 void pvr2_hdw_destroy(struct pvr2_hdw *);
 
-/* Register a function to be called whenever the master state changes. */
-void pvr2_hdw_set_state_callback(struct pvr2_hdw *,
-				 void (*callback_func)(void *),
-				 void *callback_data);
-
 /* Return true if in the ready (normal) state */
 int pvr2_hdw_dev_ok(struct pvr2_hdw *);
 
@@ -146,6 +145,23 @@
 /* Commit all control changes made up to this point */
 int pvr2_hdw_commit_ctl(struct pvr2_hdw *);
 
+/* Return a bit mask of valid input selections for this device.  Mask bits
+ * will be according to PVR_CVAL_INPUT_xxxx definitions. */
+unsigned int pvr2_hdw_get_input_available(struct pvr2_hdw *);
+
+/* Return a bit mask of allowed input selections for this device.  Mask bits
+ * will be according to PVR_CVAL_INPUT_xxxx definitions. */
+unsigned int pvr2_hdw_get_input_allowed(struct pvr2_hdw *);
+
+/* Change the set of allowed input selections for this device.  Both
+   change_mask and change_valu are mask bits according to
+   PVR_CVAL_INPUT_xxxx definitions.  The change_mask parameter indicate
+   which settings are being changed and the change_val parameter indicates
+   whether corresponding settings are being set or cleared. */
+int pvr2_hdw_set_input_allowed(struct pvr2_hdw *,
+			       unsigned int change_mask,
+			       unsigned int change_val);
+
 /* Return name for this driver instance */
 const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *);
 
@@ -250,6 +266,9 @@
 /* Execute simple reset command */
 int pvr2_hdw_cmd_powerup(struct pvr2_hdw *);
 
+/* suspend */
+int pvr2_hdw_cmd_powerdown(struct pvr2_hdw *);
+
 /* Order decoder to reset */
 int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *);
 
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
index 62867fa..793c89a 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -35,7 +35,7 @@
 
 */
 
-static unsigned int i2c_scan = 0;
+static unsigned int i2c_scan;
 module_param(i2c_scan, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time");
 
diff --git a/drivers/media/video/pvrusb2/pvrusb2-io.c b/drivers/media/video/pvrusb2/pvrusb2-io.c
index a9889ff..7aff8b7 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-io.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-io.c
@@ -80,6 +80,10 @@
 	/* Tracking state for tolerating errors */
 	unsigned int fail_count;
 	unsigned int fail_tolerance;
+
+	unsigned int buffers_processed;
+	unsigned int buffers_failed;
+	unsigned int bytes_processed;
 };
 
 struct pvr2_buffer {
@@ -446,6 +450,8 @@
 	    (urb->status == -ENOENT) ||
 	    (urb->status == -ECONNRESET) ||
 	    (urb->status == -ESHUTDOWN)) {
+		(sp->buffers_processed)++;
+		sp->bytes_processed += urb->actual_length;
 		bp->used_count = urb->actual_length;
 		if (sp->fail_count) {
 			pvr2_trace(PVR2_TRACE_TOLERANCE,
@@ -457,11 +463,13 @@
 		// We can tolerate this error, because we're below the
 		// threshold...
 		(sp->fail_count)++;
+		(sp->buffers_failed)++;
 		pvr2_trace(PVR2_TRACE_TOLERANCE,
 			   "stream %p ignoring error %d"
 			   " - fail count increased to %u",
 			   sp,urb->status,sp->fail_count);
 	} else {
+		(sp->buffers_failed)++;
 		bp->status = urb->status;
 	}
 	spin_unlock_irqrestore(&sp->list_lock,irq_flags);
@@ -515,6 +523,28 @@
 	} while(0); mutex_unlock(&sp->mutex);
 }
 
+void pvr2_stream_get_stats(struct pvr2_stream *sp,
+			   struct pvr2_stream_stats *stats,
+			   int zero_counts)
+{
+	unsigned long irq_flags;
+	spin_lock_irqsave(&sp->list_lock,irq_flags);
+	if (stats) {
+		stats->buffers_in_queue = sp->q_count;
+		stats->buffers_in_idle = sp->i_count;
+		stats->buffers_in_ready = sp->r_count;
+		stats->buffers_processed = sp->buffers_processed;
+		stats->buffers_failed = sp->buffers_failed;
+		stats->bytes_processed = sp->bytes_processed;
+	}
+	if (zero_counts) {
+		sp->buffers_processed = 0;
+		sp->buffers_failed = 0;
+		sp->bytes_processed = 0;
+	}
+	spin_unlock_irqrestore(&sp->list_lock,irq_flags);
+}
+
 /* Query / set the nominal buffer count */
 int pvr2_stream_get_buffer_count(struct pvr2_stream *sp)
 {
diff --git a/drivers/media/video/pvrusb2/pvrusb2-io.h b/drivers/media/video/pvrusb2/pvrusb2-io.h
index 93279cc..42fcf82 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-io.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-io.h
@@ -36,6 +36,15 @@
 struct pvr2_stream;
 struct pvr2_buffer;
 
+struct pvr2_stream_stats {
+	unsigned int buffers_in_queue;
+	unsigned int buffers_in_idle;
+	unsigned int buffers_in_ready;
+	unsigned int buffers_processed;
+	unsigned int buffers_failed;
+	unsigned int bytes_processed;
+};
+
 /* Initialize / tear down stream structure */
 struct pvr2_stream *pvr2_stream_create(void);
 void pvr2_stream_destroy(struct pvr2_stream *);
@@ -45,6 +54,9 @@
 void pvr2_stream_set_callback(struct pvr2_stream *,
 			      pvr2_stream_callback func,
 			      void *data);
+void pvr2_stream_get_stats(struct pvr2_stream *,
+			   struct pvr2_stream_stats *,
+			   int zero_counts);
 
 /* Query / set the nominal buffer count */
 int pvr2_stream_get_buffer_count(struct pvr2_stream *);
diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c
index b63b226..332aced 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-main.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-main.c
@@ -60,6 +60,10 @@
 {
 	/* Create association with v4l layer */
 	pvr2_v4l2_create(pvr);
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+	/* Create association with dvb layer */
+	pvr2_dvb_create(pvr);
+#endif
 #ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
 	pvr2_sysfs_create(pvr,class_ptr);
 #endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
@@ -121,6 +125,12 @@
 
 	pvr2_trace(PVR2_TRACE_INIT,"pvr_init");
 
+	ret = pvr2_context_global_init();
+	if (ret != 0) {
+		pvr2_trace(PVR2_TRACE_INIT,"pvr_init failure code=%d",ret);
+		return ret;
+	}
+
 #ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
 	class_ptr = pvr2_sysfs_class_create();
 #endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
@@ -132,6 +142,8 @@
 	if (pvrusb2_debug) info("Debug mask is %d (0x%x)",
 				pvrusb2_debug,pvrusb2_debug);
 
+	pvr2_trace(PVR2_TRACE_INIT,"pvr_init complete");
+
 	return ret;
 }
 
@@ -144,6 +156,10 @@
 #ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
 	pvr2_sysfs_class_destroy(class_ptr);
 #endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
+
+	pvr2_context_global_done();
+
+	pvr2_trace(PVR2_TRACE_INIT,"pvr_exit complete");
 }
 
 module_init(pvr_init);
diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.c b/drivers/media/video/pvrusb2/pvrusb2-std.c
index da30928..fdc5a2b 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-std.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-std.c
@@ -79,7 +79,7 @@
 #define TSTD_Nc  (V4L2_STD_PAL_Nc)
 #define TSTD_60  (V4L2_STD_PAL_60)
 
-#define CSTD_ALL (CSTD_PAL|CSTD_NTSC|CSTD_SECAM)
+#define CSTD_ALL (CSTD_PAL|CSTD_NTSC|CSTD_ATSC|CSTD_SECAM)
 
 /* Mapping of standard bits to color system */
 static const struct std_name std_groups[] = {
@@ -328,7 +328,7 @@
 	struct v4l2_standard *stddefs;
 
 	if (pvrusb2_debug & PVR2_TRACE_STD) {
-		char buf[50];
+		char buf[100];
 		bcnt = pvr2_std_id_to_str(buf,sizeof(buf),id);
 		pvr2_trace(
 			PVR2_TRACE_STD,"Mapping standards mask=0x%x (%.*s)",
@@ -352,8 +352,11 @@
 		if ((id & std_mixes[idx2]) == std_mixes[idx2]) std_cnt++;
 	}
 
+	/* Don't complain about ATSC standard values */
+	fmsk &= ~CSTD_ATSC;
+
 	if (fmsk) {
-		char buf[50];
+		char buf[100];
 		bcnt = pvr2_std_id_to_str(buf,sizeof(buf),fmsk);
 		pvr2_trace(
 			PVR2_TRACE_ERROR_LEGS,
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
index 07f4eae..0ff7a83 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
@@ -287,6 +287,8 @@
 	struct pvr2_sysfs *sfp;
 	int ret;
 	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
+	pvr2_sysfs_trace("pvr2_sysfs(%p) store_val_norm(cid=%d) \"%.*s\"",
+			 sfp,id,(int)count,buf);
 	ret = store_val_any(id,0,sfp,buf,count);
 	if (!ret) ret = count;
 	return ret;
@@ -298,6 +300,8 @@
 	struct pvr2_sysfs *sfp;
 	int ret;
 	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
+	pvr2_sysfs_trace("pvr2_sysfs(%p) store_val_custom(cid=%d) \"%.*s\"",
+			 sfp,id,(int)count,buf);
 	ret = store_val_any(id,1,sfp,buf,count);
 	if (!ret) ret = count;
 	return ret;
@@ -604,8 +608,9 @@
 
 	ret = sysfs_create_group(&sfp->class_dev->kobj,&cip->grp);
 	if (ret) {
-		printk(KERN_WARNING "%s: sysfs_create_group error: %d\n",
-		       __FUNCTION__, ret);
+		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+			   "sysfs_create_group error: %d",
+			   ret);
 		return;
 	}
 	cip->created_ok = !0;
@@ -636,15 +641,17 @@
 	sfp->debugifc = dip;
 	ret = device_create_file(sfp->class_dev,&dip->attr_debugcmd);
 	if (ret < 0) {
-		printk(KERN_WARNING "%s: device_create_file error: %d\n",
-		       __FUNCTION__, ret);
+		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+			   "device_create_file error: %d",
+			   ret);
 	} else {
 		dip->debugcmd_created_ok = !0;
 	}
 	ret = device_create_file(sfp->class_dev,&dip->attr_debuginfo);
 	if (ret < 0) {
-		printk(KERN_WARNING "%s: device_create_file error: %d\n",
-		       __FUNCTION__, ret);
+		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+			   "device_create_file error: %d",
+			   ret);
 	} else {
 		dip->debuginfo_created_ok = !0;
 	}
@@ -847,8 +854,8 @@
 	class_dev->driver_data = sfp;
 	ret = device_register(class_dev);
 	if (ret) {
-		printk(KERN_ERR "%s: device_register failed\n",
-		       __FUNCTION__);
+		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+			   "device_register failed");
 		kfree(class_dev);
 		return;
 	}
@@ -860,8 +867,9 @@
 	ret = device_create_file(sfp->class_dev,
 				       &sfp->attr_v4l_minor_number);
 	if (ret < 0) {
-		printk(KERN_WARNING "%s: device_create_file error: %d\n",
-		       __FUNCTION__, ret);
+		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+			   "device_create_file error: %d",
+			   ret);
 	} else {
 		sfp->v4l_minor_number_created_ok = !0;
 	}
@@ -873,8 +881,9 @@
 	ret = device_create_file(sfp->class_dev,
 				       &sfp->attr_v4l_radio_minor_number);
 	if (ret < 0) {
-		printk(KERN_WARNING "%s: device_create_file error: %d\n",
-		       __FUNCTION__, ret);
+		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+			   "device_create_file error: %d",
+			   ret);
 	} else {
 		sfp->v4l_radio_minor_number_created_ok = !0;
 	}
@@ -885,8 +894,9 @@
 	sfp->attr_unit_number.store = NULL;
 	ret = device_create_file(sfp->class_dev,&sfp->attr_unit_number);
 	if (ret < 0) {
-		printk(KERN_WARNING "%s: device_create_file error: %d\n",
-		       __FUNCTION__, ret);
+		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+			   "device_create_file error: %d",
+			   ret);
 	} else {
 		sfp->unit_number_created_ok = !0;
 	}
@@ -898,8 +908,9 @@
 	ret = device_create_file(sfp->class_dev,
 				       &sfp->attr_bus_info);
 	if (ret < 0) {
-		printk(KERN_WARNING "%s: device_create_file error: %d\n",
-		       __FUNCTION__, ret);
+		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+			   "device_create_file error: %d",
+			   ret);
 	} else {
 		sfp->bus_info_created_ok = !0;
 	}
@@ -911,8 +922,9 @@
 	ret = device_create_file(sfp->class_dev,
 				 &sfp->attr_hdw_name);
 	if (ret < 0) {
-		printk(KERN_WARNING "%s: device_create_file error: %d\n",
-		       __FUNCTION__, ret);
+		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+			   "device_create_file error: %d",
+			   ret);
 	} else {
 		sfp->hdw_name_created_ok = !0;
 	}
@@ -924,8 +936,9 @@
 	ret = device_create_file(sfp->class_dev,
 				 &sfp->attr_hdw_desc);
 	if (ret < 0) {
-		printk(KERN_WARNING "%s: device_create_file error: %d\n",
-		       __FUNCTION__, ret);
+		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+			   "device_create_file error: %d",
+			   ret);
 	} else {
 		sfp->hdw_desc_created_ok = !0;
 	}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index 8f0587e..087a182 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -57,7 +57,9 @@
 	struct pvr2_v4l2_fh *vprev;
 	wait_queue_head_t wait_data;
 	int fw_mode_flag;
-	int prev_input_val;
+	/* Map contiguous ordinal value to input id */
+	unsigned char *input_map;
+	unsigned int input_cnt;
 };
 
 struct pvr2_v4l2 {
@@ -259,14 +261,21 @@
 		struct v4l2_input *vi = (struct v4l2_input *)arg;
 		struct v4l2_input tmp;
 		unsigned int cnt;
+		int val;
 
 		cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
 
 		memset(&tmp,0,sizeof(tmp));
 		tmp.index = vi->index;
 		ret = 0;
-		switch (vi->index) {
+		if ((vi->index < 0) || (vi->index >= fh->input_cnt)) {
+			ret = -EINVAL;
+			break;
+		}
+		val = fh->input_map[vi->index];
+		switch (val) {
 		case PVR2_CVAL_INPUT_TV:
+		case PVR2_CVAL_INPUT_DTV:
 		case PVR2_CVAL_INPUT_RADIO:
 			tmp.type = V4L2_INPUT_TYPE_TUNER;
 			break;
@@ -281,7 +290,7 @@
 		if (ret < 0) break;
 
 		cnt = 0;
-		pvr2_ctrl_get_valname(cptr,vi->index,
+		pvr2_ctrl_get_valname(cptr,val,
 				      tmp.name,sizeof(tmp.name)-1,&cnt);
 		tmp.name[cnt] = 0;
 
@@ -303,22 +312,33 @@
 
 	case VIDIOC_G_INPUT:
 	{
+		unsigned int idx;
 		struct pvr2_ctrl *cptr;
 		struct v4l2_input *vi = (struct v4l2_input *)arg;
 		int val;
 		cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
 		val = 0;
 		ret = pvr2_ctrl_get_value(cptr,&val);
-		vi->index = val;
+		vi->index = 0;
+		for (idx = 0; idx < fh->input_cnt; idx++) {
+			if (fh->input_map[idx] == val) {
+				vi->index = idx;
+				break;
+			}
+		}
 		break;
 	}
 
 	case VIDIOC_S_INPUT:
 	{
 		struct v4l2_input *vi = (struct v4l2_input *)arg;
+		if ((vi->index < 0) || (vi->index >= fh->input_cnt)) {
+			ret = -ERANGE;
+			break;
+		}
 		ret = pvr2_ctrl_set_value(
 			pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
-			vi->index);
+			fh->input_map[vi->index]);
 		break;
 	}
 
@@ -858,7 +878,6 @@
 {
 	struct pvr2_v4l2_fh *fhp = file->private_data;
 	struct pvr2_v4l2 *vp = fhp->vhead;
-	struct pvr2_context *mp = fhp->vhead->channel.mc_head;
 	struct pvr2_hdw *hdw = fhp->channel.mc_head->hdw;
 
 	pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_release");
@@ -875,42 +894,30 @@
 	v4l2_prio_close(&vp->prio, &fhp->prio);
 	file->private_data = NULL;
 
-	pvr2_context_enter(mp); do {
-		/* Restore the previous input selection, if it makes sense
-		   to do so. */
-		if (fhp->dev_info->v4l_type == VFL_TYPE_RADIO) {
-			struct pvr2_ctrl *cp;
-			int pval;
-			cp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
-			pvr2_ctrl_get_value(cp,&pval);
-			/* Only restore if we're still selecting the radio */
-			if (pval == PVR2_CVAL_INPUT_RADIO) {
-				pvr2_ctrl_set_value(cp,fhp->prev_input_val);
-				pvr2_hdw_commit_ctl(hdw);
-			}
-		}
-
-		if (fhp->vnext) {
-			fhp->vnext->vprev = fhp->vprev;
-		} else {
-			vp->vlast = fhp->vprev;
-		}
-		if (fhp->vprev) {
-			fhp->vprev->vnext = fhp->vnext;
-		} else {
-			vp->vfirst = fhp->vnext;
-		}
-		fhp->vnext = NULL;
-		fhp->vprev = NULL;
-		fhp->vhead = NULL;
-		pvr2_channel_done(&fhp->channel);
-		pvr2_trace(PVR2_TRACE_STRUCT,
-			   "Destroying pvr_v4l2_fh id=%p",fhp);
-		kfree(fhp);
-		if (vp->channel.mc_head->disconnect_flag && !vp->vfirst) {
-			pvr2_v4l2_destroy_no_lock(vp);
-		}
-	} while (0); pvr2_context_exit(mp);
+	if (fhp->vnext) {
+		fhp->vnext->vprev = fhp->vprev;
+	} else {
+		vp->vlast = fhp->vprev;
+	}
+	if (fhp->vprev) {
+		fhp->vprev->vnext = fhp->vnext;
+	} else {
+		vp->vfirst = fhp->vnext;
+	}
+	fhp->vnext = NULL;
+	fhp->vprev = NULL;
+	fhp->vhead = NULL;
+	pvr2_channel_done(&fhp->channel);
+	pvr2_trace(PVR2_TRACE_STRUCT,
+		   "Destroying pvr_v4l2_fh id=%p",fhp);
+	if (fhp->input_map) {
+		kfree(fhp->input_map);
+		fhp->input_map = NULL;
+	}
+	kfree(fhp);
+	if (vp->channel.mc_head->disconnect_flag && !vp->vfirst) {
+		pvr2_v4l2_destroy_no_lock(vp);
+	}
 	return 0;
 }
 
@@ -921,6 +928,9 @@
 	struct pvr2_v4l2_fh *fhp;
 	struct pvr2_v4l2 *vp;
 	struct pvr2_hdw *hdw;
+	unsigned int input_mask = 0;
+	unsigned int input_cnt,idx;
+	int ret = 0;
 
 	dip = container_of(video_devdata(file),struct pvr2_v4l2_dev,devbase);
 
@@ -943,32 +953,62 @@
 	init_waitqueue_head(&fhp->wait_data);
 	fhp->dev_info = dip;
 
-	pvr2_context_enter(vp->channel.mc_head); do {
-		pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp);
-		pvr2_channel_init(&fhp->channel,vp->channel.mc_head);
+	pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp);
+	pvr2_channel_init(&fhp->channel,vp->channel.mc_head);
 
-		fhp->vnext = NULL;
-		fhp->vprev = vp->vlast;
-		if (vp->vlast) {
-			vp->vlast->vnext = fhp;
-		} else {
-			vp->vfirst = fhp;
-		}
-		vp->vlast = fhp;
-		fhp->vhead = vp;
+	if (dip->v4l_type == VFL_TYPE_RADIO) {
+		/* Opening device as a radio, legal input selection subset
+		   is just the radio. */
+		input_mask = (1 << PVR2_CVAL_INPUT_RADIO);
+	} else {
+		/* Opening the main V4L device, legal input selection
+		   subset includes all analog inputs. */
+		input_mask = ((1 << PVR2_CVAL_INPUT_RADIO) |
+			      (1 << PVR2_CVAL_INPUT_TV) |
+			      (1 << PVR2_CVAL_INPUT_COMPOSITE) |
+			      (1 << PVR2_CVAL_INPUT_SVIDEO));
+	}
+	ret = pvr2_channel_limit_inputs(&fhp->channel,input_mask);
+	if (ret) {
+		pvr2_channel_done(&fhp->channel);
+		pvr2_trace(PVR2_TRACE_STRUCT,
+			   "Destroying pvr_v4l2_fh id=%p (input mask error)",
+			   fhp);
 
-		/* Opening the /dev/radioX device implies a mode switch.
-		   So execute that here.  Note that you can get the
-		   IDENTICAL effect merely by opening the normal video
-		   device and setting the input appropriately. */
-		if (dip->v4l_type == VFL_TYPE_RADIO) {
-			struct pvr2_ctrl *cp;
-			cp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
-			pvr2_ctrl_get_value(cp,&fhp->prev_input_val);
-			pvr2_ctrl_set_value(cp,PVR2_CVAL_INPUT_RADIO);
-			pvr2_hdw_commit_ctl(hdw);
-		}
-	} while (0); pvr2_context_exit(vp->channel.mc_head);
+		kfree(fhp);
+		return ret;
+	}
+
+	input_mask &= pvr2_hdw_get_input_available(hdw);
+	input_cnt = 0;
+	for (idx = 0; idx < (sizeof(input_mask) << 3); idx++) {
+		if (input_mask & (1 << idx)) input_cnt++;
+	}
+	fhp->input_cnt = input_cnt;
+	fhp->input_map = kzalloc(input_cnt,GFP_KERNEL);
+	if (!fhp->input_map) {
+		pvr2_channel_done(&fhp->channel);
+		pvr2_trace(PVR2_TRACE_STRUCT,
+			   "Destroying pvr_v4l2_fh id=%p (input map failure)",
+			   fhp);
+		kfree(fhp);
+		return -ENOMEM;
+	}
+	input_cnt = 0;
+	for (idx = 0; idx < (sizeof(input_mask) << 3); idx++) {
+		if (!(input_mask & (1 << idx))) continue;
+		fhp->input_map[input_cnt++] = idx;
+	}
+
+	fhp->vnext = NULL;
+	fhp->vprev = vp->vlast;
+	if (vp->vlast) {
+		vp->vlast->vnext = fhp;
+	} else {
+		vp->vfirst = fhp;
+	}
+	vp->vlast = fhp;
+	fhp->vhead = vp;
 
 	fhp->file = file;
 	file->private_data = fhp;
@@ -1201,24 +1241,27 @@
 
 	vp = kzalloc(sizeof(*vp),GFP_KERNEL);
 	if (!vp) return vp;
-	vp->dev_video = kzalloc(sizeof(*vp->dev_video),GFP_KERNEL);
-	vp->dev_radio = kzalloc(sizeof(*vp->dev_radio),GFP_KERNEL);
-	if (!(vp->dev_video && vp->dev_radio)) {
-		kfree(vp->dev_video);
-		kfree(vp->dev_radio);
-		kfree(vp);
-		return NULL;
-	}
 	pvr2_channel_init(&vp->channel,mnp);
 	pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp);
 
 	vp->channel.check_func = pvr2_v4l2_internal_check;
 
 	/* register streams */
+	vp->dev_video = kzalloc(sizeof(*vp->dev_video),GFP_KERNEL);
+	if (!vp->dev_video) goto fail;
 	pvr2_v4l2_dev_init(vp->dev_video,vp,VFL_TYPE_GRABBER);
-	pvr2_v4l2_dev_init(vp->dev_radio,vp,VFL_TYPE_RADIO);
+	if (pvr2_hdw_get_input_available(vp->channel.mc_head->hdw) &
+	    (1 << PVR2_CVAL_INPUT_RADIO)) {
+		vp->dev_radio = kzalloc(sizeof(*vp->dev_radio),GFP_KERNEL);
+		if (!vp->dev_radio) goto fail;
+		pvr2_v4l2_dev_init(vp->dev_radio,vp,VFL_TYPE_RADIO);
+	}
 
 	return vp;
+ fail:
+	pvr2_trace(PVR2_TRACE_STRUCT,"Failure creating pvr2_v4l2 id=%p",vp);
+	pvr2_v4l2_destroy_no_lock(vp);
+	return 0;
 }
 
 /*
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index e0a453a..423fa7c 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -130,8 +130,8 @@
 #ifdef CONFIG_USB_PWC_DEBUG
 	int pwc_trace = PWC_DEBUG_LEVEL;
 #endif
-static int power_save = 0;
-static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */
+static int power_save;
+static int led_on = 100, led_off; /* defaults to LED that is on while in use */
 static int pwc_preferred_compression = 1; /* 0..3 = uncompressed..high */
 static struct {
 	int type;
@@ -159,7 +159,9 @@
 	.poll =		pwc_video_poll,
 	.mmap =		pwc_video_mmap,
 	.ioctl =        pwc_video_ioctl,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl = v4l_compat_ioctl32,
+#endif
 	.llseek =       no_llseek,
 };
 static struct video_device pwc_template = {
@@ -487,7 +489,7 @@
 	int i;
 	unsigned long flags;
 
-	PWC_DEBUG_MEMORY(">> %s __enter__\n", __FUNCTION__);
+	PWC_DEBUG_MEMORY(">> %s __enter__\n", __func__);
 
 	spin_lock_irqsave(&pdev->ptrlock, flags);
 	pdev->full_frames = NULL;
@@ -509,7 +511,7 @@
 	pdev->fill_image = 0;
 	spin_unlock_irqrestore(&pdev->ptrlock, flags);
 
-	PWC_DEBUG_MEMORY("<< %s __leaving__\n", __FUNCTION__);
+	PWC_DEBUG_MEMORY("<< %s __leaving__\n", __func__);
 }
 
 
@@ -786,8 +788,8 @@
 		} /* ..status == 0 */
 		else {
 			/* This is normally not interesting to the user, unless
-			 * you are really debugging something */
-			static int iso_error = 0;
+			 * you are really debugging something, default = 0 */
+			static int iso_error;
 			iso_error++;
 			if (iso_error < 20)
 				PWC_DEBUG_FLOW("Iso frame %d of USB has error %d\n", i, fst);
@@ -1426,7 +1428,7 @@
 	unsigned long page, pos = 0;
 	int index;
 
-	PWC_DEBUG_MEMORY(">> %s\n", __FUNCTION__);
+	PWC_DEBUG_MEMORY(">> %s\n", __func__);
 	pdev = vdev->priv;
 	size = vma->vm_end - vma->vm_start;
 	start = vma->vm_start;
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c
index 32fbe1a..1742889 100644
--- a/drivers/media/video/pwc/pwc-v4l.c
+++ b/drivers/media/video/pwc/pwc-v4l.c
@@ -351,8 +351,10 @@
 		return -EFAULT;
 
 #ifdef CONFIG_USB_PWC_DEBUG
-	if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace)
+	if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace) {
 		v4l_printk_ioctl(cmd);
+		printk("\n");
+	}
 #endif
 
 
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
new file mode 100644
index 0000000..7cc8e9b
--- /dev/null
+++ b/drivers/media/video/pxa_camera.c
@@ -0,0 +1,1206 @@
+/*
+ * V4L2 Driver for PXA camera host
+ *
+ * Copyright (C) 2006, Sascha Hauer, Pengutronix
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/version.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/soc_camera.h>
+
+#include <linux/videodev2.h>
+
+#include <asm/dma.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/camera.h>
+
+#define PXA_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 5)
+#define PXA_CAM_DRV_NAME "pxa27x-camera"
+
+#define CICR0_SIM_MP	(0 << 24)
+#define CICR0_SIM_SP	(1 << 24)
+#define CICR0_SIM_MS	(2 << 24)
+#define CICR0_SIM_EP	(3 << 24)
+#define CICR0_SIM_ES	(4 << 24)
+
+#define CICR1_DW_VAL(x)   ((x) & CICR1_DW)	    /* Data bus width */
+#define CICR1_PPL_VAL(x)  (((x) << 15) & CICR1_PPL) /* Pixels per line */
+#define CICR1_COLOR_SP_VAL(x)	(((x) << 3) & CICR1_COLOR_SP)	/* color space */
+#define CICR1_RGB_BPP_VAL(x)	(((x) << 7) & CICR1_RGB_BPP)	/* bpp for rgb */
+#define CICR1_RGBT_CONV_VAL(x)	(((x) << 29) & CICR1_RGBT_CONV)	/* rgbt conv */
+
+#define CICR2_BLW_VAL(x)  (((x) << 24) & CICR2_BLW) /* Beginning-of-line pixel clock wait count */
+#define CICR2_ELW_VAL(x)  (((x) << 16) & CICR2_ELW) /* End-of-line pixel clock wait count */
+#define CICR2_HSW_VAL(x)  (((x) << 10) & CICR2_HSW) /* Horizontal sync pulse width */
+#define CICR2_BFPW_VAL(x) (((x) << 3) & CICR2_BFPW) /* Beginning-of-frame pixel clock wait count */
+#define CICR2_FSW_VAL(x)  (((x) << 0) & CICR2_FSW)  /* Frame stabilization wait count */
+
+#define CICR3_BFW_VAL(x)  (((x) << 24) & CICR3_BFW) /* Beginning-of-frame line clock wait count  */
+#define CICR3_EFW_VAL(x)  (((x) << 16) & CICR3_EFW) /* End-of-frame line clock wait count */
+#define CICR3_VSW_VAL(x)  (((x) << 11) & CICR3_VSW) /* Vertical sync pulse width */
+#define CICR3_LPF_VAL(x)  (((x) << 0) & CICR3_LPF)  /* Lines per frame */
+
+#define CICR0_IRQ_MASK (CICR0_TOM | CICR0_RDAVM | CICR0_FEM | CICR0_EOLM | \
+			CICR0_PERRM | CICR0_QDM | CICR0_CDM | CICR0_SOFM | \
+			CICR0_EOFM | CICR0_FOM)
+
+static DEFINE_MUTEX(camera_lock);
+
+/*
+ * Structures
+ */
+enum pxa_camera_active_dma {
+	DMA_Y = 0x1,
+	DMA_U = 0x2,
+	DMA_V = 0x4,
+};
+
+/* descriptor needed for the PXA DMA engine */
+struct pxa_cam_dma {
+	dma_addr_t		sg_dma;
+	struct pxa_dma_desc	*sg_cpu;
+	size_t			sg_size;
+	int			sglen;
+};
+
+/* buffer for one video frame */
+struct pxa_buffer {
+	/* common v4l buffer stuff -- must be first */
+	struct videobuf_buffer vb;
+
+	const struct soc_camera_data_format        *fmt;
+
+	/* our descriptor lists for Y, U and V channels */
+	struct pxa_cam_dma dmas[3];
+
+	int			inwork;
+
+	enum pxa_camera_active_dma active_dma;
+};
+
+struct pxa_camera_dev {
+	struct device		*dev;
+	/* PXA27x is only supposed to handle one camera on its Quick Capture
+	 * interface. If anyone ever builds hardware to enable more than
+	 * one camera, they will have to modify this driver too */
+	struct soc_camera_device *icd;
+	struct clk		*clk;
+
+	unsigned int		irq;
+	void __iomem		*base;
+
+	int			channels;
+	unsigned int		dma_chans[3];
+
+	struct pxacamera_platform_data *pdata;
+	struct resource		*res;
+	unsigned long		platform_flags;
+	unsigned long		platform_mclk_10khz;
+
+	struct list_head	capture;
+
+	spinlock_t		lock;
+
+	struct pxa_buffer	*active;
+	struct pxa_dma_desc	*sg_tail[3];
+};
+
+static const char *pxa_cam_driver_description = "PXA_Camera";
+
+static unsigned int vid_limit = 16;	/* Video memory limit, in Mb */
+
+/*
+ *  Videobuf operations
+ */
+static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
+			      unsigned int *size)
+{
+	struct soc_camera_device *icd = vq->priv_data;
+	struct soc_camera_host *ici =
+		to_soc_camera_host(icd->dev.parent);
+	struct pxa_camera_dev *pcdev = ici->priv;
+
+	dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size);
+
+	/* planar capture requires Y, U and V buffers to be page aligned */
+	if (pcdev->channels == 3) {
+		*size = PAGE_ALIGN(icd->width * icd->height); /* Y pages */
+		*size += PAGE_ALIGN(icd->width * icd->height / 2); /* U pages */
+		*size += PAGE_ALIGN(icd->width * icd->height / 2); /* V pages */
+	} else {
+		*size = icd->width * icd->height *
+			((icd->current_fmt->depth + 7) >> 3);
+	}
+
+	if (0 == *count)
+		*count = 32;
+	while (*size * *count > vid_limit * 1024 * 1024)
+		(*count)--;
+
+	return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf)
+{
+	struct soc_camera_device *icd = vq->priv_data;
+	struct soc_camera_host *ici =
+		to_soc_camera_host(icd->dev.parent);
+	struct pxa_camera_dev *pcdev = ici->priv;
+	struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+	int i;
+
+	BUG_ON(in_interrupt());
+
+	dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+		&buf->vb, buf->vb.baddr, buf->vb.bsize);
+
+	/* This waits until this buffer is out of danger, i.e., until it is no
+	 * longer in STATE_QUEUED or STATE_ACTIVE */
+	videobuf_waiton(&buf->vb, 0, 0);
+	videobuf_dma_unmap(vq, dma);
+	videobuf_dma_free(dma);
+
+	for (i = 0; i < ARRAY_SIZE(buf->dmas); i++) {
+		if (buf->dmas[i].sg_cpu)
+			dma_free_coherent(pcdev->dev, buf->dmas[i].sg_size,
+					  buf->dmas[i].sg_cpu,
+					  buf->dmas[i].sg_dma);
+		buf->dmas[i].sg_cpu = NULL;
+	}
+
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev,
+				struct pxa_buffer *buf,
+				struct videobuf_dmabuf *dma, int channel,
+				int sglen, int sg_start, int cibr,
+				unsigned int size)
+{
+	struct pxa_cam_dma *pxa_dma = &buf->dmas[channel];
+	int i;
+
+	if (pxa_dma->sg_cpu)
+		dma_free_coherent(pcdev->dev, pxa_dma->sg_size,
+				  pxa_dma->sg_cpu, pxa_dma->sg_dma);
+
+	pxa_dma->sg_size = (sglen + 1) * sizeof(struct pxa_dma_desc);
+	pxa_dma->sg_cpu = dma_alloc_coherent(pcdev->dev, pxa_dma->sg_size,
+					     &pxa_dma->sg_dma, GFP_KERNEL);
+	if (!pxa_dma->sg_cpu)
+		return -ENOMEM;
+
+	pxa_dma->sglen = sglen;
+
+	for (i = 0; i < sglen; i++) {
+		int sg_i = sg_start + i;
+		struct scatterlist *sg = dma->sglist;
+		unsigned int dma_len = sg_dma_len(&sg[sg_i]), xfer_len;
+
+		pxa_dma->sg_cpu[i].dsadr = pcdev->res->start + cibr;
+		pxa_dma->sg_cpu[i].dtadr = sg_dma_address(&sg[sg_i]);
+
+		/* PXA27x Developer's Manual 27.4.4.1: round up to 8 bytes */
+		xfer_len = (min(dma_len, size) + 7) & ~7;
+
+		pxa_dma->sg_cpu[i].dcmd =
+			DCMD_FLOWSRC | DCMD_BURST8 | DCMD_INCTRGADDR | xfer_len;
+		size -= dma_len;
+		pxa_dma->sg_cpu[i].ddadr =
+			pxa_dma->sg_dma + (i + 1) * sizeof(struct pxa_dma_desc);
+	}
+
+	pxa_dma->sg_cpu[sglen - 1].ddadr = DDADR_STOP;
+	pxa_dma->sg_cpu[sglen - 1].dcmd |= DCMD_ENDIRQEN;
+
+	return 0;
+}
+
+static int pxa_videobuf_prepare(struct videobuf_queue *vq,
+		struct videobuf_buffer *vb, enum v4l2_field field)
+{
+	struct soc_camera_device *icd = vq->priv_data;
+	struct soc_camera_host *ici =
+		to_soc_camera_host(icd->dev.parent);
+	struct pxa_camera_dev *pcdev = ici->priv;
+	struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
+	int ret;
+	int sglen_y,  sglen_yu = 0, sglen_u = 0, sglen_v = 0;
+	int size_y, size_u = 0, size_v = 0;
+
+	dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+		vb, vb->baddr, vb->bsize);
+
+	/* Added list head initialization on alloc */
+	WARN_ON(!list_empty(&vb->queue));
+
+#ifdef DEBUG
+	/* This can be useful if you want to see if we actually fill
+	 * the buffer with something */
+	memset((void *)vb->baddr, 0xaa, vb->bsize);
+#endif
+
+	BUG_ON(NULL == icd->current_fmt);
+
+	/* I think, in buf_prepare you only have to protect global data,
+	 * the actual buffer is yours */
+	buf->inwork = 1;
+
+	if (buf->fmt	!= icd->current_fmt ||
+	    vb->width	!= icd->width ||
+	    vb->height	!= icd->height ||
+	    vb->field	!= field) {
+		buf->fmt	= icd->current_fmt;
+		vb->width	= icd->width;
+		vb->height	= icd->height;
+		vb->field	= field;
+		vb->state	= VIDEOBUF_NEEDS_INIT;
+	}
+
+	vb->size = vb->width * vb->height * ((buf->fmt->depth + 7) >> 3);
+	if (0 != vb->baddr && vb->bsize < vb->size) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (vb->state == VIDEOBUF_NEEDS_INIT) {
+		unsigned int size = vb->size;
+		struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+
+		ret = videobuf_iolock(vq, vb, NULL);
+		if (ret)
+			goto fail;
+
+		if (pcdev->channels == 3) {
+			/* FIXME the calculations should be more precise */
+			sglen_y = dma->sglen / 2;
+			sglen_u = sglen_v = dma->sglen / 4 + 1;
+			sglen_yu = sglen_y + sglen_u;
+			size_y = size / 2;
+			size_u = size_v = size / 4;
+		} else {
+			sglen_y = dma->sglen;
+			size_y = size;
+		}
+
+		/* init DMA for Y channel */
+		ret = pxa_init_dma_channel(pcdev, buf, dma, 0, sglen_y,
+					   0, 0x28, size_y);
+
+		if (ret) {
+			dev_err(pcdev->dev,
+				"DMA initialization for Y/RGB failed\n");
+			goto fail;
+		}
+
+		if (pcdev->channels == 3) {
+			/* init DMA for U channel */
+			ret = pxa_init_dma_channel(pcdev, buf, dma, 1, sglen_u,
+						   sglen_y, 0x30, size_u);
+			if (ret) {
+				dev_err(pcdev->dev,
+					"DMA initialization for U failed\n");
+				goto fail_u;
+			}
+
+			/* init DMA for V channel */
+			ret = pxa_init_dma_channel(pcdev, buf, dma, 2, sglen_v,
+						   sglen_yu, 0x38, size_v);
+			if (ret) {
+				dev_err(pcdev->dev,
+					"DMA initialization for V failed\n");
+				goto fail_v;
+			}
+		}
+
+		vb->state = VIDEOBUF_PREPARED;
+	}
+
+	buf->inwork = 0;
+	buf->active_dma = DMA_Y;
+	if (pcdev->channels == 3)
+		buf->active_dma |= DMA_U | DMA_V;
+
+	return 0;
+
+fail_v:
+	dma_free_coherent(pcdev->dev, buf->dmas[1].sg_size,
+			  buf->dmas[1].sg_cpu, buf->dmas[1].sg_dma);
+fail_u:
+	dma_free_coherent(pcdev->dev, buf->dmas[0].sg_size,
+			  buf->dmas[0].sg_cpu, buf->dmas[0].sg_dma);
+fail:
+	free_buffer(vq, buf);
+out:
+	buf->inwork = 0;
+	return ret;
+}
+
+static void pxa_videobuf_queue(struct videobuf_queue *vq,
+			       struct videobuf_buffer *vb)
+{
+	struct soc_camera_device *icd = vq->priv_data;
+	struct soc_camera_host *ici =
+		to_soc_camera_host(icd->dev.parent);
+	struct pxa_camera_dev *pcdev = ici->priv;
+	struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
+	struct pxa_buffer *active;
+	unsigned long flags;
+	int i;
+
+	dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+		vb, vb->baddr, vb->bsize);
+	spin_lock_irqsave(&pcdev->lock, flags);
+
+	list_add_tail(&vb->queue, &pcdev->capture);
+
+	vb->state = VIDEOBUF_ACTIVE;
+	active = pcdev->active;
+
+	if (!active) {
+		CIFR |= CIFR_RESET_F;
+
+		for (i = 0; i < pcdev->channels; i++) {
+			DDADR(pcdev->dma_chans[i]) = buf->dmas[i].sg_dma;
+			DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
+			pcdev->sg_tail[i] = buf->dmas[i].sg_cpu + buf->dmas[i].sglen - 1;
+		}
+
+		pcdev->active = buf;
+		CICR0 |= CICR0_ENB;
+	} else {
+		struct pxa_cam_dma *buf_dma;
+		struct pxa_cam_dma *act_dma;
+		int nents;
+
+		for (i = 0; i < pcdev->channels; i++) {
+			buf_dma = &buf->dmas[i];
+			act_dma = &active->dmas[i];
+			nents = buf_dma->sglen;
+
+			/* Stop DMA engine */
+			DCSR(pcdev->dma_chans[i]) = 0;
+
+			/* Add the descriptors we just initialized to
+			   the currently running chain */
+			pcdev->sg_tail[i]->ddadr = buf_dma->sg_dma;
+			pcdev->sg_tail[i] = buf_dma->sg_cpu + buf_dma->sglen - 1;
+
+			/* Setup a dummy descriptor with the DMA engines current
+			 * state
+			 */
+			buf_dma->sg_cpu[nents].dsadr =
+				pcdev->res->start + 0x28 + i*8; /* CIBRx */
+			buf_dma->sg_cpu[nents].dtadr =
+				DTADR(pcdev->dma_chans[i]);
+			buf_dma->sg_cpu[nents].dcmd =
+				DCMD(pcdev->dma_chans[i]);
+
+			if (DDADR(pcdev->dma_chans[i]) == DDADR_STOP) {
+				/* The DMA engine is on the last
+				   descriptor, set the next descriptors
+				   address to the descriptors we just
+				   initialized */
+				buf_dma->sg_cpu[nents].ddadr = buf_dma->sg_dma;
+			} else {
+				buf_dma->sg_cpu[nents].ddadr =
+					DDADR(pcdev->dma_chans[i]);
+			}
+
+			/* The next descriptor is the dummy descriptor */
+			DDADR(pcdev->dma_chans[i]) = buf_dma->sg_dma + nents *
+				sizeof(struct pxa_dma_desc);
+
+			DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
+		}
+	}
+
+	spin_unlock_irqrestore(&pcdev->lock, flags);
+}
+
+static void pxa_videobuf_release(struct videobuf_queue *vq,
+				 struct videobuf_buffer *vb)
+{
+	struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
+#ifdef DEBUG
+	struct soc_camera_device *icd = vq->priv_data;
+
+	dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+		vb, vb->baddr, vb->bsize);
+
+	switch (vb->state) {
+	case VIDEOBUF_ACTIVE:
+		dev_dbg(&icd->dev, "%s (active)\n", __func__);
+		break;
+	case VIDEOBUF_QUEUED:
+		dev_dbg(&icd->dev, "%s (queued)\n", __func__);
+		break;
+	case VIDEOBUF_PREPARED:
+		dev_dbg(&icd->dev, "%s (prepared)\n", __func__);
+		break;
+	default:
+		dev_dbg(&icd->dev, "%s (unknown)\n", __func__);
+		break;
+	}
+#endif
+
+	free_buffer(vq, buf);
+}
+
+static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev,
+			      struct videobuf_buffer *vb,
+			      struct pxa_buffer *buf)
+{
+	/* _init is used to debug races, see comment in pxa_camera_reqbufs() */
+	list_del_init(&vb->queue);
+	vb->state = VIDEOBUF_DONE;
+	do_gettimeofday(&vb->ts);
+	vb->field_count++;
+	wake_up(&vb->done);
+
+	if (list_empty(&pcdev->capture)) {
+		pcdev->active = NULL;
+		DCSR(pcdev->dma_chans[0]) = 0;
+		DCSR(pcdev->dma_chans[1]) = 0;
+		DCSR(pcdev->dma_chans[2]) = 0;
+		CICR0 &= ~CICR0_ENB;
+		return;
+	}
+
+	pcdev->active = list_entry(pcdev->capture.next,
+				   struct pxa_buffer, vb.queue);
+}
+
+static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
+			       enum pxa_camera_active_dma act_dma)
+{
+	struct pxa_buffer *buf;
+	unsigned long flags;
+	u32 status, camera_status, overrun;
+	struct videobuf_buffer *vb;
+
+	spin_lock_irqsave(&pcdev->lock, flags);
+
+	status = DCSR(channel);
+	DCSR(channel) = status | DCSR_ENDINTR;
+
+	if (status & DCSR_BUSERR) {
+		dev_err(pcdev->dev, "DMA Bus Error IRQ!\n");
+		goto out;
+	}
+
+	if (!(status & DCSR_ENDINTR)) {
+		dev_err(pcdev->dev, "Unknown DMA IRQ source, "
+			"status: 0x%08x\n", status);
+		goto out;
+	}
+
+	if (!pcdev->active) {
+		dev_err(pcdev->dev, "DMA End IRQ with no active buffer!\n");
+		goto out;
+	}
+
+	camera_status = CISR;
+	overrun = CISR_IFO_0;
+	if (pcdev->channels == 3)
+		overrun |= CISR_IFO_1 | CISR_IFO_2;
+	if (camera_status & overrun) {
+		dev_dbg(pcdev->dev, "FIFO overrun! CISR: %x\n", camera_status);
+		/* Stop the Capture Interface */
+		CICR0 &= ~CICR0_ENB;
+		/* Stop DMA */
+		DCSR(channel) = 0;
+		/* Reset the FIFOs */
+		CIFR |= CIFR_RESET_F;
+		/* Enable End-Of-Frame Interrupt */
+		CICR0 &= ~CICR0_EOFM;
+		/* Restart the Capture Interface */
+		CICR0 |= CICR0_ENB;
+		goto out;
+	}
+
+	vb = &pcdev->active->vb;
+	buf = container_of(vb, struct pxa_buffer, vb);
+	WARN_ON(buf->inwork || list_empty(&vb->queue));
+	dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+		vb, vb->baddr, vb->bsize);
+
+	buf->active_dma &= ~act_dma;
+	if (!buf->active_dma)
+		pxa_camera_wakeup(pcdev, vb, buf);
+
+out:
+	spin_unlock_irqrestore(&pcdev->lock, flags);
+}
+
+static void pxa_camera_dma_irq_y(int channel, void *data)
+{
+	struct pxa_camera_dev *pcdev = data;
+	pxa_camera_dma_irq(channel, pcdev, DMA_Y);
+}
+
+static void pxa_camera_dma_irq_u(int channel, void *data)
+{
+	struct pxa_camera_dev *pcdev = data;
+	pxa_camera_dma_irq(channel, pcdev, DMA_U);
+}
+
+static void pxa_camera_dma_irq_v(int channel, void *data)
+{
+	struct pxa_camera_dev *pcdev = data;
+	pxa_camera_dma_irq(channel, pcdev, DMA_V);
+}
+
+static struct videobuf_queue_ops pxa_videobuf_ops = {
+	.buf_setup      = pxa_videobuf_setup,
+	.buf_prepare    = pxa_videobuf_prepare,
+	.buf_queue      = pxa_videobuf_queue,
+	.buf_release    = pxa_videobuf_release,
+};
+
+static int mclk_get_divisor(struct pxa_camera_dev *pcdev)
+{
+	unsigned int mclk_10khz = pcdev->platform_mclk_10khz;
+	unsigned long div;
+	unsigned long lcdclk;
+
+	lcdclk = clk_get_rate(pcdev->clk) / 10000;
+
+	/* We verify platform_mclk_10khz != 0, so if anyone breaks it, here
+	 * they get a nice Oops */
+	div = (lcdclk + 2 * mclk_10khz - 1) / (2 * mclk_10khz) - 1;
+
+	dev_dbg(pcdev->dev, "LCD clock %lukHz, target freq %dkHz, "
+		"divisor %lu\n", lcdclk * 10, mclk_10khz * 10, div);
+
+	return div;
+}
+
+static void pxa_camera_activate(struct pxa_camera_dev *pcdev)
+{
+	struct pxacamera_platform_data *pdata = pcdev->pdata;
+	u32 cicr4 = 0;
+
+	dev_dbg(pcdev->dev, "Registered platform device at %p data %p\n",
+		pcdev, pdata);
+
+	if (pdata && pdata->init) {
+		dev_dbg(pcdev->dev, "%s: Init gpios\n", __func__);
+		pdata->init(pcdev->dev);
+	}
+
+	if (pdata && pdata->power) {
+		dev_dbg(pcdev->dev, "%s: Power on camera\n", __func__);
+		pdata->power(pcdev->dev, 1);
+	}
+
+	if (pdata && pdata->reset) {
+		dev_dbg(pcdev->dev, "%s: Releasing camera reset\n",
+			__func__);
+		pdata->reset(pcdev->dev, 1);
+	}
+
+	CICR0 = 0x3FF;   /* disable all interrupts */
+
+	if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
+		cicr4 |= CICR4_PCLK_EN;
+	if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN)
+		cicr4 |= CICR4_MCLK_EN;
+	if (pcdev->platform_flags & PXA_CAMERA_PCP)
+		cicr4 |= CICR4_PCP;
+	if (pcdev->platform_flags & PXA_CAMERA_HSP)
+		cicr4 |= CICR4_HSP;
+	if (pcdev->platform_flags & PXA_CAMERA_VSP)
+		cicr4 |= CICR4_VSP;
+
+	CICR4 = mclk_get_divisor(pcdev) | cicr4;
+
+	clk_enable(pcdev->clk);
+}
+
+static void pxa_camera_deactivate(struct pxa_camera_dev *pcdev)
+{
+	struct pxacamera_platform_data *board = pcdev->pdata;
+
+	clk_disable(pcdev->clk);
+
+	if (board && board->reset) {
+		dev_dbg(pcdev->dev, "%s: Asserting camera reset\n",
+			__func__);
+		board->reset(pcdev->dev, 0);
+	}
+
+	if (board && board->power) {
+		dev_dbg(pcdev->dev, "%s: Power off camera\n", __func__);
+		board->power(pcdev->dev, 0);
+	}
+}
+
+static irqreturn_t pxa_camera_irq(int irq, void *data)
+{
+	struct pxa_camera_dev *pcdev = data;
+	unsigned int status = CISR;
+
+	dev_dbg(pcdev->dev, "Camera interrupt status 0x%x\n", status);
+
+	if (!status)
+		return IRQ_NONE;
+
+	CISR = status;
+
+	if (status & CISR_EOF) {
+		int i;
+		for (i = 0; i < pcdev->channels; i++) {
+			DDADR(pcdev->dma_chans[i]) =
+				pcdev->active->dmas[i].sg_dma;
+			DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
+		}
+		CICR0 |= CICR0_EOFM;
+	}
+
+	return IRQ_HANDLED;
+}
+
+/* The following two functions absolutely depend on the fact, that
+ * there can be only one camera on PXA quick capture interface */
+static int pxa_camera_add_device(struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+	struct pxa_camera_dev *pcdev = ici->priv;
+	int ret;
+
+	mutex_lock(&camera_lock);
+
+	if (pcdev->icd) {
+		ret = -EBUSY;
+		goto ebusy;
+	}
+
+	dev_info(&icd->dev, "PXA Camera driver attached to camera %d\n",
+		 icd->devnum);
+
+	pxa_camera_activate(pcdev);
+	ret = icd->ops->init(icd);
+
+	if (!ret)
+		pcdev->icd = icd;
+
+ebusy:
+	mutex_unlock(&camera_lock);
+
+	return ret;
+}
+
+static void pxa_camera_remove_device(struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+	struct pxa_camera_dev *pcdev = ici->priv;
+
+	BUG_ON(icd != pcdev->icd);
+
+	dev_info(&icd->dev, "PXA Camera driver detached from camera %d\n",
+		 icd->devnum);
+
+	/* disable capture, disable interrupts */
+	CICR0 = 0x3ff;
+
+	/* Stop DMA engine */
+	DCSR(pcdev->dma_chans[0]) = 0;
+	DCSR(pcdev->dma_chans[1]) = 0;
+	DCSR(pcdev->dma_chans[2]) = 0;
+
+	icd->ops->release(icd);
+
+	pxa_camera_deactivate(pcdev);
+
+	pcdev->icd = NULL;
+}
+
+static int test_platform_param(struct pxa_camera_dev *pcdev,
+			       unsigned char buswidth, unsigned long *flags)
+{
+	/*
+	 * Platform specified synchronization and pixel clock polarities are
+	 * only a recommendation and are only used during probing. The PXA270
+	 * quick capture interface supports both.
+	 */
+	*flags = (pcdev->platform_flags & PXA_CAMERA_MASTER ?
+		  SOCAM_MASTER : SOCAM_SLAVE) |
+		SOCAM_HSYNC_ACTIVE_HIGH |
+		SOCAM_HSYNC_ACTIVE_LOW |
+		SOCAM_VSYNC_ACTIVE_HIGH |
+		SOCAM_VSYNC_ACTIVE_LOW |
+		SOCAM_PCLK_SAMPLE_RISING |
+		SOCAM_PCLK_SAMPLE_FALLING;
+
+	/* If requested data width is supported by the platform, use it */
+	switch (buswidth) {
+	case 10:
+		if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10))
+			return -EINVAL;
+		*flags |= SOCAM_DATAWIDTH_10;
+		break;
+	case 9:
+		if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9))
+			return -EINVAL;
+		*flags |= SOCAM_DATAWIDTH_9;
+		break;
+	case 8:
+		if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8))
+			return -EINVAL;
+		*flags |= SOCAM_DATAWIDTH_8;
+	}
+
+	return 0;
+}
+
+static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
+{
+	struct soc_camera_host *ici =
+		to_soc_camera_host(icd->dev.parent);
+	struct pxa_camera_dev *pcdev = ici->priv;
+	unsigned long dw, bpp, bus_flags, camera_flags, common_flags;
+	u32 cicr0, cicr1, cicr4 = 0;
+	int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags);
+
+	if (ret < 0)
+		return ret;
+
+	camera_flags = icd->ops->query_bus_param(icd);
+
+	common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags);
+	if (!common_flags)
+		return -EINVAL;
+
+	pcdev->channels = 1;
+
+	/* Make choises, based on platform preferences */
+	if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) &&
+	    (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) {
+		if (pcdev->platform_flags & PXA_CAMERA_HSP)
+			common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH;
+		else
+			common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW;
+	}
+
+	if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) &&
+	    (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) {
+		if (pcdev->platform_flags & PXA_CAMERA_VSP)
+			common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH;
+		else
+			common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW;
+	}
+
+	if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) &&
+	    (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) {
+		if (pcdev->platform_flags & PXA_CAMERA_PCP)
+			common_flags &= ~SOCAM_PCLK_SAMPLE_RISING;
+		else
+			common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING;
+	}
+
+	ret = icd->ops->set_bus_param(icd, common_flags);
+	if (ret < 0)
+		return ret;
+
+	/* Datawidth is now guaranteed to be equal to one of the three values.
+	 * We fix bit-per-pixel equal to data-width... */
+	switch (common_flags & SOCAM_DATAWIDTH_MASK) {
+	case SOCAM_DATAWIDTH_10:
+		icd->buswidth = 10;
+		dw = 4;
+		bpp = 0x40;
+		break;
+	case SOCAM_DATAWIDTH_9:
+		icd->buswidth = 9;
+		dw = 3;
+		bpp = 0x20;
+		break;
+	default:
+		/* Actually it can only be 8 now,
+		 * default is just to silence compiler warnings */
+	case SOCAM_DATAWIDTH_8:
+		icd->buswidth = 8;
+		dw = 2;
+		bpp = 0;
+	}
+
+	if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
+		cicr4 |= CICR4_PCLK_EN;
+	if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN)
+		cicr4 |= CICR4_MCLK_EN;
+	if (common_flags & SOCAM_PCLK_SAMPLE_FALLING)
+		cicr4 |= CICR4_PCP;
+	if (common_flags & SOCAM_HSYNC_ACTIVE_LOW)
+		cicr4 |= CICR4_HSP;
+	if (common_flags & SOCAM_VSYNC_ACTIVE_LOW)
+		cicr4 |= CICR4_VSP;
+
+	cicr0 = CICR0;
+	if (cicr0 & CICR0_ENB)
+		CICR0 = cicr0 & ~CICR0_ENB;
+
+	cicr1 = CICR1_PPL_VAL(icd->width - 1) | bpp | dw;
+
+	switch (pixfmt) {
+	case V4L2_PIX_FMT_YUV422P:
+		pcdev->channels = 3;
+		cicr1 |= CICR1_YCBCR_F;
+	case V4L2_PIX_FMT_YUYV:
+		cicr1 |= CICR1_COLOR_SP_VAL(2);
+		break;
+	case V4L2_PIX_FMT_RGB555:
+		cicr1 |= CICR1_RGB_BPP_VAL(1) | CICR1_RGBT_CONV_VAL(2) |
+			CICR1_TBIT | CICR1_COLOR_SP_VAL(1);
+		break;
+	case V4L2_PIX_FMT_RGB565:
+		cicr1 |= CICR1_COLOR_SP_VAL(1) | CICR1_RGB_BPP_VAL(2);
+		break;
+	}
+
+	CICR1 = cicr1;
+	CICR2 = 0;
+	CICR3 = CICR3_LPF_VAL(icd->height - 1) |
+		CICR3_BFW_VAL(min((unsigned short)255, icd->y_skip_top));
+	CICR4 = mclk_get_divisor(pcdev) | cicr4;
+
+	/* CIF interrupts are not used, only DMA */
+	CICR0 = (pcdev->platform_flags & PXA_CAMERA_MASTER ?
+		 CICR0_SIM_MP : (CICR0_SL_CAP_EN | CICR0_SIM_SP)) |
+		CICR0_DMAEN | CICR0_IRQ_MASK | (cicr0 & CICR0_ENB);
+
+	return 0;
+}
+
+static int pxa_camera_try_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
+{
+	struct soc_camera_host *ici =
+		to_soc_camera_host(icd->dev.parent);
+	struct pxa_camera_dev *pcdev = ici->priv;
+	unsigned long bus_flags, camera_flags;
+	int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags);
+
+	if (ret < 0)
+		return ret;
+
+	camera_flags = icd->ops->query_bus_param(icd);
+
+	return soc_camera_bus_param_compatible(camera_flags, bus_flags) ? 0 : -EINVAL;
+}
+
+static int pxa_camera_set_fmt_cap(struct soc_camera_device *icd,
+				  __u32 pixfmt, struct v4l2_rect *rect)
+{
+	return icd->ops->set_fmt_cap(icd, pixfmt, rect);
+}
+
+static int pxa_camera_try_fmt_cap(struct soc_camera_device *icd,
+				  struct v4l2_format *f)
+{
+	/* limit to pxa hardware capabilities */
+	if (f->fmt.pix.height < 32)
+		f->fmt.pix.height = 32;
+	if (f->fmt.pix.height > 2048)
+		f->fmt.pix.height = 2048;
+	if (f->fmt.pix.width < 48)
+		f->fmt.pix.width = 48;
+	if (f->fmt.pix.width > 2048)
+		f->fmt.pix.width = 2048;
+	f->fmt.pix.width &= ~0x01;
+
+	/* limit to sensor capabilities */
+	return icd->ops->try_fmt_cap(icd, f);
+}
+
+static int pxa_camera_reqbufs(struct soc_camera_file *icf,
+			      struct v4l2_requestbuffers *p)
+{
+	int i;
+
+	/* This is for locking debugging only. I removed spinlocks and now I
+	 * check whether .prepare is ever called on a linked buffer, or whether
+	 * a dma IRQ can occur for an in-work or unlinked buffer. Until now
+	 * it hadn't triggered */
+	for (i = 0; i < p->count; i++) {
+		struct pxa_buffer *buf = container_of(icf->vb_vidq.bufs[i],
+						      struct pxa_buffer, vb);
+		buf->inwork = 0;
+		INIT_LIST_HEAD(&buf->vb.queue);
+	}
+
+	return 0;
+}
+
+static unsigned int pxa_camera_poll(struct file *file, poll_table *pt)
+{
+	struct soc_camera_file *icf = file->private_data;
+	struct pxa_buffer *buf;
+
+	buf = list_entry(icf->vb_vidq.stream.next, struct pxa_buffer,
+			 vb.stream);
+
+	poll_wait(file, &buf->vb.done, pt);
+
+	if (buf->vb.state == VIDEOBUF_DONE ||
+	    buf->vb.state == VIDEOBUF_ERROR)
+		return POLLIN|POLLRDNORM;
+
+	return 0;
+}
+
+static int pxa_camera_querycap(struct soc_camera_host *ici,
+			       struct v4l2_capability *cap)
+{
+	/* cap->name is set by the firendly caller:-> */
+	strlcpy(cap->card, pxa_cam_driver_description, sizeof(cap->card));
+	cap->version = PXA_CAM_VERSION_CODE;
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+	return 0;
+}
+
+static spinlock_t *pxa_camera_spinlock_alloc(struct soc_camera_file *icf)
+{
+	struct soc_camera_host *ici =
+		to_soc_camera_host(icf->icd->dev.parent);
+	struct pxa_camera_dev *pcdev = ici->priv;
+
+	return &pcdev->lock;
+}
+
+static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
+	.owner		= THIS_MODULE,
+	.add		= pxa_camera_add_device,
+	.remove		= pxa_camera_remove_device,
+	.set_fmt_cap	= pxa_camera_set_fmt_cap,
+	.try_fmt_cap	= pxa_camera_try_fmt_cap,
+	.reqbufs	= pxa_camera_reqbufs,
+	.poll		= pxa_camera_poll,
+	.querycap	= pxa_camera_querycap,
+	.try_bus_param	= pxa_camera_try_bus_param,
+	.set_bus_param	= pxa_camera_set_bus_param,
+	.spinlock_alloc	= pxa_camera_spinlock_alloc,
+};
+
+/* Should be allocated dynamically too, but we have only one. */
+static struct soc_camera_host pxa_soc_camera_host = {
+	.drv_name		= PXA_CAM_DRV_NAME,
+	.vbq_ops		= &pxa_videobuf_ops,
+	.msize			= sizeof(struct pxa_buffer),
+	.ops			= &pxa_soc_camera_host_ops,
+};
+
+static int pxa_camera_probe(struct platform_device *pdev)
+{
+	struct pxa_camera_dev *pcdev;
+	struct resource *res;
+	void __iomem *base;
+	unsigned int irq;
+	int err = 0;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	irq = platform_get_irq(pdev, 0);
+	if (!res || !irq) {
+		err = -ENODEV;
+		goto exit;
+	}
+
+	pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL);
+	if (!pcdev) {
+		dev_err(&pdev->dev, "Could not allocate pcdev\n");
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	pcdev->clk = clk_get(&pdev->dev, "CAMCLK");
+	if (IS_ERR(pcdev->clk)) {
+		err = PTR_ERR(pcdev->clk);
+		goto exit_kfree;
+	}
+
+	dev_set_drvdata(&pdev->dev, pcdev);
+	pcdev->res = res;
+
+	pcdev->pdata = pdev->dev.platform_data;
+	pcdev->platform_flags = pcdev->pdata->flags;
+	if (!(pcdev->platform_flags & (PXA_CAMERA_DATAWIDTH_8 |
+			PXA_CAMERA_DATAWIDTH_9 | PXA_CAMERA_DATAWIDTH_10))) {
+		/* Platform hasn't set available data widths. This is bad.
+		 * Warn and use a default. */
+		dev_warn(&pdev->dev, "WARNING! Platform hasn't set available "
+			 "data widths, using default 10 bit\n");
+		pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_10;
+	}
+	pcdev->platform_mclk_10khz = pcdev->pdata->mclk_10khz;
+	if (!pcdev->platform_mclk_10khz) {
+		dev_warn(&pdev->dev,
+			 "mclk_10khz == 0! Please, fix your platform data. "
+			 "Using default 20MHz\n");
+		pcdev->platform_mclk_10khz = 2000;
+	}
+
+	INIT_LIST_HEAD(&pcdev->capture);
+	spin_lock_init(&pcdev->lock);
+
+	/*
+	 * Request the regions.
+	 */
+	if (!request_mem_region(res->start, res->end - res->start + 1,
+				PXA_CAM_DRV_NAME)) {
+		err = -EBUSY;
+		goto exit_clk;
+	}
+
+	base = ioremap(res->start, res->end - res->start + 1);
+	if (!base) {
+		err = -ENOMEM;
+		goto exit_release;
+	}
+	pcdev->irq = irq;
+	pcdev->base = base;
+	pcdev->dev = &pdev->dev;
+
+	/* request dma */
+	pcdev->dma_chans[0] = pxa_request_dma("CI_Y", DMA_PRIO_HIGH,
+					      pxa_camera_dma_irq_y, pcdev);
+	if (pcdev->dma_chans[0] < 0) {
+		dev_err(pcdev->dev, "Can't request DMA for Y\n");
+		err = -ENOMEM;
+		goto exit_iounmap;
+	}
+	dev_dbg(pcdev->dev, "got DMA channel %d\n", pcdev->dma_chans[0]);
+
+	pcdev->dma_chans[1] = pxa_request_dma("CI_U", DMA_PRIO_HIGH,
+					      pxa_camera_dma_irq_u, pcdev);
+	if (pcdev->dma_chans[1] < 0) {
+		dev_err(pcdev->dev, "Can't request DMA for U\n");
+		err = -ENOMEM;
+		goto exit_free_dma_y;
+	}
+	dev_dbg(pcdev->dev, "got DMA channel (U) %d\n", pcdev->dma_chans[1]);
+
+	pcdev->dma_chans[2] = pxa_request_dma("CI_V", DMA_PRIO_HIGH,
+					      pxa_camera_dma_irq_v, pcdev);
+	if (pcdev->dma_chans[0] < 0) {
+		dev_err(pcdev->dev, "Can't request DMA for V\n");
+		err = -ENOMEM;
+		goto exit_free_dma_u;
+	}
+	dev_dbg(pcdev->dev, "got DMA channel (V) %d\n", pcdev->dma_chans[2]);
+
+	DRCMR68 = pcdev->dma_chans[0] | DRCMR_MAPVLD;
+	DRCMR69 = pcdev->dma_chans[1] | DRCMR_MAPVLD;
+	DRCMR70 = pcdev->dma_chans[2] | DRCMR_MAPVLD;
+
+	/* request irq */
+	err = request_irq(pcdev->irq, pxa_camera_irq, 0, PXA_CAM_DRV_NAME,
+			  pcdev);
+	if (err) {
+		dev_err(pcdev->dev, "Camera interrupt register failed \n");
+		goto exit_free_dma;
+	}
+
+	pxa_soc_camera_host.priv	= pcdev;
+	pxa_soc_camera_host.dev.parent	= &pdev->dev;
+	pxa_soc_camera_host.nr		= pdev->id;
+	err = soc_camera_host_register(&pxa_soc_camera_host);
+	if (err)
+		goto exit_free_irq;
+
+	return 0;
+
+exit_free_irq:
+	free_irq(pcdev->irq, pcdev);
+exit_free_dma:
+	pxa_free_dma(pcdev->dma_chans[2]);
+exit_free_dma_u:
+	pxa_free_dma(pcdev->dma_chans[1]);
+exit_free_dma_y:
+	pxa_free_dma(pcdev->dma_chans[0]);
+exit_iounmap:
+	iounmap(base);
+exit_release:
+	release_mem_region(res->start, res->end - res->start + 1);
+exit_clk:
+	clk_put(pcdev->clk);
+exit_kfree:
+	kfree(pcdev);
+exit:
+	return err;
+}
+
+static int __devexit pxa_camera_remove(struct platform_device *pdev)
+{
+	struct pxa_camera_dev *pcdev = platform_get_drvdata(pdev);
+	struct resource *res;
+
+	clk_put(pcdev->clk);
+
+	pxa_free_dma(pcdev->dma_chans[0]);
+	pxa_free_dma(pcdev->dma_chans[1]);
+	pxa_free_dma(pcdev->dma_chans[2]);
+	free_irq(pcdev->irq, pcdev);
+
+	soc_camera_host_unregister(&pxa_soc_camera_host);
+
+	iounmap(pcdev->base);
+
+	res = pcdev->res;
+	release_mem_region(res->start, res->end - res->start + 1);
+
+	kfree(pcdev);
+
+	dev_info(&pdev->dev, "PXA Camera driver unloaded\n");
+
+	return 0;
+}
+
+static struct platform_driver pxa_camera_driver = {
+	.driver 	= {
+		.name	= PXA_CAM_DRV_NAME,
+	},
+	.probe		= pxa_camera_probe,
+	.remove		= __exit_p(pxa_camera_remove),
+};
+
+
+static int __devinit pxa_camera_init(void)
+{
+	return platform_driver_register(&pxa_camera_driver);
+}
+
+static void __exit pxa_camera_exit(void)
+{
+	return platform_driver_unregister(&pxa_camera_driver);
+}
+
+module_init(pxa_camera_init);
+module_exit(pxa_camera_exit);
+
+MODULE_DESCRIPTION("PXA27x SoC Camera Host driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
index f55d6e8..ec8c65d 100644
--- a/drivers/media/video/saa5249.c
+++ b/drivers/media/video/saa5249.c
@@ -701,7 +701,9 @@
 	.open		= saa5249_open,
 	.release       	= saa5249_release,
 	.ioctl          = saa5249_ioctl,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
+#endif
 	.llseek         = no_llseek,
 };
 
diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c
index 72e344a..716ee7f 100644
--- a/drivers/media/video/saa6588.c
+++ b/drivers/media/video/saa6588.c
@@ -44,10 +44,10 @@
 I2C_CLIENT_INSMOD;
 
 /* insmod options */
-static unsigned int debug = 0;
-static unsigned int xtal = 0;
-static unsigned int rbds = 0;
-static unsigned int plvl = 0;
+static unsigned int debug;
+static unsigned int xtal;
+static unsigned int rbds;
+static unsigned int plvl;
 static unsigned int bufblocks = 100;
 
 module_param(debug, int, 0644);
diff --git a/drivers/media/video/saa7110.c b/drivers/media/video/saa7110.c
index 1df2602..4aa82b3 100644
--- a/drivers/media/video/saa7110.c
+++ b/drivers/media/video/saa7110.c
@@ -46,7 +46,7 @@
 #include <media/v4l2-common.h>
 #include <linux/video_decoder.h>
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
diff --git a/drivers/media/video/saa7111.c b/drivers/media/video/saa7111.c
index a0772c5..96c3d43 100644
--- a/drivers/media/video/saa7111.c
+++ b/drivers/media/video/saa7111.c
@@ -55,7 +55,7 @@
 #define I2C_NAME(s) (s)->name
 
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
diff --git a/drivers/media/video/saa7114.c b/drivers/media/video/saa7114.c
index bf91a4f..e790755 100644
--- a/drivers/media/video/saa7114.c
+++ b/drivers/media/video/saa7114.c
@@ -56,7 +56,7 @@
 #define I2C_NAME(x) (x)->name
 
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index 41e5e51..416d05d 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -57,7 +57,7 @@
 		"Hans Verkuil, Mauro Carvalho Chehab");
 MODULE_LICENSE("GPL");
 
-static int debug = 0;
+static int debug;
 module_param(debug, bool, 0644);
 
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
@@ -957,7 +957,7 @@
 
 		if (std == V4L2_STD_PAL_M) {
 			reg |= 0x30;
-		} else if (std == V4L2_STD_PAL_N) {
+		} else if (std == V4L2_STD_PAL_Nc) {
 			reg |= 0x20;
 		} else if (std == V4L2_STD_PAL_60) {
 			reg |= 0x10;
diff --git a/drivers/media/video/saa711x.c b/drivers/media/video/saa711x.c
index 80bf911..cedb988 100644
--- a/drivers/media/video/saa711x.c
+++ b/drivers/media/video/saa711x.c
@@ -48,7 +48,7 @@
 
 #include <linux/video_decoder.h>
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, " Set the default Debug level.  Default: 0 (Off) - (0-1)");
 
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig
index 96bc3b1..e086f14 100644
--- a/drivers/media/video/saa7134/Kconfig
+++ b/drivers/media/video/saa7134/Kconfig
@@ -37,6 +37,7 @@
 	select DVB_TDA826X if !DVB_FE_CUSTOMISE
 	select DVB_TDA827X if !DVB_FE_CUSTOMISE
 	select DVB_ISL6421 if !DVB_FE_CUSTOMISE
+	select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
 	---help---
 	  This adds support for DVB cards based on the
 	  Philips saa7134 chip.
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index 047add8..ba30824 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -31,7 +31,7 @@
 #include "saa7134.h"
 #include "saa7134-reg.h"
 
-static unsigned int debug  = 0;
+static unsigned int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug,"enable debug messages [alsa]");
 
@@ -503,7 +503,7 @@
 	/* release the old buffer */
 	if (substream->runtime->dma_area) {
 		saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
-		videobuf_pci_dma_unmap(dev->pci, &dev->dmasound.dma);
+		videobuf_sg_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
 		dsp_buffer_free(dev);
 		substream->runtime->dma_area = NULL;
 	}
@@ -519,12 +519,12 @@
 		return err;
 	}
 
-	if (0 != (err = videobuf_pci_dma_map(dev->pci, &dev->dmasound.dma))) {
+	if (0 != (err = videobuf_sg_dma_map(&dev->pci->dev, &dev->dmasound.dma))) {
 		dsp_buffer_free(dev);
 		return err;
 	}
 	if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt))) {
-		videobuf_pci_dma_unmap(dev->pci, &dev->dmasound.dma);
+		videobuf_sg_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
 		dsp_buffer_free(dev);
 		return err;
 	}
@@ -533,7 +533,7 @@
 						dev->dmasound.dma.sglen,
 						0))) {
 		saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
-		videobuf_pci_dma_unmap(dev->pci, &dev->dmasound.dma);
+		videobuf_sg_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
 		dsp_buffer_free(dev);
 		return err;
 	}
@@ -569,7 +569,7 @@
 
 	if (substream->runtime->dma_area) {
 		saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
-		videobuf_pci_dma_unmap(dev->pci, &dev->dmasound.dma);
+		videobuf_sg_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
 		dsp_buffer_free(dev);
 		substream->runtime->dma_area = NULL;
 	}
@@ -954,10 +954,8 @@
 	if (chip->dev->dmasound.priv_data == NULL)
 		return;
 
-	if (chip->irq >= 0) {
-		synchronize_irq(chip->irq);
+	if (chip->irq >= 0)
 		free_irq(chip->irq, &chip->dev->dmasound);
-	}
 
 	chip->dev->dmasound.priv_data = NULL;
 
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 6f57442..9837595 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -22,11 +22,15 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
 
 #include "saa7134-reg.h"
 #include "saa7134.h"
+#include "tuner-xc2028.h"
 #include <media/v4l2-common.h>
 #include <media/tveeprom.h>
+#include "tea5767.h"
 
 /* commly used strings */
 static char name_mute[]    = "mute";
@@ -1046,7 +1050,7 @@
 	},
 	[SAA7134_BOARD_MANLI_MTV002] = {
 		/* Ognjen Nastic <ognjen@logosoft.ba> */
-		.name           = "Manli MuchTV M-TV002/Behold TV 403 FM",
+		.name           = "Manli MuchTV M-TV002",
 		.audio_clock    = 0x00200000,
 		.tuner_type     = TUNER_PHILIPS_PAL,
 		.radio_type     = UNSET,
@@ -1073,7 +1077,7 @@
 	},
 	[SAA7134_BOARD_MANLI_MTV001] = {
 		/* Ognjen Nastic <ognjen@logosoft.ba> UNTESTED */
-		.name           = "Manli MuchTV M-TV001/Behold TV 401",
+		.name           = "Manli MuchTV M-TV001",
 		.audio_clock    = 0x00200000,
 		.tuner_type     = TUNER_PHILIPS_PAL,
 		.radio_type     = UNSET,
@@ -2195,6 +2199,8 @@
 	},
 	[SAA7134_BOARD_BEHOLD_409FM] = {
 		/* <http://tuner.beholder.ru>, Sergey <skiv@orel.ru> */
+		/*       Beholder Intl. Ltd. 2008      */
+		/*Dmitry Belimov <d.belimov@gmail.com> */
 		.name           = "Beholder BeholdTV 409 FM",
 		.audio_clock    = 0x00187de7,
 		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
@@ -2202,6 +2208,7 @@
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask       = 0x00008000,
 		.inputs         = {{
 			  .name = name_tv,
 			  .vmux = 3,
@@ -2908,15 +2915,13 @@
 		}},
 	},
 	[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 */
+		/* The second saa7134 on this card only serves as DVB-S host bridge */
 		.name           = "Medion 7134 Bridge #2",
 		.audio_clock    = 0x00187de7,
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
 	},
 	[SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS] = {
 		.name		= "LifeView FlyDVB-T Hybrid Cardbus/MSI TV @nywhere A/D NB",
@@ -3330,7 +3335,7 @@
   /*	Juan Pablo Sormani <sorman@gmail.com> */
 		.name           = "Encore ENLTV-FM",
 		.audio_clock    = 0x00200000,
-		.tuner_type     = TUNER_PHILIPS_ATSC,
+		.tuner_type     = TUNER_PHILIPS_FCV1236D,
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
@@ -3575,12 +3580,15 @@
 		}},
 	},
 	[SAA7134_BOARD_BEHOLD_401] = {
+		/*       Beholder Intl. Ltd. 2008      */
+		/*Dmitry Belimov <d.belimov@gmail.com> */
 		.name           = "Beholder BeholdTV 401",
 		.audio_clock    = 0x00187de7,
 		.tuner_type     = TUNER_PHILIPS_FQ1216ME,
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
+		.gpiomask       = 0x00008000,
 		.inputs         = {{
 			.name = name_svideo,
 			.vmux = 8,
@@ -3601,12 +3609,15 @@
 		},
 	},
 	[SAA7134_BOARD_BEHOLD_403] = {
+		/*       Beholder Intl. Ltd. 2008      */
+		/*Dmitry Belimov <d.belimov@gmail.com> */
 		.name           = "Beholder BeholdTV 403",
 		.audio_clock    = 0x00187de7,
 		.tuner_type     = TUNER_PHILIPS_FQ1216ME,
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
+		.gpiomask       = 0x00008000,
 		.inputs         = {{
 			.name = name_svideo,
 			.vmux = 8,
@@ -3623,12 +3634,15 @@
 		}},
 	},
 	[SAA7134_BOARD_BEHOLD_403FM] = {
+		/*       Beholder Intl. Ltd. 2008      */
+		/*Dmitry Belimov <d.belimov@gmail.com> */
 		.name           = "Beholder BeholdTV 403 FM",
 		.audio_clock    = 0x00187de7,
 		.tuner_type     = TUNER_PHILIPS_FQ1216ME,
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
+		.gpiomask       = 0x00008000,
 		.inputs         = {{
 			.name = name_svideo,
 			.vmux = 8,
@@ -3649,6 +3663,8 @@
 		},
 	},
 	[SAA7134_BOARD_BEHOLD_405] = {
+		/*       Beholder Intl. Ltd. 2008      */
+		/*Dmitry Belimov <d.belimov@gmail.com> */
 		.name           = "Beholder BeholdTV 405",
 		.audio_clock    = 0x00187de7,
 		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
@@ -3656,6 +3672,7 @@
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask       = 0x00008000,
 		.inputs         = {{
 			.name = name_svideo,
 			.vmux = 8,
@@ -3673,6 +3690,8 @@
 	},
 	[SAA7134_BOARD_BEHOLD_405FM] = {
 		/* Sergey <skiv@orel.ru> */
+		/*       Beholder Intl. Ltd. 2008      */
+		/*Dmitry Belimov <d.belimov@gmail.com> */
 		.name           = "Beholder BeholdTV 405 FM",
 		.audio_clock    = 0x00187de7,
 		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
@@ -3680,6 +3699,7 @@
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask       = 0x00008000,
 		.inputs         = {{
 			.name = name_svideo,
 			.vmux = 8,
@@ -3700,6 +3720,8 @@
 		},
 	},
 	[SAA7134_BOARD_BEHOLD_407] = {
+		/*       Beholder Intl. Ltd. 2008      */
+		/*Dmitry Belimov <d.belimov@gmail.com> */
 		.name 		= "Beholder BeholdTV 407",
 		.audio_clock 	= 0x00187de7,
 		.tuner_type 	= TUNER_PHILIPS_FM1216ME_MK3,
@@ -3707,7 +3729,7 @@
 		.tuner_addr 	= ADDR_UNSET,
 		.radio_addr 	= ADDR_UNSET,
 		.tda9887_conf 	= TDA9887_PRESENT,
-		.gpiomask = 0xc0c000,
+		.gpiomask       = 0x00008000,
 		.inputs = {{
 			.name = name_svideo,
 			.vmux = 8,
@@ -3727,6 +3749,8 @@
 		}},
 	},
 	[SAA7134_BOARD_BEHOLD_407FM] = {
+		/*       Beholder Intl. Ltd. 2008      */
+		/*Dmitry Belimov <d.belimov@gmail.com> */
 		.name 		= "Beholder BeholdTV 407 FM",
 		.audio_clock 	= 0x00187de7,
 		.tuner_type 	= TUNER_PHILIPS_FM1216ME_MK3,
@@ -3734,7 +3758,7 @@
 		.tuner_addr 	= ADDR_UNSET,
 		.radio_addr 	= ADDR_UNSET,
 		.tda9887_conf 	= TDA9887_PRESENT,
-		.gpiomask = 0xc0c000,
+		.gpiomask       = 0x00008000,
 		.inputs = {{
 			.name = name_svideo,
 			.vmux = 8,
@@ -3759,6 +3783,8 @@
 		},
 	},
 	[SAA7134_BOARD_BEHOLD_409] = {
+		/*       Beholder Intl. Ltd. 2008      */
+		/*Dmitry Belimov <d.belimov@gmail.com> */
 		.name           = "Beholder BeholdTV 409",
 		.audio_clock    = 0x00187de7,
 		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
@@ -3766,6 +3792,7 @@
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask       = 0x00008000,
 		.inputs         = {{
 			.name = name_tv,
 			.vmux = 3,
@@ -3782,6 +3809,8 @@
 		}},
 	},
 	[SAA7134_BOARD_BEHOLD_505FM] = {
+		/*       Beholder Intl. Ltd. 2008      */
+		/*Dmitry Belimov <d.belimov@gmail.com> */
 		.name           = "Beholder BeholdTV 505 FM/RDS",
 		.audio_clock    = 0x00200000,
 		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
@@ -3789,6 +3818,7 @@
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask       = 0x00008000,
 		.inputs         = {{
 			.name = name_tv,
 			.vmux = 3,
@@ -3813,6 +3843,8 @@
 		},
 	},
 	[SAA7134_BOARD_BEHOLD_507_9FM] = {
+		/*       Beholder Intl. Ltd. 2008      */
+		/*Dmitry Belimov <d.belimov@gmail.com> */
 		.name           = "Beholder BeholdTV 507 FM/RDS / BeholdTV 509 FM",
 		.audio_clock    = 0x00187de7,
 		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
@@ -3820,6 +3852,7 @@
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask       = 0x00008000,
 		.inputs         = {{
 			.name = name_tv,
 			.vmux = 3,
@@ -3840,6 +3873,8 @@
 		},
 	},
 	[SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM] = {
+		/*       Beholder Intl. Ltd. 2008      */
+		/*Dmitry Belimov <d.belimov@gmail.com> */
 		.name           = "Beholder BeholdTV Columbus TVFM",
 		.audio_clock    = 0x00187de7,
 		.tuner_type     = TUNER_ALPS_TSBE5_PAL,
@@ -3847,23 +3882,28 @@
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
+		.gpiomask       = 0x000A8004,
 		.inputs         = {{
 			.name = name_tv,
 			.vmux = 3,
 			.amux = TV,
 			.tv   = 1,
-		},{
+			.gpio = 0x000A8004,
+		}, {
 			.name = name_comp1,
 			.vmux = 1,
 			.amux = LINE1,
-		},{
+			.gpio = 0x000A8000,
+		}, {
 			.name = name_svideo,
 			.vmux = 8,
 			.amux = LINE1,
-		}},
+			.gpio = 0x000A8000,
+		} },
 		.radio = {
 			.name = name_radio,
 			.amux = LINE2,
+			.gpio = 0x000A8000,
 		},
 	},
 	[SAA7134_BOARD_BEHOLD_607_9FM] = {
@@ -3992,6 +4032,221 @@
 			.gpio = 0x6000,
 		},
 	},
+	[SAA7134_BOARD_PHILIPS_SNAKE] = {
+		.name           = "NXP Snake DVB-S reference design",
+		.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,
+			.vmux   = 3,
+			.amux   = LINE1,
+		}, {
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE1,
+		} },
+	},
+	[SAA7134_BOARD_CREATIX_CTX953] = {
+		.name         = "Medion/Creatix CTX953 Hybrid",
+		.audio_clock  = 0x00187de7,
+		.tuner_type   = TUNER_PHILIPS_TDA8290,
+		.radio_type   = UNSET,
+		.tuner_addr   = ADDR_UNSET,
+		.radio_addr   = ADDR_UNSET,
+		.tuner_config = 0,
+		.mpeg         = SAA7134_MPEG_DVB,
+		.inputs       = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+	},
+	[SAA7134_BOARD_MSI_TVANYWHERE_AD11] = {
+		.name           = "MSI TV@nywhere A/D v1.1",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tuner_config   = 2,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.gpiomask       = 0x0200000,
+		.inputs = { {
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		}, {
+			.name   = name_comp1,
+			.vmux   = 3,
+			.amux   = LINE1,
+		}, {
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE1,
+		} },
+		.radio = {
+			.name   = name_radio,
+			.amux   = TV,
+			.gpio   = 0x0200000,
+		},
+	},
+	[SAA7134_BOARD_AVERMEDIA_CARDBUS_506] = {
+		.name           = "AVerMedia Cardbus TV/Radio (E506R)",
+		.audio_clock    = 0x187de7,
+		.tuner_type     = TUNER_XC2028,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		 /*
+		    TODO:
+		 .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 = LINE1,
+		 } },
+		 .radio = {
+			 .name = name_radio,
+			 .amux = TV,
+		 },
+	},
+	[SAA7134_BOARD_AVERMEDIA_A16D] = {
+		.name           = "AVerMedia Hybrid TV/Radio (A16D)",
+		.audio_clock    = 0x187de7,
+		.tuner_type     = TUNER_XC2028,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = LINE1,
+		},
+	},
+	[SAA7134_BOARD_AVERMEDIA_M115] = {
+		.name           = "Avermedia M115",
+		.audio_clock    = 0x187de7,
+		.tuner_type     = TUNER_XC2028,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		} },
+	},
+	[SAA7134_BOARD_VIDEOMATE_T750] = {
+		/* John Newbigin <jn@it.swin.edu.au> */
+		.name           = "Compro VideoMate T750",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_XC2028,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 3,
+			.amux   = TV,
+			.tv     = 1,
+		}, {
+			.name   = name_comp1,
+			.vmux   = 1,
+			.amux   = LINE2,
+		}, {
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE2,
+		} },
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+		}
+	},
+	[SAA7134_BOARD_AVERMEDIA_A700_PRO] = {
+		/* Matthias Schwarzott <zzam@gentoo.org> */
+		.name           = "Avermedia DVB-S Pro A700",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		/* no DVB support for now */
+		/* .mpeg           = SAA7134_MPEG_DVB, */
+		.inputs         = { {
+			.name = name_comp,
+			.vmux = 1,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 6,
+			.amux = LINE1,
+		} },
+	},
+	[SAA7134_BOARD_AVERMEDIA_A700_HYBRID] = {
+		/* Matthias Schwarzott <zzam@gentoo.org> */
+		.name           = "Avermedia DVB-S Hybrid+FM A700",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_ABSENT, /* TUNER_XC2028 */
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		/* no DVB support for now */
+		/* .mpeg           = SAA7134_MPEG_DVB, */
+		.inputs         = { {
+			.name = name_comp,
+			.vmux = 1,
+			.amux = LINE1,
+		}, {
+			.name = name_svideo,
+			.vmux = 6,
+			.amux = LINE1,
+		} },
+	},
 };
 
 const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -4224,6 +4479,18 @@
 		.driver_data  = SAA7134_BOARD_MD2819,
 	},{
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0xa7a1,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_A700_PRO,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0xa7a2,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_A700_HYBRID,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
 		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
 		.subdevice    = 0x2115,
@@ -4942,7 +5209,43 @@
 		.subvendor    = 0x1822, /*Twinhan Technology Co. Ltd*/
 		.subdevice    = 0x0022,
 		.driver_data  = SAA7134_BOARD_TWINHAN_DTV_DVB_3056,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x16be,
+		.subdevice    = 0x0010, /* Medion version CTX953_V.1.4.3 */
+		.driver_data  = SAA7134_BOARD_CREATIX_CTX953,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1462, /* MSI */
+		.subdevice    = 0x8625, /* TV@nywhere A/D v1.1 */
+		.driver_data  = SAA7134_BOARD_MSI_TVANYWHERE_AD11,
 	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0xf436,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_CARDBUS_506,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0xf936,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_A16D,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0xa836,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_M115,
+	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x185b,
+		.subdevice    = 0xc900,
+		.driver_data  = SAA7134_BOARD_VIDEOMATE_T750,
+	}, {
 		/* --- boards without eeprom + subsystem ID --- */
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -4998,6 +5301,77 @@
 	       dev->name, dev->name, dev->name);
 }
 
+static int saa7134_xc2028_callback(struct saa7134_dev *dev,
+				   int command, int arg)
+{
+	switch (command) {
+	case XC2028_TUNER_RESET:
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x06e20000, 0x06e20000);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x06a20000, 0x06a20000);
+		mdelay(250);
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x06e20000, 0);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x06a20000, 0);
+		mdelay(250);
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x06e20000, 0x06e20000);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x06a20000, 0x06a20000);
+		mdelay(250);
+		saa_andorl(SAA7133_ANALOG_IO_SELECT >> 2, 0x02, 0x02);
+		saa_andorl(SAA7134_ANALOG_IN_CTRL1 >> 2, 0x81, 0x81);
+		saa_andorl(SAA7134_AUDIO_CLOCK0 >> 2, 0x03187de7, 0x03187de7);
+		saa_andorl(SAA7134_AUDIO_PLL_CTRL >> 2, 0x03, 0x03);
+		saa_andorl(SAA7134_AUDIO_CLOCKS_PER_FIELD0 >> 2,
+			   0x0001e000, 0x0001e000);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+
+static int saa7134_tda8290_callback(struct saa7134_dev *dev,
+				    int command, int arg)
+{
+	u8 sync_control;
+
+	switch (command) {
+	case 0: /* switch LNA gain through GPIO 22*/
+		saa7134_set_gpio(dev, 22, arg) ;
+		break;
+	case 1: /* vsync output at GPIO22. 50 / 60Hz */
+		saa_andorb(SAA7134_VIDEO_PORT_CTRL3, 0x80, 0x80);
+		saa_andorb(SAA7134_VIDEO_PORT_CTRL6, 0x0f, 0x03);
+		if (arg == 1)
+			sync_control = 11;
+		else
+			sync_control = 17;
+		saa_writeb(SAA7134_VGATE_START, sync_control);
+		saa_writeb(SAA7134_VGATE_STOP, sync_control + 1);
+		saa_andorb(SAA7134_MISC_VGATE_MSB, 0x03, 0x00);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int saa7134_tuner_callback(void *priv, int command, int arg)
+{
+	struct saa7134_dev *dev = priv;
+	if (dev != NULL) {
+		switch (dev->tuner_type) {
+		case TUNER_PHILIPS_TDA8290:
+			return saa7134_tda8290_callback(dev, command, arg);
+		case TUNER_XC2028:
+			return saa7134_xc2028_callback(dev, command, arg);
+		}
+	} else {
+		printk(KERN_ERR "saa7134: Error - device struct undefined.\n");
+		return -EINVAL;
+	}
+	return -EINVAL;
+}
+EXPORT_SYMBOL(saa7134_tuner_callback);
+
 /* ----------------------------------------------------------- */
 
 static void hauppauge_eeprom(struct saa7134_dev *dev, u8 *eeprom_data)
@@ -5067,6 +5441,7 @@
 	case SAA7134_BOARD_VIDEOMATE_DVBT_300:
 	case SAA7134_BOARD_VIDEOMATE_DVBT_200:
 	case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
+	case SAA7134_BOARD_VIDEOMATE_T750:
 	case SAA7134_BOARD_MANLI_MTV001:
 	case SAA7134_BOARD_MANLI_MTV002:
 	case SAA7134_BOARD_BEHOLD_409FM:
@@ -5133,11 +5508,29 @@
 		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08000000, 0x00000000);
 		break;
 	case SAA7134_BOARD_AVERMEDIA_CARDBUS:
-	case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
+	case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+	case SAA7134_BOARD_AVERMEDIA_M115:
+	case SAA7134_BOARD_AVERMEDIA_A16D:
+		/* power-down tuner chip */
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0xffffffff, 0);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0);
+		msleep(10);
 		/* power-up tuner chip */
 		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0xffffffff, 0xffffffff);
 		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0xffffffff);
-		msleep(1);
+		msleep(10);
+		break;
+	case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
+		/* power-down tuner chip */
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x000A8004, 0x000A8004);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x000A8004, 0);
+		msleep(10);
+		/* power-up tuner chip */
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x000A8004, 0x000A8004);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x000A8004, 0x000A8004);
+		msleep(10);
+		/* remote via GPIO */
+		dev->has_remote = SAA7134_REMOTE_GPIO;
 		break;
 	case SAA7134_BOARD_RTD_VFG7350:
 
@@ -5160,7 +5553,6 @@
 		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",
@@ -5172,6 +5564,15 @@
 		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x8c040007, 0x8c040007);
 		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0c0007cd, 0x0c0007cd);
 		break;
+	case SAA7134_BOARD_AVERMEDIA_A700_PRO:
+	case SAA7134_BOARD_AVERMEDIA_A700_HYBRID:
+		/* write windows gpio values */
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x80040100, 0x80040100);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x80040100, 0x00040100);
+		printk("%s: %s: hybrid analog/dvb card\n"
+		       "%s: Sorry, only the analog inputs are supported for now.\n",
+			dev->name, card(dev).name, dev->name);
+		break;
 	}
 	return 0;
 }
@@ -5200,11 +5601,16 @@
 		dev->tuner_type = saa7134_boards[dev->board].tuner_type;
 
 		if (TUNER_ABSENT != dev->tuner_type) {
-				tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
-				tun_setup.type = dev->tuner_type;
-				tun_setup.addr = ADDR_UNSET;
+			tun_setup.mode_mask = T_RADIO     |
+					      T_ANALOG_TV |
+					      T_DIGITAL_TV;
+			tun_setup.type = dev->tuner_type;
+			tun_setup.addr = ADDR_UNSET;
+			tun_setup.tuner_callback = saa7134_tuner_callback;
 
-				saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR, &tun_setup);
+			saa7134_i2c_call_clients(dev,
+						 TUNER_SET_TYPE_ADDR,
+						 &tun_setup);
 		}
 		break;
 	case SAA7134_BOARD_MD7134:
@@ -5275,14 +5681,25 @@
 						 &tda9887_cfg);
 		}
 
-		tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
+		tun_setup.mode_mask = T_RADIO     |
+				      T_ANALOG_TV |
+				      T_DIGITAL_TV;
 		tun_setup.type = dev->tuner_type;
 		tun_setup.addr = ADDR_UNSET;
 
-		saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup);
+		saa7134_i2c_call_clients(dev,
+					 TUNER_SET_TYPE_ADDR, &tun_setup);
 		}
 		break;
 	case SAA7134_BOARD_PHILIPS_EUROPA:
+		if (dev->autodetected && (dev->eedata[0x41] == 0x1c)) {
+			/* Reconfigure board as Snake reference design */
+			dev->board = SAA7134_BOARD_PHILIPS_SNAKE;
+			dev->tuner_type = saa7134_boards[dev->board].tuner_type;
+			printk(KERN_INFO "%s: Reconfigured board as %s\n",
+				dev->name, saa7134_boards[dev->board].name);
+			break;
+		}
 	case SAA7134_BOARD_VIDEOMATE_DVBT_300:
 	case SAA7134_BOARD_ASUS_EUROPA2_HYBRID:
 		/* The Philips EUROPA based hybrid boards have the tuner connected through
@@ -5333,6 +5750,7 @@
 	case SAA7134_BOARD_MEDION_MD8800_QUADRO:
 	case SAA7134_BOARD_AVERMEDIA_SUPER_007:
 	case SAA7134_BOARD_TWINHAN_DTV_DVB_3056:
+	case SAA7134_BOARD_CREATIX_CTX953:
 		/* this is a hybrid board, initialize to analog mode
 		 * and configure firmware eeprom address
 		 */
@@ -5402,13 +5820,46 @@
 			break;
 		}
 		break;
+	case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
+		{
+		struct v4l2_priv_tun_config tea5767_cfg;
+		struct tea5767_ctrl ctl;
+
+		dev->i2c_client.addr = 0xC0;
+		/* set TEA5767(analog FM) defines */
+		memset(&ctl, 0, sizeof(ctl));
+		ctl.xtal_freq = TEA5767_HIGH_LO_13MHz;
+		tea5767_cfg.tuner = TUNER_TEA5767;
+		tea5767_cfg.priv  = &ctl;
+		saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &tea5767_cfg);
+		}
+		break;
 	}
+
+	if (dev->tuner_type == TUNER_XC2028) {
+		struct v4l2_priv_tun_config  xc2028_cfg;
+		struct xc2028_ctrl           ctl;
+
+		memset(&xc2028_cfg, 0, sizeof(ctl));
+		memset(&ctl, 0, sizeof(ctl));
+
+		ctl.fname   = XC2028_DEFAULT_FIRMWARE;
+		ctl.max_len = 64;
+
+		switch (dev->board) {
+		case SAA7134_BOARD_AVERMEDIA_A16D:
+			ctl.demod = XC3028_FE_ZARLINK456;
+			break;
+		default:
+			ctl.demod = XC3028_FE_OREN538;
+			ctl.mts = 1;
+		}
+
+		xc2028_cfg.tuner = TUNER_XC2028;
+		xc2028_cfg.priv  = &ctl;
+
+		saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg);
+	}
+
 	return 0;
 }
-
-/* ----------------------------------------------------------- */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index 58ab163..eec1278 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -42,23 +42,23 @@
 
 /* ------------------------------------------------------------------ */
 
-static unsigned int irq_debug = 0;
+static unsigned int irq_debug;
 module_param(irq_debug, int, 0644);
 MODULE_PARM_DESC(irq_debug,"enable debug messages [IRQ handler]");
 
-static unsigned int core_debug = 0;
+static unsigned int core_debug;
 module_param(core_debug, int, 0644);
 MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
 
-static unsigned int gpio_tracking = 0;
+static unsigned int gpio_tracking;
 module_param(gpio_tracking, int, 0644);
 MODULE_PARM_DESC(gpio_tracking,"enable debug messages [gpio]");
 
-static unsigned int alsa = 0;
+static unsigned int alsa;
 module_param(alsa, int, 0644);
 MODULE_PARM_DESC(alsa,"enable ALSA DMA sound [dmasound]");
 
-static unsigned int oss = 0;
+static unsigned int oss;
 module_param(oss, int, 0644);
 MODULE_PARM_DESC(oss,"enable OSS DMA sound [dmasound]");
 
@@ -142,39 +142,6 @@
 	}
 }
 
-int saa7134_tuner_callback(void *ptr, int command, int arg)
-{
-	u8 sync_control;
-	struct saa7134_dev *dev = ptr;
-
-	switch (dev->tuner_type) {
-	case TUNER_PHILIPS_TDA8290:
-		switch (command) {
-		case 0: /* switch LNA gain through GPIO 22*/
-			saa7134_set_gpio(dev, 22, arg) ;
-			break;
-		case 1: /* vsync output at GPIO22. 50 / 60Hz */
-			dprintk("setting GPIO22 to vsync %d\n", arg);
-			saa_andorb(SAA7134_VIDEO_PORT_CTRL3, 0x80, 0x80);
-			saa_andorb(SAA7134_VIDEO_PORT_CTRL6, 0x0f, 0x03);
-			if (arg == 1)
-				sync_control = 11;
-			else
-				sync_control = 17;
-			saa_writeb(SAA7134_VGATE_START, sync_control);
-			saa_writeb(SAA7134_VGATE_STOP, sync_control + 1);
-			saa_andorb(SAA7134_MISC_VGATE_MSB, 0x03, 0x00);
-			break;
-		default:
-			return -EINVAL;
-		}
-		break;
-	default:
-		return -ENODEV;
-	}
-	return 0;
-}
-
 /* ------------------------------------------------------------------ */
 
 
@@ -897,6 +864,10 @@
 	struct saa7134_dev *dev;
 	struct saa7134_mpeg_ops *mops;
 	int err;
+	int mask;
+
+	if (saa7134_devcount == SAA7134_MAXBOARDS)
+		return -ENOMEM;
 
 	dev = kzalloc(sizeof(*dev),GFP_KERNEL);
 	if (NULL == dev)
@@ -1094,6 +1065,11 @@
 	if (TUNER_ABSENT != dev->tuner_type)
 		saa7134_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL);
 
+	if (card(dev).gpiomask != 0) {
+		mask = card(dev).gpiomask;
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   mask, mask);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, 0);
+	}
 	return 0;
 
  fail4:
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index ea2be9e..2d16be2 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -33,33 +33,40 @@
 #include "saa7134.h"
 #include <media/v4l2-common.h>
 #include "dvb-pll.h"
+#include <dvb_frontend.h>
 
 #include "mt352.h"
 #include "mt352_priv.h" /* FIXME */
 #include "tda1004x.h"
 #include "nxt200x.h"
+#include "tuner-xc2028.h"
 
 #include "tda10086.h"
 #include "tda826x.h"
 #include "tda827x.h"
 #include "isl6421.h"
+#include "isl6405.h"
+#include "lnbp21.h"
+#include "tuner-simple.h"
 
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
 
-static unsigned int antenna_pwr = 0;
+static unsigned int antenna_pwr;
 
 module_param(antenna_pwr, int, 0444);
 MODULE_PARM_DESC(antenna_pwr,"enable antenna power (Pinnacle 300i)");
 
-static int use_frontend = 0;
+static int use_frontend;
 module_param(use_frontend, int, 0644);
 MODULE_PARM_DESC(use_frontend,"for cards with multiple frontends (0: terrestrial, 1: satellite)");
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off module debugging (default:off).");
 
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
 #define dprintk(fmt, arg...)	do { if (debug) \
 	printk(KERN_DEBUG "%s/dvb: " fmt, dev->name , ## arg); } while(0)
 
@@ -91,7 +98,7 @@
 	saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2,   (1 << 28));
 	udelay(10);
 	ok = saa_readl(SAA7134_GPIO_GPSTATUS0) & (1 << 27);
-	dprintk("%s %s\n", __FUNCTION__, ok ? "on" : "off");
+	dprintk("%s %s\n", __func__, ok ? "on" : "off");
 
 	if (!ok)
 		saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2,   (1 << 26));
@@ -111,7 +118,7 @@
 	static u8 irq_cfg []       = { INTERRUPT_EN_0, 0x00, 0x00, 0x00, 0x00 };
 	struct saa7134_dev *dev= fe->dvb->priv;
 
-	dprintk("%s called\n", __FUNCTION__);
+	dprintk("%s called\n", __func__);
 
 	mt352_write(fe, clock_config,   sizeof(clock_config));
 	udelay(200);
@@ -146,6 +153,26 @@
 	return 0;
 }
 
+static int mt352_aver_a16d_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_tuner_set_params(struct dvb_frontend* fe,
 					   struct dvb_frontend_parameters* params)
 {
@@ -188,6 +215,16 @@
 	.demod_init    = mt352_aver777_init,
 };
 
+static struct mt352_config avermedia_16d = {
+	.demod_address = 0xf,
+	.demod_init    = mt352_aver_a16d_init,
+};
+
+static struct mt352_config avermedia_e506r_mt352_dev = {
+	.demod_address   = (0x1e >> 1),
+	.no_tuner        = 1,
+};
+
 /* ==================================================================
  * tda1004x based DVB-T cards, helper functions
  */
@@ -430,8 +467,6 @@
 	.request_firmware = philips_tda1004x_request_firmware
 };
 
-/* ------------------------------------------------------------------ */
-
 static struct tda1004x_config medion_cardbus = {
 	.demod_address = 0x08,
 	.invert        = 1,
@@ -447,47 +482,6 @@
  * tda 1004x based cards with philips silicon tuner
  */
 
-static void philips_tda827x_lna_gain(struct dvb_frontend *fe, int high)
-{
-	struct saa7134_dev *dev = fe->dvb->priv;
-	struct tda1004x_state *state = fe->demodulator_priv;
-	u8 addr = state->config->i2c_gate;
-	u8 config = state->config->tuner_config;
-	u8 GP00_CF[] = {0x20, 0x01};
-	u8 GP00_LEV[] = {0x22, 0x00};
-
-	struct i2c_msg msg = {.addr = addr,.flags = 0,.buf = GP00_CF, .len = 2};
-	if (config) {
-		if (high) {
-			dprintk("setting LNA to high gain\n");
-		} else {
-			dprintk("setting LNA to low gain\n");
-		}
-	}
-	switch (config) {
-	case 0: /* no LNA */
-		break;
-	case 1: /* switch is GPIO 0 of tda8290 */
-	case 2:
-		/* turn Vsync off */
-		saa7134_set_gpio(dev, 22, 0);
-		GP00_LEV[1] = high ? 0 : 1;
-		if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) {
-			wprintk("could not access tda8290 at addr: 0x%02x\n",
-				addr << 1);
-			return;
-		}
-		msg.buf = GP00_LEV;
-		if (config == 2)
-			GP00_LEV[1] = high ? 1 : 0;
-		i2c_transfer(&dev->i2c_adap, &msg, 1);
-		break;
-	case 3: /* switch with GPIO of saa713x */
-		saa7134_set_gpio(dev, 22, high);
-		break;
-	}
-}
-
 static int tda8290_i2c_gate_ctrl( struct dvb_frontend* fe, int enable)
 {
 	struct tda1004x_state *state = fe->demodulator_priv;
@@ -510,8 +504,6 @@
 	return 0;
 }
 
-/* ------------------------------------------------------------------ */
-
 static int philips_tda827x_tuner_init(struct dvb_frontend *fe)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
@@ -546,28 +538,57 @@
 	return 0;
 }
 
-static struct tda827x_config tda827x_cfg = {
-	.lna_gain = philips_tda827x_lna_gain,
-	.init = philips_tda827x_tuner_init,
-	.sleep = philips_tda827x_tuner_sleep
-};
-
-static void configure_tda827x_fe(struct saa7134_dev *dev, struct tda1004x_config *tda_conf)
+static void configure_tda827x_fe(struct saa7134_dev *dev, struct tda1004x_config *cdec_conf,
+							  struct tda827x_config *tuner_conf)
 {
-	dev->dvb.frontend = dvb_attach(tda10046_attach, tda_conf, &dev->i2c_adap);
+	dev->dvb.frontend = dvb_attach(tda10046_attach, cdec_conf, &dev->i2c_adap);
 	if (dev->dvb.frontend) {
-		if (tda_conf->i2c_gate)
+		if (cdec_conf->i2c_gate)
 			dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
-		if (dvb_attach(tda827x_attach, dev->dvb.frontend, tda_conf->tuner_address,
-						&dev->i2c_adap,&tda827x_cfg) == NULL) {
+		if (dvb_attach(tda827x_attach, dev->dvb.frontend, cdec_conf->tuner_address,
+							&dev->i2c_adap, tuner_conf) == NULL) {
 			wprintk("no tda827x tuner found at addr: %02x\n",
-				tda_conf->tuner_address);
+				cdec_conf->tuner_address);
 		}
 	}
 }
 
 /* ------------------------------------------------------------------ */
 
+static struct tda827x_config tda827x_cfg_0 = {
+	.tuner_callback = saa7134_tuner_callback,
+	.init = philips_tda827x_tuner_init,
+	.sleep = philips_tda827x_tuner_sleep,
+	.config = 0,
+	.switch_addr = 0
+};
+
+static struct tda827x_config tda827x_cfg_1 = {
+	.tuner_callback = saa7134_tuner_callback,
+	.init = philips_tda827x_tuner_init,
+	.sleep = philips_tda827x_tuner_sleep,
+	.config = 1,
+	.switch_addr = 0x4b
+};
+
+static struct tda827x_config tda827x_cfg_2 = {
+	.tuner_callback = saa7134_tuner_callback,
+	.init = philips_tda827x_tuner_init,
+	.sleep = philips_tda827x_tuner_sleep,
+	.config = 2,
+	.switch_addr = 0x4b
+};
+
+static struct tda827x_config tda827x_cfg_2_sw42 = {
+	.tuner_callback = saa7134_tuner_callback,
+	.init = philips_tda827x_tuner_init,
+	.sleep = philips_tda827x_tuner_sleep,
+	.config = 2,
+	.switch_addr = 0x42
+};
+
+/* ------------------------------------------------------------------ */
+
 static struct tda1004x_config tda827x_lifeview_config = {
 	.demod_address = 0x08,
 	.invert        = 1,
@@ -590,7 +611,6 @@
 	.if_freq       = TDA10046_FREQ_045,
 	.i2c_gate      = 0x4b,
 	.tuner_address = 0x61,
-	.tuner_config  = 0,
 	.antenna_switch= 1,
 	.request_firmware = philips_tda1004x_request_firmware
 };
@@ -605,7 +625,6 @@
 	.if_freq       = TDA10046_FREQ_045,
 	.i2c_gate      = 0x4b,
 	.tuner_address = 0x61,
-	.tuner_config  = 0,
 	.request_firmware = philips_tda1004x_request_firmware
 };
 
@@ -619,7 +638,6 @@
 	.if_freq       = TDA10046_FREQ_045,
 	.i2c_gate      = 0x4b,
 	.tuner_address = 0x60,
-	.tuner_config  = 0,
 	.request_firmware = philips_tda1004x_request_firmware
 };
 
@@ -633,7 +651,6 @@
 	.if_freq       = TDA10046_FREQ_045,
 	.i2c_gate      = 0x4b,
 	.tuner_address = 0x61,
-	.tuner_config  = 2,
 	.antenna_switch= 1,
 	.request_firmware = philips_tda1004x_request_firmware
 };
@@ -648,7 +665,6 @@
 	.if_freq       = TDA10046_FREQ_045,
 	.i2c_gate      = 0x4b,
 	.tuner_address = 0x61,
-	.tuner_config  = 1,
 	.request_firmware = philips_tda1004x_request_firmware
 };
 
@@ -662,7 +678,6 @@
 	.if_freq       = TDA10046_FREQ_045,
 	.i2c_gate      = 0x4b,
 	.tuner_address = 0x61,
-	.tuner_config  = 1,
 	.request_firmware = philips_tda1004x_request_firmware
 };
 
@@ -676,7 +691,6 @@
 	.if_freq       = TDA10046_FREQ_045,
 	.i2c_gate      = 0x4b,
 	.tuner_address = 0x61,
-	.tuner_config  = 0,
 	.antenna_switch= 2,
 	.request_firmware = philips_tda1004x_request_firmware
 };
@@ -715,7 +729,6 @@
 	.if_freq       = TDA10046_FREQ_045,
 	.i2c_gate      = 0x4b,
 	.tuner_address = 0x60,
-	.tuner_config  = 0,
 	.request_firmware = philips_tda1004x_request_firmware
 };
 
@@ -729,7 +742,6 @@
 	.if_freq       = TDA10046_FREQ_045,
 	.i2c_gate      = 0x4b,
 	.tuner_address = 0x61,
-	.tuner_config  = 2,
 	.antenna_switch= 2,
 	.request_firmware = philips_tda1004x_request_firmware
 };
@@ -744,7 +756,6 @@
 	.if_freq       = TDA10046_FREQ_045,
 	.i2c_gate      = 0x4b,
 	.tuner_address = 0x61,
-	.tuner_config  = 2,
 	.antenna_switch= 2,
 	.request_firmware = philips_tda1004x_request_firmware
 };
@@ -759,7 +770,6 @@
 	.if_freq       = TDA10046_FREQ_045,
 	.i2c_gate      = 0x4b,
 	.tuner_address = 0x61,
-	.tuner_config  = 2,
 	.antenna_switch= 1,
 	.request_firmware = philips_tda1004x_request_firmware
 };
@@ -774,7 +784,6 @@
 	.if_freq       = TDA10046_FREQ_045,
 	.i2c_gate      = 0x4b,
 	.tuner_address = 0x60,
-	.tuner_config  = 0,
 	.antenna_switch= 1,
 	.request_firmware = philips_tda1004x_request_firmware
 };
@@ -789,7 +798,6 @@
 	.if_freq       = TDA10046_FREQ_045,
 	.i2c_gate      = 0x42,
 	.tuner_address = 0x61,
-	.tuner_config  = 2,
 	.antenna_switch = 1,
 	.request_firmware = philips_tda1004x_request_firmware
 };
@@ -817,9 +825,10 @@
 }
 
 static struct tda827x_config ads_duo_cfg = {
-	.lna_gain = philips_tda827x_lna_gain,
+	.tuner_callback = saa7134_tuner_callback,
 	.init = ads_duo_tuner_init,
-	.sleep = ads_duo_tuner_sleep
+	.sleep = ads_duo_tuner_sleep,
+	.config = 0
 };
 
 static struct tda1004x_config ads_tech_duo_config = {
@@ -842,8 +851,73 @@
 	.demod_address = 0x0e,
 	.invert = 0,
 	.diseqc_tone = 0,
+	.xtal_freq = TDA10086_XTAL_16M,
 };
 
+static struct tda10086_config sd1878_4m = {
+	.demod_address = 0x0e,
+	.invert = 0,
+	.diseqc_tone = 0,
+	.xtal_freq = TDA10086_XTAL_4M,
+};
+
+/* ------------------------------------------------------------------
+ * special case: lnb supply is connected to the gated i2c
+ */
+
+static int md8800_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	int res = -EIO;
+	struct saa7134_dev *dev = fe->dvb->priv;
+	if (fe->ops.i2c_gate_ctrl) {
+		fe->ops.i2c_gate_ctrl(fe, 1);
+		if (dev->original_set_voltage)
+			res = dev->original_set_voltage(fe, voltage);
+		fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+	return res;
+};
+
+static int md8800_set_high_voltage(struct dvb_frontend *fe, long arg)
+{
+	int res = -EIO;
+	struct saa7134_dev *dev = fe->dvb->priv;
+	if (fe->ops.i2c_gate_ctrl) {
+		fe->ops.i2c_gate_ctrl(fe, 1);
+		if (dev->original_set_high_voltage)
+			res = dev->original_set_high_voltage(fe, arg);
+		fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+	return res;
+};
+
+static int md8800_set_voltage2(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	u8 wbuf[2] = { 0x1f, 00 };
+	u8 rbuf;
+	struct i2c_msg msg[] = { { .addr = 0x08, .flags = 0, .buf = wbuf, .len = 1 },
+				 { .addr = 0x08, .flags = I2C_M_RD, .buf = &rbuf, .len = 1 } };
+
+	if (i2c_transfer(&dev->i2c_adap, msg, 2) != 2)
+		return -EIO;
+	/* NOTE: this assumes that gpo1 is used, it might be bit 5 (gpo2) */
+	if (voltage == SEC_VOLTAGE_18)
+		wbuf[1] = rbuf | 0x10;
+	else
+		wbuf[1] = rbuf & 0xef;
+	msg[0].len = 2;
+	i2c_transfer(&dev->i2c_adap, msg, 1);
+	return 0;
+}
+
+static int md8800_set_high_voltage2(struct dvb_frontend *fe, long arg)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	wprintk("%s: sorry can't set high LNB supply voltage from here\n", __func__);
+	return -EIO;
+}
+
 /* ==================================================================
  * nxt200x based ATSC cards, helper functions
  */
@@ -863,12 +937,14 @@
 static int dvb_init(struct saa7134_dev *dev)
 {
 	int ret;
+	int attach_xc3028 = 0;
+
 	/* init struct videobuf_dvb */
 	dev->ts.nr_bufs    = 32;
 	dev->ts.nr_packets = 32*4;
 	dev->dvb.name = dev->name;
-	videobuf_queue_pci_init(&dev->dvb.dvbq, &saa7134_ts_qops,
-			    dev->pci, &dev->slock,
+	videobuf_queue_sg_init(&dev->dvb.dvbq, &saa7134_ts_qops,
+			    &dev->pci->dev, &dev->slock,
 			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
 			    V4L2_FIELD_ALTERNATE,
 			    sizeof(struct saa7134_buf),
@@ -889,17 +965,25 @@
 		dev->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777,
 					       &dev->i2c_adap);
 		if (dev->dvb.frontend) {
-			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-				   NULL, DVB_PLL_PHILIPS_TD1316);
+			dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+				   &dev->i2c_adap, 0x61,
+				   TUNER_PHILIPS_TD1316);
 		}
 		break;
+	case SAA7134_BOARD_AVERMEDIA_A16D:
+		dprintk("avertv A16D dvb setup\n");
+		dev->dvb.frontend = dvb_attach(mt352_attach, &avermedia_16d,
+					       &dev->i2c_adap);
+		attach_xc3028 = 1;
+		break;
 	case SAA7134_BOARD_MD7134:
 		dev->dvb.frontend = dvb_attach(tda10046_attach,
 					       &medion_cardbus,
 					       &dev->i2c_adap);
 		if (dev->dvb.frontend) {
-			dvb_attach(dvb_pll_attach, dev->dvb.frontend, medion_cardbus.tuner_address,
-				   &dev->i2c_adap, DVB_PLL_FMD1216ME);
+			dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+				   &dev->i2c_adap, medion_cardbus.tuner_address,
+				   TUNER_PHILIPS_FMD1216ME_MK3);
 		}
 		break;
 	case SAA7134_BOARD_PHILIPS_TOUGH:
@@ -913,7 +997,7 @@
 		break;
 	case SAA7134_BOARD_FLYDVBTDUO:
 	case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS:
-		configure_tda827x_fe(dev, &tda827x_lifeview_config);
+		configure_tda827x_fe(dev, &tda827x_lifeview_config, &tda827x_cfg_0);
 		break;
 	case SAA7134_BOARD_PHILIPS_EUROPA:
 	case SAA7134_BOARD_VIDEOMATE_DVBT_300:
@@ -938,36 +1022,36 @@
 		}
 		break;
 	case SAA7134_BOARD_KWORLD_DVBT_210:
-		configure_tda827x_fe(dev, &kworld_dvb_t_210_config);
+		configure_tda827x_fe(dev, &kworld_dvb_t_210_config, &tda827x_cfg_2);
 		break;
 	case SAA7134_BOARD_PHILIPS_TIGER:
-		configure_tda827x_fe(dev, &philips_tiger_config);
+		configure_tda827x_fe(dev, &philips_tiger_config, &tda827x_cfg_0);
 		break;
 	case SAA7134_BOARD_PINNACLE_PCTV_310i:
-		configure_tda827x_fe(dev, &pinnacle_pctv_310i_config);
+		configure_tda827x_fe(dev, &pinnacle_pctv_310i_config, &tda827x_cfg_1);
 		break;
 	case SAA7134_BOARD_HAUPPAUGE_HVR1110:
-		configure_tda827x_fe(dev, &hauppauge_hvr_1110_config);
+		configure_tda827x_fe(dev, &hauppauge_hvr_1110_config, &tda827x_cfg_1);
 		break;
 	case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
-		configure_tda827x_fe(dev, &asus_p7131_dual_config);
+		configure_tda827x_fe(dev, &asus_p7131_dual_config, &tda827x_cfg_0);
 		break;
 	case SAA7134_BOARD_FLYDVBT_LR301:
-		configure_tda827x_fe(dev, &tda827x_lifeview_config);
+		configure_tda827x_fe(dev, &tda827x_lifeview_config, &tda827x_cfg_0);
 		break;
 	case SAA7134_BOARD_FLYDVB_TRIO:
 		if(! use_frontend) {	/* terrestrial */
-			configure_tda827x_fe(dev, &lifeview_trio_config);
-		} else {  	        /* satellite */
+			configure_tda827x_fe(dev, &lifeview_trio_config, &tda827x_cfg_0);
+		} else {  		/* satellite */
 			dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap);
 			if (dev->dvb.frontend) {
 				if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x63,
 									&dev->i2c_adap, 0) == NULL) {
-					wprintk("%s: Lifeview Trio, No tda826x found!\n", __FUNCTION__);
+					wprintk("%s: Lifeview Trio, No tda826x found!\n", __func__);
 				}
 				if (dvb_attach(isl6421_attach, dev->dvb.frontend, &dev->i2c_adap,
 										0x08, 0, 0) == NULL) {
-					wprintk("%s: Lifeview Trio, No ISL6421 found!\n", __FUNCTION__);
+					wprintk("%s: Lifeview Trio, No ISL6421 found!\n", __func__);
 				}
 			}
 		}
@@ -979,18 +1063,56 @@
 					       &dev->i2c_adap);
 		if (dev->dvb.frontend) {
 			if (dvb_attach(tda827x_attach,dev->dvb.frontend,
-				   ads_tech_duo_config.tuner_address,
-				   &dev->i2c_adap,&ads_duo_cfg) == NULL) {
+				   ads_tech_duo_config.tuner_address, &dev->i2c_adap,
+								&ads_duo_cfg) == NULL) {
 				wprintk("no tda827x tuner found at addr: %02x\n",
 					ads_tech_duo_config.tuner_address);
 			}
 		}
 		break;
 	case SAA7134_BOARD_TEVION_DVBT_220RF:
-		configure_tda827x_fe(dev, &tevion_dvbt220rf_config);
+		configure_tda827x_fe(dev, &tevion_dvbt220rf_config, &tda827x_cfg_0);
 		break;
 	case SAA7134_BOARD_MEDION_MD8800_QUADRO:
-		configure_tda827x_fe(dev, &md8800_dvbt_config);
+		if (!use_frontend) {     /* terrestrial */
+			configure_tda827x_fe(dev, &md8800_dvbt_config, &tda827x_cfg_0);
+		} else {        /* satellite */
+			dev->dvb.frontend = dvb_attach(tda10086_attach,
+							&flydvbs, &dev->i2c_adap);
+			if (dev->dvb.frontend) {
+				struct dvb_frontend *fe = dev->dvb.frontend;
+				u8 dev_id = dev->eedata[2];
+				u8 data = 0xc4;
+				struct i2c_msg msg = {.addr = 0x08, .flags = 0, .len = 1};
+
+				if (dvb_attach(tda826x_attach, dev->dvb.frontend,
+						0x60, &dev->i2c_adap, 0) == NULL)
+					wprintk("%s: Medion Quadro, no tda826x "
+						"found !\n", __func__);
+				if (dev_id != 0x08) {
+					/* we need to open the i2c gate (we know it exists) */
+					fe->ops.i2c_gate_ctrl(fe, 1);
+					if (dvb_attach(isl6405_attach, fe,
+							&dev->i2c_adap, 0x08, 0, 0) == NULL)
+						wprintk("%s: Medion Quadro, no ISL6405 "
+							"found !\n", __func__);
+					if (dev_id == 0x07) {
+						/* fire up the 2nd section of the LNB supply since
+						   we can't do this from the other section */
+						msg.buf = &data;
+						i2c_transfer(&dev->i2c_adap, &msg, 1);
+					}
+					fe->ops.i2c_gate_ctrl(fe, 0);
+					dev->original_set_voltage = fe->ops.set_voltage;
+					fe->ops.set_voltage = md8800_set_voltage;
+					dev->original_set_high_voltage = fe->ops.enable_high_lnb_voltage;
+					fe->ops.enable_high_lnb_voltage = md8800_set_high_voltage;
+				} else {
+					fe->ops.set_voltage = md8800_set_voltage2;
+					fe->ops.enable_high_lnb_voltage = md8800_set_high_voltage2;
+				}
+			}
+		}
 		break;
 	case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
 		dev->dvb.frontend = dvb_attach(nxt200x_attach, &avertvhda180,
@@ -1004,8 +1126,9 @@
 		dev->dvb.frontend = dvb_attach(nxt200x_attach, &kworldatsc110,
 					       &dev->i2c_adap);
 		if (dev->dvb.frontend) {
-			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-				   NULL, DVB_PLL_TUV1236D);
+			dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+				   &dev->i2c_adap, 0x61,
+				   TUNER_PHILIPS_TUV1236D);
 		}
 		break;
 	case SAA7134_BOARD_FLYDVBS_LR300:
@@ -1014,11 +1137,11 @@
 		if (dev->dvb.frontend) {
 			if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x60,
 				       &dev->i2c_adap, 0) == NULL) {
-				wprintk("%s: No tda826x found!\n", __FUNCTION__);
+				wprintk("%s: No tda826x found!\n", __func__);
 			}
 			if (dvb_attach(isl6421_attach, dev->dvb.frontend,
 				       &dev->i2c_adap, 0x08, 0, 0) == NULL) {
-				wprintk("%s: No ISL6421 found!\n", __FUNCTION__);
+				wprintk("%s: No ISL6421 found!\n", __func__);
 			}
 		}
 		break;
@@ -1030,8 +1153,9 @@
 			dev->original_demod_sleep = dev->dvb.frontend->ops.sleep;
 			dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
 
-			dvb_attach(dvb_pll_attach, dev->dvb.frontend, medion_cardbus.tuner_address,
-				   &dev->i2c_adap, DVB_PLL_FMD1216ME);
+			dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+				   &dev->i2c_adap, medion_cardbus.tuner_address,
+				   TUNER_PHILIPS_FMD1216ME_MK3);
 		}
 		break;
 	case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
@@ -1044,38 +1168,107 @@
 		}
 		break;
 	case SAA7134_BOARD_CINERGY_HT_PCMCIA:
-		configure_tda827x_fe(dev, &cinergy_ht_config);
+		configure_tda827x_fe(dev, &cinergy_ht_config, &tda827x_cfg_0);
 		break;
 	case SAA7134_BOARD_CINERGY_HT_PCI:
-		configure_tda827x_fe(dev, &cinergy_ht_pci_config);
+		configure_tda827x_fe(dev, &cinergy_ht_pci_config, &tda827x_cfg_0);
 		break;
 	case SAA7134_BOARD_PHILIPS_TIGER_S:
-		configure_tda827x_fe(dev, &philips_tiger_s_config);
+		configure_tda827x_fe(dev, &philips_tiger_s_config, &tda827x_cfg_2);
 		break;
 	case SAA7134_BOARD_ASUS_P7131_4871:
-		configure_tda827x_fe(dev, &asus_p7131_4871_config);
+		configure_tda827x_fe(dev, &asus_p7131_4871_config, &tda827x_cfg_2);
 		break;
 	case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
-		configure_tda827x_fe(dev, &asus_p7131_hybrid_lna_config);
+		configure_tda827x_fe(dev, &asus_p7131_hybrid_lna_config, &tda827x_cfg_2);
 		break;
 	case SAA7134_BOARD_AVERMEDIA_SUPER_007:
-		configure_tda827x_fe(dev, &avermedia_super_007_config);
+		configure_tda827x_fe(dev, &avermedia_super_007_config, &tda827x_cfg_0);
 		break;
 	case SAA7134_BOARD_TWINHAN_DTV_DVB_3056:
-		configure_tda827x_fe(dev, &twinhan_dtv_dvb_3056_config);
+		configure_tda827x_fe(dev, &twinhan_dtv_dvb_3056_config, &tda827x_cfg_2_sw42);
+		break;
+	case SAA7134_BOARD_PHILIPS_SNAKE:
+		dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
+						&dev->i2c_adap);
+		if (dev->dvb.frontend) {
+			if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x60,
+					&dev->i2c_adap, 0) == NULL)
+				wprintk("%s: No tda826x found!\n", __func__);
+			if (dvb_attach(lnbp21_attach, dev->dvb.frontend,
+					&dev->i2c_adap, 0, 0) == NULL)
+				wprintk("%s: No lnbp21 found!\n", __func__);
+		}
+		break;
+	case SAA7134_BOARD_CREATIX_CTX953:
+		configure_tda827x_fe(dev, &md8800_dvbt_config, &tda827x_cfg_0);
+		break;
+	case SAA7134_BOARD_MSI_TVANYWHERE_AD11:
+		configure_tda827x_fe(dev, &philips_tiger_s_config, &tda827x_cfg_2);
+		break;
+	case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+		dev->dvb.frontend = dvb_attach(mt352_attach,
+					       &avermedia_e506r_mt352_dev,
+					       &dev->i2c_adap);
+		attach_xc3028 = 1;
+		break;
+	case SAA7134_BOARD_MD7134_BRIDGE_2:
+		dev->dvb.frontend = dvb_attach(tda10086_attach,
+						&sd1878_4m, &dev->i2c_adap);
+		if (dev->dvb.frontend) {
+			struct dvb_frontend *fe;
+			if (dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
+				  &dev->i2c_adap, DVB_PLL_PHILIPS_SD1878_TDA8261) == NULL)
+				wprintk("%s: MD7134 DVB-S, no SD1878 "
+					"found !\n", __func__);
+			/* we need to open the i2c gate (we know it exists) */
+			fe = dev->dvb.frontend;
+			fe->ops.i2c_gate_ctrl(fe, 1);
+			if (dvb_attach(isl6405_attach, fe,
+					&dev->i2c_adap, 0x08, 0, 0) == NULL)
+				wprintk("%s: MD7134 DVB-S, no ISL6405 "
+					"found !\n", __func__);
+			fe->ops.i2c_gate_ctrl(fe, 0);
+			dev->original_set_voltage = fe->ops.set_voltage;
+			fe->ops.set_voltage = md8800_set_voltage;
+			dev->original_set_high_voltage = fe->ops.enable_high_lnb_voltage;
+			fe->ops.enable_high_lnb_voltage = md8800_set_high_voltage;
+		}
 		break;
 	default:
 		wprintk("Huh? unknown DVB card?\n");
 		break;
 	}
 
+	if (attach_xc3028) {
+		struct dvb_frontend *fe;
+		struct xc2028_config cfg = {
+			.i2c_adap  = &dev->i2c_adap,
+			.i2c_addr  = 0x61,
+		};
+
+		if (!dev->dvb.frontend)
+			return -1;
+
+		fe = dvb_attach(xc2028_attach, dev->dvb.frontend, &cfg);
+		if (!fe) {
+			printk(KERN_ERR "%s/2: xc3028 attach failed\n",
+			       dev->name);
+			dvb_frontend_detach(dev->dvb.frontend);
+			dvb_unregister_frontend(dev->dvb.frontend);
+			dev->dvb.frontend = NULL;
+			return -1;
+		}
+	}
+
 	if (NULL == dev->dvb.frontend) {
 		printk(KERN_ERR "%s/dvb: frontend initialization failed\n", dev->name);
 		return -1;
 	}
 
 	/* register everything else */
-	ret = videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev);
+	ret = videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev,
+				    adapter_nr);
 
 	/* this sequence is necessary to make the tda1004x load its firmware
 	 * and to enter analog mode of hybrid boards
@@ -1106,9 +1299,22 @@
 
 		/* otherwise we don't detect the tuner on next insmod */
 		saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &tda9887_cfg);
+	} else if (dev->board == SAA7134_BOARD_MEDION_MD8800_QUADRO) {
+		if ((dev->eedata[2] == 0x07) && use_frontend) {
+			/* turn off the 2nd lnb supply */
+			u8 data = 0x80;
+			struct i2c_msg msg = {.addr = 0x08, .buf = &data, .flags = 0, .len = 1};
+			struct dvb_frontend *fe;
+			fe = dev->dvb.frontend;
+			if (fe->ops.i2c_gate_ctrl) {
+				fe->ops.i2c_gate_ctrl(fe, 1);
+				i2c_transfer(&dev->i2c_adap, &msg, 1);
+				fe->ops.i2c_gate_ctrl(fe, 0);
+			}
+		}
 	}
-
-	videobuf_dvb_unregister(&dev->dvb);
+	if (dev->dvb.frontend)
+		videobuf_dvb_unregister(&dev->dvb);
 	return 0;
 }
 
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
index 3d2ec30..1314522 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -40,7 +40,7 @@
 module_param_array(empress_nr, int, NULL, 0444);
 MODULE_PARM_DESC(empress_nr,"ts device number");
 
-static unsigned int debug = 0;
+static unsigned int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug,"enable debug messages");
 
@@ -402,7 +402,7 @@
 {
 	int err;
 
-	dprintk("%s: %s\n",dev->name,__FUNCTION__);
+	dprintk("%s: %s\n",dev->name,__func__);
 	dev->empress_dev = video_device_alloc();
 	if (NULL == dev->empress_dev)
 		return -ENOMEM;
@@ -427,8 +427,8 @@
 	printk(KERN_INFO "%s: registered device video%d [mpeg]\n",
 	       dev->name,dev->empress_dev->minor & 0x1f);
 
-	videobuf_queue_pci_init(&dev->empress_tsq, &saa7134_ts_qops,
-			    dev->pci, &dev->slock,
+	videobuf_queue_sg_init(&dev->empress_tsq, &saa7134_ts_qops,
+			    &dev->pci->dev, &dev->slock,
 			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
 			    V4L2_FIELD_ALTERNATE,
 			    sizeof(struct saa7134_buf),
@@ -440,7 +440,7 @@
 
 static int empress_fini(struct saa7134_dev *dev)
 {
-	dprintk("%s: %s\n",dev->name,__FUNCTION__);
+	dprintk("%s: %s\n",dev->name,__func__);
 
 	if (NULL == dev->empress_dev)
 		return 0;
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
index d3322c3..2ccfaba 100644
--- a/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/drivers/media/video/saa7134/saa7134-i2c.c
@@ -33,11 +33,11 @@
 
 /* ----------------------------------------------------------- */
 
-static unsigned int i2c_debug = 0;
+static unsigned int i2c_debug;
 module_param(i2c_debug, int, 0644);
 MODULE_PARM_DESC(i2c_debug,"enable debug messages [i2c]");
 
-static unsigned int i2c_scan = 0;
+static unsigned int i2c_scan;
 module_param(i2c_scan, int, 0444);
 MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time");
 
@@ -140,6 +140,8 @@
 {
 	switch (status) {
 	case BUSY:
+	case TO_SCL:
+	case TO_ARB:
 		return true;
 	default:
 		return false;
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index b418881..767ff30 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -27,15 +27,15 @@
 #include "saa7134-reg.h"
 #include "saa7134.h"
 
-static unsigned int disable_ir = 0;
+static unsigned int disable_ir;
 module_param(disable_ir, int, 0444);
 MODULE_PARM_DESC(disable_ir,"disable infrared remote support");
 
-static unsigned int ir_debug = 0;
+static unsigned int ir_debug;
 module_param(ir_debug, int, 0644);
 MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
 
-static int pinnacle_remote = 0;
+static int pinnacle_remote;
 module_param(pinnacle_remote, int, 0644);    /* Choose Pinnacle PCTV remote */
 MODULE_PARM_DESC(pinnacle_remote, "Specify Pinnacle PCTV remote: 0=coloured, 1=grey (defaults to 0)");
 
@@ -331,6 +331,11 @@
 		break;
 	case SAA7134_BOARD_MANLI_MTV001:
 	case SAA7134_BOARD_MANLI_MTV002:
+		ir_codes     = ir_codes_manli;
+		mask_keycode = 0x001f00;
+		mask_keyup   = 0x004000;
+		polling      = 50; /* ms */
+		break;
 	case SAA7134_BOARD_BEHOLD_409FM:
 	case SAA7134_BOARD_BEHOLD_401:
 	case SAA7134_BOARD_BEHOLD_403:
@@ -343,7 +348,13 @@
 	case SAA7134_BOARD_BEHOLD_505FM:
 	case SAA7134_BOARD_BEHOLD_507_9FM:
 		ir_codes     = ir_codes_manli;
-		mask_keycode = 0x001f00;
+		mask_keycode = 0x003f00;
+		mask_keyup   = 0x004000;
+		polling      = 50; /* ms */
+		break;
+	case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
+		ir_codes     = ir_codes_behold_columbus;
+		mask_keycode = 0x003f00;
 		mask_keyup   = 0x004000;
 		polling      = 50; // ms
 		break;
diff --git a/drivers/media/video/saa7134/saa7134-reg.h b/drivers/media/video/saa7134/saa7134-reg.h
index ac6431b..86f5eef 100644
--- a/drivers/media/video/saa7134/saa7134-reg.h
+++ b/drivers/media/video/saa7134/saa7134-reg.h
@@ -365,6 +365,9 @@
 #define SAA7135_DSP_RWSTATE_RDB                 (1 << 1)
 #define SAA7135_DSP_RWSTATE_WRR                 (1 << 0)
 
+#define SAA7135_DSP_RWCLEAR			0x586
+#define SAA7135_DSP_RWCLEAR_RERR		    1
+
 /* ------------------------------------------------------------------ */
 /*
  * Local variables:
diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c
index f1b8fca..eae72fd 100644
--- a/drivers/media/video/saa7134/saa7134-ts.c
+++ b/drivers/media/video/saa7134/saa7134-ts.c
@@ -32,7 +32,7 @@
 
 /* ------------------------------------------------------------------ */
 
-static unsigned int ts_debug  = 0;
+static unsigned int ts_debug;
 module_param(ts_debug, int, 0644);
 MODULE_PARM_DESC(ts_debug,"enable debug messages [ts]");
 
diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c
index 4e98104..232af59 100644
--- a/drivers/media/video/saa7134/saa7134-tvaudio.c
+++ b/drivers/media/video/saa7134/saa7134-tvaudio.c
@@ -35,18 +35,18 @@
 
 /* ------------------------------------------------------------------ */
 
-static unsigned int audio_debug = 0;
+static unsigned int audio_debug;
 module_param(audio_debug, int, 0644);
 MODULE_PARM_DESC(audio_debug,"enable debug messages [tv audio]");
 
-static unsigned int audio_ddep = 0;
+static unsigned int audio_ddep;
 module_param(audio_ddep, int, 0644);
 MODULE_PARM_DESC(audio_ddep,"audio ddep overwrite");
 
 static int audio_clock_override = UNSET;
 module_param(audio_clock_override, int, 0644);
 
-static int audio_clock_tweak = 0;
+static int audio_clock_tweak;
 module_param(audio_clock_tweak, int, 0644);
 MODULE_PARM_DESC(audio_clock_tweak, "Audio clock tick fine tuning for cards with audio crystal that's slightly off (range [-1024 .. 1024])");
 
@@ -653,6 +653,17 @@
 
 #define DSP_RETRY 32
 #define DSP_DELAY 16
+#define SAA7135_DSP_RWCLEAR_RERR 1
+
+static inline int saa_dsp_reset_error_bit(struct saa7134_dev *dev)
+{
+	int state = saa_readb(SAA7135_DSP_RWSTATE);
+	if (unlikely(state & SAA7135_DSP_RWSTATE_ERR)) {
+		d2printk("%s: resetting error bit\n", dev->name);
+		saa_writeb(SAA7135_DSP_RWCLEAR, SAA7135_DSP_RWCLEAR_RERR);
+	}
+	return 0;
+}
 
 static inline int saa_dsp_wait_bit(struct saa7134_dev *dev, int bit)
 {
@@ -660,8 +671,8 @@
 
 	state = saa_readb(SAA7135_DSP_RWSTATE);
 	if (unlikely(state & SAA7135_DSP_RWSTATE_ERR)) {
-		printk("%s: dsp access error\n",dev->name);
-		/* FIXME: send ack ... */
+		printk(KERN_WARNING "%s: dsp access error\n", dev->name);
+		saa_dsp_reset_error_bit(dev);
 		return -EIO;
 	}
 	while (0 == (state & bit)) {
diff --git a/drivers/media/video/saa7134/saa7134-vbi.c b/drivers/media/video/saa7134/saa7134-vbi.c
index f0d5ed9..cb03042 100644
--- a/drivers/media/video/saa7134/saa7134-vbi.c
+++ b/drivers/media/video/saa7134/saa7134-vbi.c
@@ -31,7 +31,7 @@
 
 /* ------------------------------------------------------------------ */
 
-static unsigned int vbi_debug  = 0;
+static unsigned int vbi_debug;
 module_param(vbi_debug, int, 0644);
 MODULE_PARM_DESC(vbi_debug,"enable debug messages [vbi]");
 
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index 39c41ad..a0baf2d 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -40,7 +40,7 @@
 
 unsigned int video_debug;
 static unsigned int gbuffers      = 8;
-static unsigned int noninterlaced = 0;
+static unsigned int noninterlaced; /* 0 */
 static unsigned int gbufsize      = 720*576*4;
 static unsigned int gbufsize_max  = 720*576*4;
 static char secam[] = "--";
@@ -626,13 +626,8 @@
 {
 	saa7134_set_decoder(dev);
 
-	if (card_in(dev, dev->ctl_input).tv) {
-		if ((card(dev).tuner_type == TUNER_PHILIPS_TDA8290)
-				&& ((card(dev).tuner_config == 1)
-				||  (card(dev).tuner_config == 2)))
-			saa7134_set_gpio(dev, 22, 5);
+	if (card_in(dev, dev->ctl_input).tv)
 		saa7134_i2c_call_clients(dev, VIDIOC_S_STD, &dev->tvnorm->id);
-	}
 }
 
 static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale)
@@ -1350,14 +1345,14 @@
 	fh->height   = 576;
 	v4l2_prio_open(&dev->prio,&fh->prio);
 
-	videobuf_queue_pci_init(&fh->cap, &video_qops,
-			    dev->pci, &dev->slock,
+	videobuf_queue_sg_init(&fh->cap, &video_qops,
+			    &dev->pci->dev, &dev->slock,
 			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
 			    V4L2_FIELD_INTERLACED,
 			    sizeof(struct saa7134_buf),
 			    fh);
-	videobuf_queue_pci_init(&fh->vbi, &saa7134_vbi_qops,
-			    dev->pci, &dev->slock,
+	videobuf_queue_sg_init(&fh->vbi, &saa7134_vbi_qops,
+			    &dev->pci->dev, &dev->slock,
 			    V4L2_BUF_TYPE_VBI_CAPTURE,
 			    V4L2_FIELD_SEQ_TB,
 			    sizeof(struct saa7134_buf),
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index f940d02..924ffd1 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -253,7 +253,17 @@
 #define SAA7134_BOARD_BEHOLD_607_9FM	129
 #define SAA7134_BOARD_BEHOLD_M6		130
 #define SAA7134_BOARD_TWINHAN_DTV_DVB_3056 131
-#define SAA7134_BOARD_GENIUS_TVGO_A11MCE 132
+#define SAA7134_BOARD_GENIUS_TVGO_A11MCE   132
+#define SAA7134_BOARD_PHILIPS_SNAKE        133
+#define SAA7134_BOARD_CREATIX_CTX953       134
+#define SAA7134_BOARD_MSI_TVANYWHERE_AD11  135
+#define SAA7134_BOARD_AVERMEDIA_CARDBUS_506 136
+#define SAA7134_BOARD_AVERMEDIA_A16D       137
+#define SAA7134_BOARD_AVERMEDIA_M115       138
+#define SAA7134_BOARD_VIDEOMATE_T750       139
+#define SAA7134_BOARD_AVERMEDIA_A700_PRO    140
+#define SAA7134_BOARD_AVERMEDIA_A700_HYBRID 141
+
 
 #define SAA7134_MAXBOARDS 8
 #define SAA7134_INPUT_MAX 8
@@ -380,9 +390,7 @@
 	unsigned int               radio;
 	enum v4l2_buf_type         type;
 	unsigned int               resources;
-#ifdef VIDIOC_G_PRIORITY
 	enum v4l2_priority	   prio;
-#endif
 
 	/* video overlay */
 	struct v4l2_window         win;
@@ -454,9 +462,7 @@
 	struct list_head           devlist;
 	struct mutex               lock;
 	spinlock_t                 slock;
-#ifdef VIDIOC_G_PRIORITY
 	struct v4l2_prio_state     prio;
-#endif
 	/* workstruct for loading modules */
 	struct work_struct request_module_wk;
 
@@ -556,7 +562,9 @@
 #if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE)
 	/* SAA7134_MPEG_DVB only */
 	struct videobuf_dvb        dvb;
-	int (*original_demod_sleep)(struct dvb_frontend* fe);
+	int (*original_demod_sleep)(struct dvb_frontend *fe);
+	int (*original_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
+	int (*original_set_high_voltage)(struct dvb_frontend *fe, long arg);
 #endif
 };
 
@@ -594,7 +602,6 @@
 
 void saa7134_track_gpio(struct saa7134_dev *dev, char *msg);
 void saa7134_set_gpio(struct saa7134_dev *dev, int bit_no, int value);
-int saa7134_tuner_callback(void *ptr, int command, int arg);
 
 #define SAA7134_PGTABLE_SIZE 4096
 
@@ -631,6 +638,7 @@
 
 extern int saa7134_board_init1(struct saa7134_dev *dev);
 extern int saa7134_board_init2(struct saa7134_dev *dev);
+int saa7134_tuner_callback(void *priv, int command, int arg);
 
 
 /* ----------------------------------------------------------- */
diff --git a/drivers/media/video/saa717x.c b/drivers/media/video/saa717x.c
new file mode 100644
index 0000000..53c5edb
--- /dev/null
+++ b/drivers/media/video/saa717x.c
@@ -0,0 +1,1516 @@
+/*
+ * saa717x - Philips SAA717xHL video decoder driver
+ *
+ * Based on the saa7115 driver
+ *
+ * Changes by Ohta Kyuma <alpha292@bremen.or.jp>
+ *    - Apply to SAA717x,NEC uPD64031,uPD64083. (1/31/2004)
+ *
+ * Changes by T.Adachi (tadachi@tadachi-net.com)
+ *    - support audio, video scaler etc, and checked the initialize sequence.
+ *
+ * Cleaned up by Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * Note: this is a reversed engineered driver based on captures from
+ * the I2C bus under Windows. This chip is very similar to the saa7134,
+ * though. Unfortunately, this driver is currently only working for NTSC.
+ *
+ * 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/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+#include <linux/videodev.h>
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv.h>
+
+MODULE_DESCRIPTION("Philips SAA717x audio/video decoder driver");
+MODULE_AUTHOR("K. Ohta, T. Adachi, Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+
+struct saa717x_state {
+	v4l2_std_id std;
+	int input;
+	int enable;
+	int radio;
+	int bright;
+	int contrast;
+	int hue;
+	int sat;
+	int playback;
+	int audio;
+	int tuner_audio_mode;
+	int audio_main_mute;
+	int audio_main_vol_r;
+	int audio_main_vol_l;
+	u16 audio_main_bass;
+	u16 audio_main_treble;
+	u16 audio_main_volume;
+	u16 audio_main_balance;
+	int audio_input;
+};
+
+/* ----------------------------------------------------------------------- */
+
+/* for audio mode */
+#define TUNER_AUDIO_MONO   	0  /* LL */
+#define TUNER_AUDIO_STEREO 	1  /* LR */
+#define TUNER_AUDIO_LANG1  	2  /* LL */
+#define TUNER_AUDIO_LANG2  	3  /* RR */
+
+#define SAA717X_NTSC_WIDTH   	(704)
+#define SAA717X_NTSC_HEIGHT  	(480)
+
+/* ----------------------------------------------------------------------- */
+
+static int saa717x_write(struct i2c_client *client, u32 reg, u32 value)
+{
+	struct i2c_adapter *adap = client->adapter;
+	int fw_addr = reg == 0x454 || (reg >= 0x464 && reg <= 0x478) || reg == 0x480 || reg == 0x488;
+	unsigned char mm1[6];
+	struct i2c_msg msg;
+
+	msg.flags = 0;
+	msg.addr = client->addr;
+	mm1[0] = (reg >> 8) & 0xff;
+	mm1[1] = reg & 0xff;
+
+	if (fw_addr) {
+		mm1[4] = (value >> 16) & 0xff;
+		mm1[3] = (value >> 8) & 0xff;
+		mm1[2] = value & 0xff;
+	} else {
+		mm1[2] = value & 0xff;
+	}
+	msg.len = fw_addr ? 5 : 3; /* Long Registers have *only* three bytes! */
+	msg.buf = mm1;
+	v4l_dbg(2, debug, client, "wrote:  reg 0x%03x=%08x\n", reg, value);
+	return i2c_transfer(adap, &msg, 1) == 1;
+}
+
+static void saa717x_write_regs(struct i2c_client *client, u32 *data)
+{
+	while (data[0] || data[1]) {
+		saa717x_write(client, data[0], data[1]);
+		data += 2;
+	}
+}
+
+static u32 saa717x_read(struct i2c_client *client, u32 reg)
+{
+	struct i2c_adapter *adap = client->adapter;
+	int fw_addr = (reg >= 0x404 && reg <= 0x4b8) || reg == 0x528;
+	unsigned char mm1[2];
+	unsigned char mm2[4] = { 0, 0, 0, 0 };
+	struct i2c_msg msgs[2];
+	u32 value;
+
+	msgs[0].flags = 0;
+	msgs[1].flags = I2C_M_RD;
+	msgs[0].addr = msgs[1].addr = client->addr;
+	mm1[0] = (reg >> 8) & 0xff;
+	mm1[1] = reg & 0xff;
+	msgs[0].len = 2;
+	msgs[0].buf = mm1;
+	msgs[1].len = fw_addr ? 3 : 1; /* Multibyte Registers contains *only* 3 bytes */
+	msgs[1].buf = mm2;
+	i2c_transfer(adap, msgs, 2);
+
+	if (fw_addr)
+		value = (mm2[2] & 0xff)  | ((mm2[1] & 0xff) >> 8) | ((mm2[0] & 0xff) >> 16);
+	else
+		value = mm2[0] & 0xff;
+
+	v4l_dbg(2, debug, client, "read:  reg 0x%03x=0x%08x\n", reg, value);
+	return value;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static u32 reg_init_initialize[] =
+{
+	/* from linux driver */
+	0x101, 0x008, /* Increment delay */
+
+	0x103, 0x000, /* Analog input control 2 */
+	0x104, 0x090, /* Analog input control 3 */
+	0x105, 0x090, /* Analog input control 4 */
+	0x106, 0x0eb, /* Horizontal sync start */
+	0x107, 0x0e0, /* Horizontal sync stop */
+	0x109, 0x055, /* Luminance control */
+
+	0x10f, 0x02a, /* Chroma gain control */
+	0x110, 0x000, /* Chroma control 2 */
+
+	0x114, 0x045, /* analog/ADC */
+
+	0x118, 0x040, /* RAW data gain */
+	0x119, 0x080, /* RAW data offset */
+
+	0x044, 0x000, /* VBI horizontal input window start (L) TASK A */
+	0x045, 0x000, /* VBI horizontal input window start (H) TASK A */
+	0x046, 0x0cf, /* VBI horizontal input window stop (L) TASK A */
+	0x047, 0x002, /* VBI horizontal input window stop (H) TASK A */
+
+	0x049, 0x000, /* VBI vertical input window start (H) TASK A */
+
+	0x04c, 0x0d0, /* VBI horizontal output length (L) TASK A */
+	0x04d, 0x002, /* VBI horizontal output length (H) TASK A */
+
+	0x064, 0x080, /* Lumina brightness TASK A */
+	0x065, 0x040, /* Luminance contrast TASK A */
+	0x066, 0x040, /* Chroma saturation TASK A */
+	/* 067H: Reserved */
+	0x068, 0x000, /* VBI horizontal scaling increment (L) TASK A */
+	0x069, 0x004, /* VBI horizontal scaling increment (H) TASK A */
+	0x06a, 0x000, /* VBI phase offset TASK A */
+
+	0x06e, 0x000, /* Horizontal phase offset Luma TASK A */
+	0x06f, 0x000, /* Horizontal phase offset Chroma TASK A */
+
+	0x072, 0x000, /* Vertical filter mode TASK A */
+
+	0x084, 0x000, /* VBI horizontal input window start (L) TAKS B */
+	0x085, 0x000, /* VBI horizontal input window start (H) TAKS B */
+	0x086, 0x0cf, /* VBI horizontal input window stop (L) TAKS B */
+	0x087, 0x002, /* VBI horizontal input window stop (H) TAKS B */
+
+	0x089, 0x000, /* VBI vertical input window start (H) TAKS B */
+
+	0x08c, 0x0d0, /* VBI horizontal output length (L) TASK B */
+	0x08d, 0x002, /* VBI horizontal output length (H) TASK B */
+
+	0x0a4, 0x080, /* Lumina brightness TASK B */
+	0x0a5, 0x040, /* Luminance contrast TASK B */
+	0x0a6, 0x040, /* Chroma saturation TASK B */
+	/* 0A7H reserved */
+	0x0a8, 0x000, /* VBI horizontal scaling increment (L) TASK B */
+	0x0a9, 0x004, /* VBI horizontal scaling increment (H) TASK B */
+	0x0aa, 0x000, /* VBI phase offset TASK B */
+
+	0x0ae, 0x000, /* Horizontal phase offset Luma TASK B */
+	0x0af, 0x000, /*Horizontal phase offset Chroma TASK B */
+
+	0x0b2, 0x000, /* Vertical filter mode TASK B */
+
+	0x00c, 0x000, /* Start point GREEN path */
+	0x00d, 0x000, /* Start point BLUE path */
+	0x00e, 0x000, /* Start point RED path */
+
+	0x010, 0x010, /* GREEN path gamma curve --- */
+	0x011, 0x020,
+	0x012, 0x030,
+	0x013, 0x040,
+	0x014, 0x050,
+	0x015, 0x060,
+	0x016, 0x070,
+	0x017, 0x080,
+	0x018, 0x090,
+	0x019, 0x0a0,
+	0x01a, 0x0b0,
+	0x01b, 0x0c0,
+	0x01c, 0x0d0,
+	0x01d, 0x0e0,
+	0x01e, 0x0f0,
+	0x01f, 0x0ff, /* --- GREEN path gamma curve */
+
+	0x020, 0x010, /* BLUE path gamma curve --- */
+	0x021, 0x020,
+	0x022, 0x030,
+	0x023, 0x040,
+	0x024, 0x050,
+	0x025, 0x060,
+	0x026, 0x070,
+	0x027, 0x080,
+	0x028, 0x090,
+	0x029, 0x0a0,
+	0x02a, 0x0b0,
+	0x02b, 0x0c0,
+	0x02c, 0x0d0,
+	0x02d, 0x0e0,
+	0x02e, 0x0f0,
+	0x02f, 0x0ff, /* --- BLUE path gamma curve */
+
+	0x030, 0x010, /* RED path gamma curve --- */
+	0x031, 0x020,
+	0x032, 0x030,
+	0x033, 0x040,
+	0x034, 0x050,
+	0x035, 0x060,
+	0x036, 0x070,
+	0x037, 0x080,
+	0x038, 0x090,
+	0x039, 0x0a0,
+	0x03a, 0x0b0,
+	0x03b, 0x0c0,
+	0x03c, 0x0d0,
+	0x03d, 0x0e0,
+	0x03e, 0x0f0,
+	0x03f, 0x0ff, /* --- RED path gamma curve */
+
+	0x109, 0x085, /* Luminance control  */
+
+	/**** from app start ****/
+	0x584, 0x000, /* AGC gain control */
+	0x585, 0x000, /* Program count */
+	0x586, 0x003, /* Status reset */
+	0x588, 0x0ff, /* Number of audio samples (L) */
+	0x589, 0x00f, /* Number of audio samples (M) */
+	0x58a, 0x000, /* Number of audio samples (H) */
+	0x58b, 0x000, /* Audio select */
+	0x58c, 0x010, /* Audio channel assign1 */
+	0x58d, 0x032, /* Audio channel assign2 */
+	0x58e, 0x054, /* Audio channel assign3 */
+	0x58f, 0x023, /* Audio format */
+	0x590, 0x000, /* SIF control */
+
+	0x595, 0x000, /* ?? */
+	0x596, 0x000, /* ?? */
+	0x597, 0x000, /* ?? */
+
+	0x464, 0x00, /* Digital input crossbar1 */
+
+	0x46c, 0xbbbb10, /* Digital output selection1-3 */
+	0x470, 0x101010, /* Digital output selection4-6 */
+
+	0x478, 0x00, /* Sound feature control */
+
+	0x474, 0x18, /* Softmute control */
+
+	0x454, 0x0425b9, /* Sound Easy programming(reset) */
+	0x454, 0x042539, /* Sound Easy programming(reset) */
+
+
+	/**** common setting( of DVD play, including scaler commands) ****/
+	0x042, 0x003, /* Data path configuration for VBI (TASK A) */
+
+	0x082, 0x003, /* Data path configuration for VBI (TASK B) */
+
+	0x108, 0x0f8, /* Sync control */
+	0x2a9, 0x0fd, /* ??? */
+	0x102, 0x089, /* select video input "mode 9" */
+	0x111, 0x000, /* Mode/delay control */
+
+	0x10e, 0x00a, /* Chroma control 1 */
+
+	0x594, 0x002, /* SIF, analog I/O select */
+
+	0x454, 0x0425b9, /* Sound  */
+	0x454, 0x042539,
+
+	0x111, 0x000,
+	0x10e, 0x00a,
+	0x464, 0x000,
+	0x300, 0x000,
+	0x301, 0x006,
+	0x302, 0x000,
+	0x303, 0x006,
+	0x308, 0x040,
+	0x309, 0x000,
+	0x30a, 0x000,
+	0x30b, 0x000,
+	0x000, 0x002,
+	0x001, 0x000,
+	0x002, 0x000,
+	0x003, 0x000,
+	0x004, 0x033,
+	0x040, 0x01d,
+	0x041, 0x001,
+	0x042, 0x004,
+	0x043, 0x000,
+	0x080, 0x01e,
+	0x081, 0x001,
+	0x082, 0x004,
+	0x083, 0x000,
+	0x190, 0x018,
+	0x115, 0x000,
+	0x116, 0x012,
+	0x117, 0x018,
+	0x04a, 0x011,
+	0x08a, 0x011,
+	0x04b, 0x000,
+	0x08b, 0x000,
+	0x048, 0x000,
+	0x088, 0x000,
+	0x04e, 0x012,
+	0x08e, 0x012,
+	0x058, 0x012,
+	0x098, 0x012,
+	0x059, 0x000,
+	0x099, 0x000,
+	0x05a, 0x003,
+	0x09a, 0x003,
+	0x05b, 0x001,
+	0x09b, 0x001,
+	0x054, 0x008,
+	0x094, 0x008,
+	0x055, 0x000,
+	0x095, 0x000,
+	0x056, 0x0c7,
+	0x096, 0x0c7,
+	0x057, 0x002,
+	0x097, 0x002,
+	0x0ff, 0x0ff,
+	0x060, 0x001,
+	0x0a0, 0x001,
+	0x061, 0x000,
+	0x0a1, 0x000,
+	0x062, 0x000,
+	0x0a2, 0x000,
+	0x063, 0x000,
+	0x0a3, 0x000,
+	0x070, 0x000,
+	0x0b0, 0x000,
+	0x071, 0x004,
+	0x0b1, 0x004,
+	0x06c, 0x0e9,
+	0x0ac, 0x0e9,
+	0x06d, 0x003,
+	0x0ad, 0x003,
+	0x05c, 0x0d0,
+	0x09c, 0x0d0,
+	0x05d, 0x002,
+	0x09d, 0x002,
+	0x05e, 0x0f2,
+	0x09e, 0x0f2,
+	0x05f, 0x000,
+	0x09f, 0x000,
+	0x074, 0x000,
+	0x0b4, 0x000,
+	0x075, 0x000,
+	0x0b5, 0x000,
+	0x076, 0x000,
+	0x0b6, 0x000,
+	0x077, 0x000,
+	0x0b7, 0x000,
+	0x195, 0x008,
+	0x0ff, 0x0ff,
+	0x108, 0x0f8,
+	0x111, 0x000,
+	0x10e, 0x00a,
+	0x2a9, 0x0fd,
+	0x464, 0x001,
+	0x454, 0x042135,
+	0x598, 0x0e7,
+	0x599, 0x07d,
+	0x59a, 0x018,
+	0x59c, 0x066,
+	0x59d, 0x090,
+	0x59e, 0x001,
+	0x584, 0x000,
+	0x585, 0x000,
+	0x586, 0x003,
+	0x588, 0x0ff,
+	0x589, 0x00f,
+	0x58a, 0x000,
+	0x58b, 0x000,
+	0x58c, 0x010,
+	0x58d, 0x032,
+	0x58e, 0x054,
+	0x58f, 0x023,
+	0x590, 0x000,
+	0x595, 0x000,
+	0x596, 0x000,
+	0x597, 0x000,
+	0x464, 0x000,
+	0x46c, 0xbbbb10,
+	0x470, 0x101010,
+
+
+	0x478, 0x000,
+	0x474, 0x018,
+	0x454, 0x042135,
+	0x598, 0x0e7,
+	0x599, 0x07d,
+	0x59a, 0x018,
+	0x59c, 0x066,
+	0x59d, 0x090,
+	0x59e, 0x001,
+	0x584, 0x000,
+	0x585, 0x000,
+	0x586, 0x003,
+	0x588, 0x0ff,
+	0x589, 0x00f,
+	0x58a, 0x000,
+	0x58b, 0x000,
+	0x58c, 0x010,
+	0x58d, 0x032,
+	0x58e, 0x054,
+	0x58f, 0x023,
+	0x590, 0x000,
+	0x595, 0x000,
+	0x596, 0x000,
+	0x597, 0x000,
+	0x464, 0x000,
+	0x46c, 0xbbbb10,
+	0x470, 0x101010,
+
+	0x478, 0x000,
+	0x474, 0x018,
+	0x454, 0x042135,
+	0x598, 0x0e7,
+	0x599, 0x07d,
+	0x59a, 0x018,
+	0x59c, 0x066,
+	0x59d, 0x090,
+	0x59e, 0x001,
+	0x584, 0x000,
+	0x585, 0x000,
+	0x586, 0x003,
+	0x588, 0x0ff,
+	0x589, 0x00f,
+	0x58a, 0x000,
+	0x58b, 0x000,
+	0x58c, 0x010,
+	0x58d, 0x032,
+	0x58e, 0x054,
+	0x58f, 0x023,
+	0x590, 0x000,
+	0x595, 0x000,
+	0x596, 0x000,
+	0x597, 0x000,
+	0x464, 0x000,
+	0x46c, 0xbbbb10,
+	0x470, 0x101010,
+	0x478, 0x000,
+	0x474, 0x018,
+	0x454, 0x042135,
+	0x193, 0x000,
+	0x300, 0x000,
+	0x301, 0x006,
+	0x302, 0x000,
+	0x303, 0x006,
+	0x308, 0x040,
+	0x309, 0x000,
+	0x30a, 0x000,
+	0x30b, 0x000,
+	0x000, 0x002,
+	0x001, 0x000,
+	0x002, 0x000,
+	0x003, 0x000,
+	0x004, 0x033,
+	0x040, 0x01d,
+	0x041, 0x001,
+	0x042, 0x004,
+	0x043, 0x000,
+	0x080, 0x01e,
+	0x081, 0x001,
+	0x082, 0x004,
+	0x083, 0x000,
+	0x190, 0x018,
+	0x115, 0x000,
+	0x116, 0x012,
+	0x117, 0x018,
+	0x04a, 0x011,
+	0x08a, 0x011,
+	0x04b, 0x000,
+	0x08b, 0x000,
+	0x048, 0x000,
+	0x088, 0x000,
+	0x04e, 0x012,
+	0x08e, 0x012,
+	0x058, 0x012,
+	0x098, 0x012,
+	0x059, 0x000,
+	0x099, 0x000,
+	0x05a, 0x003,
+	0x09a, 0x003,
+	0x05b, 0x001,
+	0x09b, 0x001,
+	0x054, 0x008,
+	0x094, 0x008,
+	0x055, 0x000,
+	0x095, 0x000,
+	0x056, 0x0c7,
+	0x096, 0x0c7,
+	0x057, 0x002,
+	0x097, 0x002,
+	0x060, 0x001,
+	0x0a0, 0x001,
+	0x061, 0x000,
+	0x0a1, 0x000,
+	0x062, 0x000,
+	0x0a2, 0x000,
+	0x063, 0x000,
+	0x0a3, 0x000,
+	0x070, 0x000,
+	0x0b0, 0x000,
+	0x071, 0x004,
+	0x0b1, 0x004,
+	0x06c, 0x0e9,
+	0x0ac, 0x0e9,
+	0x06d, 0x003,
+	0x0ad, 0x003,
+	0x05c, 0x0d0,
+	0x09c, 0x0d0,
+	0x05d, 0x002,
+	0x09d, 0x002,
+	0x05e, 0x0f2,
+	0x09e, 0x0f2,
+	0x05f, 0x000,
+	0x09f, 0x000,
+	0x074, 0x000,
+	0x0b4, 0x000,
+	0x075, 0x000,
+	0x0b5, 0x000,
+	0x076, 0x000,
+	0x0b6, 0x000,
+	0x077, 0x000,
+	0x0b7, 0x000,
+	0x195, 0x008,
+	0x598, 0x0e7,
+	0x599, 0x07d,
+	0x59a, 0x018,
+	0x59c, 0x066,
+	0x59d, 0x090,
+	0x59e, 0x001,
+	0x584, 0x000,
+	0x585, 0x000,
+	0x586, 0x003,
+	0x588, 0x0ff,
+	0x589, 0x00f,
+	0x58a, 0x000,
+	0x58b, 0x000,
+	0x58c, 0x010,
+	0x58d, 0x032,
+	0x58e, 0x054,
+	0x58f, 0x023,
+	0x590, 0x000,
+	0x595, 0x000,
+	0x596, 0x000,
+	0x597, 0x000,
+	0x464, 0x000,
+	0x46c, 0xbbbb10,
+	0x470, 0x101010,
+	0x478, 0x000,
+	0x474, 0x018,
+	0x454, 0x042135,
+	0x193, 0x0a6,
+	0x108, 0x0f8,
+	0x042, 0x003,
+	0x082, 0x003,
+	0x454, 0x0425b9,
+	0x454, 0x042539,
+	0x193, 0x000,
+	0x193, 0x0a6,
+	0x464, 0x000,
+
+	0, 0
+};
+
+/* Tuner */
+static u32 reg_init_tuner_input[] = {
+	0x108, 0x0f8, /* Sync control */
+	0x111, 0x000, /* Mode/delay control */
+	0x10e, 0x00a, /* Chroma control 1 */
+	0, 0
+};
+
+/* Composite */
+static u32 reg_init_composite_input[] = {
+	0x108, 0x0e8, /* Sync control */
+	0x111, 0x000, /* Mode/delay control */
+	0x10e, 0x04a, /* Chroma control 1 */
+	0, 0
+};
+
+/* S-Video */
+static u32 reg_init_svideo_input[] = {
+	0x108, 0x0e8, /* Sync control */
+	0x111, 0x000, /* Mode/delay control */
+	0x10e, 0x04a, /* Chroma control 1 */
+	0, 0
+};
+
+static u32 reg_set_audio_template[4][2] =
+{
+	{ /* for MONO
+		tadachi 6/29 DMA audio output select?
+		Register 0x46c
+		7-4: DMA2, 3-0: DMA1 ch. DMA4, DMA3 DMA2, DMA1
+		0: MAIN left,  1: MAIN right
+		2: AUX1 left,  3: AUX1 right
+		4: AUX2 left,  5: AUX2 right
+		6: DPL left,   7: DPL  right
+		8: DPL center, 9: DPL surround
+		A: monitor output, B: digital sense */
+		0xbbbb00,
+
+		/* tadachi 6/29 DAC and I2S output select?
+		   Register 0x470
+		   7-4:DAC right ch. 3-0:DAC left ch.
+		   I2S1 right,left  I2S2 right,left */
+		0x00,
+	},
+	{ /* for STEREO */
+		0xbbbb10, 0x101010,
+	},
+	{ /* for LANG1 */
+		0xbbbb00, 0x00,
+	},
+	{ /* for LANG2/SAP */
+		0xbbbb11, 0x111111,
+	}
+};
+
+
+/* Get detected audio flags (from saa7134 driver) */
+static void get_inf_dev_status(struct i2c_client *client,
+		int *dual_flag, int *stereo_flag)
+{
+	u32 reg_data3;
+
+	static char *stdres[0x20] = {
+		[0x00] = "no standard detected",
+		[0x01] = "B/G (in progress)",
+		[0x02] = "D/K (in progress)",
+		[0x03] = "M (in progress)",
+
+		[0x04] = "B/G A2",
+		[0x05] = "B/G NICAM",
+		[0x06] = "D/K A2 (1)",
+		[0x07] = "D/K A2 (2)",
+		[0x08] = "D/K A2 (3)",
+		[0x09] = "D/K NICAM",
+		[0x0a] = "L NICAM",
+		[0x0b] = "I NICAM",
+
+		[0x0c] = "M Korea",
+		[0x0d] = "M BTSC ",
+		[0x0e] = "M EIAJ",
+
+		[0x0f] = "FM radio / IF 10.7 / 50 deemp",
+		[0x10] = "FM radio / IF 10.7 / 75 deemp",
+		[0x11] = "FM radio / IF sel / 50 deemp",
+		[0x12] = "FM radio / IF sel / 75 deemp",
+
+		[0x13 ... 0x1e] = "unknown",
+		[0x1f] = "??? [in progress]",
+	};
+
+
+	*dual_flag = *stereo_flag = 0;
+
+	/* (demdec status: 0x528) */
+
+	/* read current status */
+	reg_data3 = saa717x_read(client, 0x0528);
+
+	v4l_dbg(1, debug, client, "tvaudio thread status: 0x%x [%s%s%s]\n",
+		reg_data3, stdres[reg_data3 & 0x1f],
+		(reg_data3 & 0x000020) ? ",stereo" : "",
+		(reg_data3 & 0x000040) ? ",dual"   : "");
+	v4l_dbg(1, debug, client, "detailed status: "
+		"%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s\n",
+		(reg_data3 & 0x000080) ? " A2/EIAJ pilot tone "     : "",
+		(reg_data3 & 0x000100) ? " A2/EIAJ dual "           : "",
+		(reg_data3 & 0x000200) ? " A2/EIAJ stereo "         : "",
+		(reg_data3 & 0x000400) ? " A2/EIAJ noise mute "     : "",
+
+		(reg_data3 & 0x000800) ? " BTSC/FM radio pilot "    : "",
+		(reg_data3 & 0x001000) ? " SAP carrier "            : "",
+		(reg_data3 & 0x002000) ? " BTSC stereo noise mute " : "",
+		(reg_data3 & 0x004000) ? " SAP noise mute "         : "",
+		(reg_data3 & 0x008000) ? " VDSP "                   : "",
+
+		(reg_data3 & 0x010000) ? " NICST "                  : "",
+		(reg_data3 & 0x020000) ? " NICDU "                  : "",
+		(reg_data3 & 0x040000) ? " NICAM muted "            : "",
+		(reg_data3 & 0x080000) ? " NICAM reserve sound "    : "",
+
+		(reg_data3 & 0x100000) ? " init done "              : "");
+
+	if (reg_data3 & 0x000220) {
+		v4l_dbg(1, debug, client, "ST!!!\n");
+		*stereo_flag = 1;
+	}
+
+	if (reg_data3 & 0x000140) {
+		v4l_dbg(1, debug, client, "DUAL!!!\n");
+		*dual_flag = 1;
+	}
+}
+
+/* regs write to set audio mode */
+static void set_audio_mode(struct i2c_client *client, int audio_mode)
+{
+	v4l_dbg(1, debug, client, "writing registers to set audio mode by set %d\n",
+			audio_mode);
+
+	saa717x_write(client, 0x46c, reg_set_audio_template[audio_mode][0]);
+	saa717x_write(client, 0x470, reg_set_audio_template[audio_mode][1]);
+}
+
+/* write regs to video output level (bright,contrast,hue,sat) */
+static void set_video_output_level_regs(struct i2c_client *client,
+		struct saa717x_state *decoder)
+{
+	/* brightness ffh (bright) - 80h (ITU level) - 00h (dark) */
+	saa717x_write(client, 0x10a, decoder->bright);
+
+	/* contrast 7fh (max: 1.984) - 44h (ITU) - 40h (1.0) -
+	   0h (luminance off) 40: i2c dump
+	   c0h (-1.0 inverse chrominance)
+	   80h (-2.0 inverse chrominance) */
+	saa717x_write(client, 0x10b, decoder->contrast);
+
+	/* saturation? 7fh(max)-40h(ITU)-0h(color off)
+	   c0h (-1.0 inverse chrominance)
+	   80h (-2.0 inverse chrominance) */
+	saa717x_write(client, 0x10c, decoder->sat);
+
+	/* color hue (phase) control
+	   7fh (+178.6) - 0h (0 normal) - 80h (-180.0) */
+	saa717x_write(client, 0x10d, decoder->hue);
+}
+
+/* write regs to set audio volume, bass and treble */
+static int set_audio_regs(struct i2c_client *client,
+		struct saa717x_state *decoder)
+{
+	u8 mute = 0xac; /* -84 dB */
+	u32 val;
+	unsigned int work_l, work_r;
+
+	/* set SIF analog I/O select */
+	saa717x_write(client, 0x0594, decoder->audio_input);
+	v4l_dbg(1, debug, client, "set audio input %d\n",
+			decoder->audio_input);
+
+	/* normalize ( 65535 to 0 -> 24 to -40 (not -84)) */
+	work_l = (min(65536 - decoder->audio_main_balance, 32768) * decoder->audio_main_volume) / 32768;
+	work_r = (min(decoder->audio_main_balance, (u16)32768) * decoder->audio_main_volume) / 32768;
+	decoder->audio_main_vol_l = (long)work_l * (24 - (-40)) / 65535 - 40;
+	decoder->audio_main_vol_r = (long)work_r * (24 - (-40)) / 65535 - 40;
+
+	/* set main volume */
+	/* main volume L[7-0],R[7-0],0x00  24=24dB,-83dB, -84(mute) */
+	/*    def:0dB->6dB(MPG600GR) */
+	/* if mute is on, set mute */
+	if (decoder->audio_main_mute) {
+		val = mute | (mute << 8);
+	} else {
+		val = (u8)decoder->audio_main_vol_l |
+			((u8)decoder->audio_main_vol_r << 8);
+	}
+
+	saa717x_write(client, 0x480, val);
+
+	/* bass and treble; go to another function */
+	/* set bass and treble */
+	val = decoder->audio_main_bass | (decoder->audio_main_treble << 8);
+	saa717x_write(client, 0x488, val);
+	return 0;
+}
+
+/********** scaling staff ***********/
+static void set_h_prescale(struct i2c_client *client,
+		int task, int prescale)
+{
+	static const struct {
+		int xpsc;
+		int xacl;
+		int xc2_1;
+		int xdcg;
+		int vpfy;
+	} vals[] = {
+		/* XPSC XACL XC2_1 XDCG VPFY */
+		{    1,   0,    0,    0,   0 },
+		{    2,   2,    1,    2,   2 },
+		{    3,   4,    1,    3,   2 },
+		{    4,   8,    1,    4,   2 },
+		{    5,   8,    1,    4,   2 },
+		{    6,   8,    1,    4,   3 },
+		{    7,   8,    1,    4,   3 },
+		{    8,  15,    0,    4,   3 },
+		{    9,  15,    0,    4,   3 },
+		{   10,  16,    1,    5,   3 },
+	};
+	static const int count = ARRAY_SIZE(vals);
+	int i, task_shift;
+
+	task_shift = task * 0x40;
+	for (i = 0; i < count; i++)
+		if (vals[i].xpsc == prescale)
+			break;
+	if (i == count)
+		return;
+
+	/* horizonal prescaling */
+	saa717x_write(client, 0x60 + task_shift, vals[i].xpsc);
+	/* accumulation length */
+	saa717x_write(client, 0x61 + task_shift, vals[i].xacl);
+	/* level control */
+	saa717x_write(client, 0x62 + task_shift,
+			(vals[i].xc2_1 << 3) | vals[i].xdcg);
+	/*FIR prefilter control */
+	saa717x_write(client, 0x63 + task_shift,
+			(vals[i].vpfy << 2) | vals[i].vpfy);
+}
+
+/********** scaling staff ***********/
+static void set_v_scale(struct i2c_client *client, int task, int yscale)
+{
+	int task_shift;
+
+	task_shift = task * 0x40;
+	/* Vertical scaling ratio (LOW) */
+	saa717x_write(client, 0x70 + task_shift, yscale & 0xff);
+	/* Vertical scaling ratio (HI) */
+	saa717x_write(client, 0x71 + task_shift, yscale >> 8);
+}
+
+static int saa717x_set_audio_clock_freq(struct i2c_client *client, u32 freq)
+{
+	/* not yet implament, so saa717x_cfg_??hz_??_audio is not defined. */
+	return 0;
+}
+
+static int saa717x_set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+{
+	struct saa717x_state *state = i2c_get_clientdata(client);
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		if (ctrl->value < 0 || ctrl->value > 255) {
+			v4l_err(client, "invalid brightness setting %d\n", ctrl->value);
+			return -ERANGE;
+		}
+
+		state->bright = ctrl->value;
+		v4l_dbg(1, debug, client, "bright:%d\n", state->bright);
+		saa717x_write(client, 0x10a, state->bright);
+		break;
+
+	case V4L2_CID_CONTRAST:
+		if (ctrl->value < 0 || ctrl->value > 127) {
+			v4l_err(client, "invalid contrast setting %d\n", ctrl->value);
+			return -ERANGE;
+		}
+
+		state->contrast = ctrl->value;
+		v4l_dbg(1, debug, client, "contrast:%d\n", state->contrast);
+		saa717x_write(client, 0x10b, state->contrast);
+		break;
+
+	case V4L2_CID_SATURATION:
+		if (ctrl->value < 0 || ctrl->value > 127) {
+			v4l_err(client, "invalid saturation setting %d\n", ctrl->value);
+			return -ERANGE;
+		}
+
+		state->sat = ctrl->value;
+		v4l_dbg(1, debug, client, "sat:%d\n", state->sat);
+		saa717x_write(client, 0x10c, state->sat);
+		break;
+
+	case V4L2_CID_HUE:
+		if (ctrl->value < -127 || ctrl->value > 127) {
+			v4l_err(client, "invalid hue setting %d\n", ctrl->value);
+			return -ERANGE;
+		}
+
+		state->hue = ctrl->value;
+		v4l_dbg(1, debug, client, "hue:%d\n", state->hue);
+		saa717x_write(client, 0x10d, state->hue);
+		break;
+
+	case V4L2_CID_AUDIO_MUTE:
+		state->audio_main_mute = ctrl->value;
+		set_audio_regs(client, state);
+		break;
+
+	case V4L2_CID_AUDIO_VOLUME:
+		state->audio_main_volume = ctrl->value;
+		set_audio_regs(client, state);
+		break;
+
+	case V4L2_CID_AUDIO_BALANCE:
+		state->audio_main_balance = ctrl->value;
+		set_audio_regs(client, state);
+		break;
+
+	case V4L2_CID_AUDIO_TREBLE:
+		state->audio_main_treble = ctrl->value;
+		set_audio_regs(client, state);
+		break;
+
+	case V4L2_CID_AUDIO_BASS:
+		state->audio_main_bass = ctrl->value;
+		set_audio_regs(client, state);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int saa717x_get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+{
+	struct saa717x_state *state = i2c_get_clientdata(client);
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		ctrl->value = state->bright;
+		break;
+
+	case V4L2_CID_CONTRAST:
+		ctrl->value = state->contrast;
+		break;
+
+	case V4L2_CID_SATURATION:
+		ctrl->value = state->sat;
+		break;
+
+	case V4L2_CID_HUE:
+		ctrl->value = state->hue;
+		break;
+
+	case V4L2_CID_AUDIO_MUTE:
+		ctrl->value = state->audio_main_mute;
+		break;
+
+	case V4L2_CID_AUDIO_VOLUME:
+		ctrl->value = state->audio_main_volume;
+		break;
+
+	case V4L2_CID_AUDIO_BALANCE:
+		ctrl->value = state->audio_main_balance;
+		break;
+
+	case V4L2_CID_AUDIO_TREBLE:
+		ctrl->value = state->audio_main_treble;
+		break;
+
+	case V4L2_CID_AUDIO_BASS:
+		ctrl->value = state->audio_main_bass;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static struct v4l2_queryctrl saa717x_qctrl[] = {
+	{
+		.id            = V4L2_CID_BRIGHTNESS,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Brightness",
+		.minimum       = 0,
+		.maximum       = 255,
+		.step          = 1,
+		.default_value = 128,
+		.flags         = 0,
+	}, {
+		.id            = V4L2_CID_CONTRAST,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Contrast",
+		.minimum       = 0,
+		.maximum       = 255,
+		.step          = 1,
+		.default_value = 64,
+		.flags         = 0,
+	}, {
+		.id            = V4L2_CID_SATURATION,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Saturation",
+		.minimum       = 0,
+		.maximum       = 255,
+		.step          = 1,
+		.default_value = 64,
+		.flags         = 0,
+	}, {
+		.id            = V4L2_CID_HUE,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Hue",
+		.minimum       = -128,
+		.maximum       = 127,
+		.step          = 1,
+		.default_value = 0,
+		.flags 	       = 0,
+	}, {
+		.id            = V4L2_CID_AUDIO_VOLUME,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Volume",
+		.minimum       = 0,
+		.maximum       = 65535,
+		.step          = 65535 / 100,
+		.default_value = 58880,
+		.flags         = 0,
+	}, {
+		.id            = V4L2_CID_AUDIO_BALANCE,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Balance",
+		.minimum       = 0,
+		.maximum       = 65535,
+		.step          = 65535 / 100,
+		.default_value = 32768,
+		.flags         = 0,
+	}, {
+		.id            = V4L2_CID_AUDIO_MUTE,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+		.name          = "Mute",
+		.minimum       = 0,
+		.maximum       = 1,
+		.step          = 1,
+		.default_value = 1,
+		.flags         = 0,
+	}, {
+		.id            = V4L2_CID_AUDIO_BASS,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Bass",
+		.minimum       = 0,
+		.maximum       = 65535,
+		.step          = 65535 / 100,
+		.default_value = 32768,
+	}, {
+		.id            = V4L2_CID_AUDIO_TREBLE,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Treble",
+		.minimum       = 0,
+		.maximum       = 65535,
+		.step          = 65535 / 100,
+		.default_value = 32768,
+	},
+};
+
+static int saa717x_set_video_input(struct i2c_client *client, struct saa717x_state *decoder, int inp)
+{
+	int is_tuner = inp & 0x80;  /* tuner input flag */
+
+	inp &= 0x7f;
+
+	v4l_dbg(1, debug, client, "decoder set input (%d)\n", inp);
+	/* inputs from 0-9 are available*/
+	/* saa717x have mode0-mode9 but mode5 is reserved. */
+	if (inp < 0 || inp > 9 || inp == 5)
+		return -EINVAL;
+
+	if (decoder->input != inp) {
+		int input_line = inp;
+
+		decoder->input = input_line;
+		v4l_dbg(1, debug, client,  "now setting %s input %d\n",
+				input_line >= 6 ? "S-Video" : "Composite",
+				input_line);
+
+		/* select mode */
+		saa717x_write(client, 0x102,
+				(saa717x_read(client, 0x102) & 0xf0) |
+				input_line);
+
+		/* bypass chrominance trap for modes 6..9 */
+		saa717x_write(client, 0x109,
+				(saa717x_read(client, 0x109) & 0x7f) |
+				(input_line < 6 ? 0x0 : 0x80));
+
+		/* change audio_mode */
+		if (is_tuner) {
+			/* tuner */
+			set_audio_mode(client, decoder->tuner_audio_mode);
+		} else {
+			/* Force to STEREO mode if Composite or
+			 * S-Video were chosen */
+			set_audio_mode(client, TUNER_AUDIO_STEREO);
+		}
+		/* change initialize procedure (Composite/S-Video) */
+		if (is_tuner)
+			saa717x_write_regs(client, reg_init_tuner_input);
+		else if (input_line >= 6)
+			saa717x_write_regs(client, reg_init_svideo_input);
+		else
+			saa717x_write_regs(client, reg_init_composite_input);
+	}
+
+	return 0;
+}
+
+static int saa717x_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+	struct saa717x_state *decoder = i2c_get_clientdata(client);
+
+	v4l_dbg(1, debug, client, "IOCTL: %08x\n", cmd);
+
+	switch (cmd) {
+	case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+		return saa717x_set_audio_clock_freq(client, *(u32 *)arg);
+
+	case VIDIOC_G_CTRL:
+		return saa717x_get_v4lctrl(client, (struct v4l2_control *)arg);
+
+	case VIDIOC_S_CTRL:
+		return saa717x_set_v4lctrl(client, (struct v4l2_control *)arg);
+
+	case VIDIOC_QUERYCTRL: {
+		struct v4l2_queryctrl *qc = arg;
+		int i;
+
+		for (i = 0; i < ARRAY_SIZE(saa717x_qctrl); i++)
+			if (qc->id && qc->id == saa717x_qctrl[i].id) {
+				memcpy(qc, &saa717x_qctrl[i], sizeof(*qc));
+				return 0;
+			}
+		return -EINVAL;
+	}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	case VIDIOC_DBG_G_REGISTER: {
+		struct v4l2_register *reg = arg;
+
+		if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
+			return -EINVAL;
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		reg->val = saa717x_read(client, reg->reg);
+		break;
+	}
+
+	case VIDIOC_DBG_S_REGISTER: {
+		struct v4l2_register *reg = arg;
+		u16 addr = reg->reg & 0xffff;
+		u8 val = reg->val & 0xff;
+
+		if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
+			return -EINVAL;
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		saa717x_write(client, addr, val);
+		break;
+	}
+#endif
+
+	case VIDIOC_S_FMT: {
+		struct v4l2_format *fmt = (struct v4l2_format *)arg;
+		struct v4l2_pix_format *pix;
+		int prescale, h_scale, v_scale;
+
+		pix = &fmt->fmt.pix;
+		v4l_dbg(1, debug, client, "decoder set size\n");
+
+		/* FIXME need better bounds checking here */
+		if (pix->width < 1 || pix->width > 1440)
+			return -EINVAL;
+		if (pix->height < 1 || pix->height > 960)
+			return -EINVAL;
+
+		/* scaling setting */
+		/* NTSC and interlace only */
+		prescale = SAA717X_NTSC_WIDTH / pix->width;
+		if (prescale == 0)
+			prescale = 1;
+		h_scale = 1024 * SAA717X_NTSC_WIDTH / prescale / pix->width;
+		/* interlace */
+		v_scale = 512 * 2 * SAA717X_NTSC_HEIGHT / pix->height;
+
+		/* Horizontal prescaling etc */
+		set_h_prescale(client, 0, prescale);
+		set_h_prescale(client, 1, prescale);
+
+		/* Horizontal scaling increment */
+		/* TASK A */
+		saa717x_write(client, 0x6C, (u8)(h_scale & 0xFF));
+		saa717x_write(client, 0x6D, (u8)((h_scale >> 8) & 0xFF));
+		/* TASK B */
+		saa717x_write(client, 0xAC, (u8)(h_scale & 0xFF));
+		saa717x_write(client, 0xAD, (u8)((h_scale >> 8) & 0xFF));
+
+		/* Vertical prescaling etc */
+		set_v_scale(client, 0, v_scale);
+		set_v_scale(client, 1, v_scale);
+
+		/* set video output size */
+		/* video number of pixels at output */
+		/* TASK A */
+		saa717x_write(client, 0x5C, (u8)(pix->width & 0xFF));
+		saa717x_write(client, 0x5D, (u8)((pix->width >> 8) & 0xFF));
+		/* TASK B */
+		saa717x_write(client, 0x9C, (u8)(pix->width & 0xFF));
+		saa717x_write(client, 0x9D, (u8)((pix->width >> 8) & 0xFF));
+
+		/* video number of lines at output */
+		/* TASK A */
+		saa717x_write(client, 0x5E, (u8)(pix->height & 0xFF));
+		saa717x_write(client, 0x5F, (u8)((pix->height >> 8) & 0xFF));
+		/* TASK B */
+		saa717x_write(client, 0x9E, (u8)(pix->height & 0xFF));
+		saa717x_write(client, 0x9F, (u8)((pix->height >> 8) & 0xFF));
+		break;
+	}
+
+	case AUDC_SET_RADIO:
+		decoder->radio = 1;
+		break;
+
+	case VIDIOC_S_STD: {
+		v4l2_std_id std = *(v4l2_std_id *) arg;
+
+		v4l_dbg(1, debug, client, "decoder set norm ");
+		v4l_dbg(1, debug, client, "(not yet implementd)\n");
+
+		decoder->radio = 0;
+		decoder->std = std;
+		break;
+	}
+
+	case VIDIOC_INT_G_AUDIO_ROUTING: {
+		struct v4l2_routing *route = arg;
+
+		route->input = decoder->audio_input;
+		route->output = 0;
+		break;
+	}
+
+	case VIDIOC_INT_S_AUDIO_ROUTING: {
+		struct v4l2_routing *route = arg;
+
+		if (route->input < 3) { /* FIXME! --tadachi */
+			decoder->audio_input = route->input;
+			v4l_dbg(1, debug, client,
+				"set decoder audio input to %d\n",
+				decoder->audio_input);
+			set_audio_regs(client, decoder);
+			break;
+		}
+		return -ERANGE;
+	}
+
+	case VIDIOC_INT_S_VIDEO_ROUTING: {
+		struct v4l2_routing *route = arg;
+		int inp = route->input;
+
+		return saa717x_set_video_input(client, decoder, inp);
+	}
+
+	case VIDIOC_STREAMON: {
+		v4l_dbg(1, debug, client, "decoder enable output\n");
+		decoder->enable = 1;
+		saa717x_write(client, 0x193, 0xa6);
+		break;
+	}
+
+	case VIDIOC_STREAMOFF: {
+		v4l_dbg(1, debug, client, "decoder disable output\n");
+		decoder->enable = 0;
+		saa717x_write(client, 0x193, 0x26); /* right? FIXME!--tadachi */
+		break;
+	}
+
+		/* change audio mode */
+	case VIDIOC_S_TUNER: {
+		struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
+		int audio_mode;
+		char *mes[4] = {
+			"MONO", "STEREO", "LANG1", "LANG2/SAP"
+		};
+
+		audio_mode = V4L2_TUNER_MODE_STEREO;
+
+		switch (vt->audmode) {
+		case V4L2_TUNER_MODE_MONO:
+			audio_mode = TUNER_AUDIO_MONO;
+			break;
+		case V4L2_TUNER_MODE_STEREO:
+			audio_mode = TUNER_AUDIO_STEREO;
+			break;
+		case V4L2_TUNER_MODE_LANG2:
+			audio_mode = TUNER_AUDIO_LANG2;
+			break;
+		case V4L2_TUNER_MODE_LANG1:
+			audio_mode = TUNER_AUDIO_LANG1;
+			break;
+		}
+
+		v4l_dbg(1, debug, client, "change audio mode to %s\n",
+				mes[audio_mode]);
+		decoder->tuner_audio_mode = audio_mode;
+		/* The registers are not changed here. */
+		/* See DECODER_ENABLE_OUTPUT section. */
+		set_audio_mode(client, decoder->tuner_audio_mode);
+		break;
+	}
+
+	case VIDIOC_G_TUNER: {
+		struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
+		int dual_f, stereo_f;
+
+		if (decoder->radio)
+			break;
+		get_inf_dev_status(client, &dual_f, &stereo_f);
+
+		v4l_dbg(1, debug, client, "DETECT==st:%d dual:%d\n",
+				stereo_f, dual_f);
+
+		/* mono */
+		if ((dual_f == 0) && (stereo_f == 0)) {
+			vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+			v4l_dbg(1, debug, client, "DETECT==MONO\n");
+		}
+
+		/* stereo */
+		if (stereo_f == 1) {
+			if (vt->audmode == V4L2_TUNER_MODE_STEREO ||
+			    vt->audmode == V4L2_TUNER_MODE_LANG1) {
+				vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
+				v4l_dbg(1, debug, client, "DETECT==ST(ST)\n");
+			} else {
+				vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+				v4l_dbg(1, debug, client, "DETECT==ST(MONO)\n");
+			}
+		}
+
+		/* dual */
+		if (dual_f == 1) {
+			if (vt->audmode == V4L2_TUNER_MODE_LANG2) {
+				vt->rxsubchans = V4L2_TUNER_SUB_LANG2 | V4L2_TUNER_SUB_MONO;
+				v4l_dbg(1, debug, client, "DETECT==DUAL1\n");
+			} else {
+				vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_MONO;
+				v4l_dbg(1, debug, client, "DETECT==DUAL2\n");
+			}
+		}
+		break;
+	}
+
+	case VIDIOC_LOG_STATUS:
+		/* not yet implemented */
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+
+/* i2c implementation */
+
+/* ----------------------------------------------------------------------- */
+static int saa717x_probe(struct i2c_client *client)
+{
+	struct saa717x_state *decoder;
+	u8 id = 0;
+	char *p = "";
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	snprintf(client->name, sizeof(client->name) - 1, "saa717x");
+
+	if (saa717x_write(client, 0x5a4, 0xfe) &&
+			saa717x_write(client, 0x5a5, 0x0f) &&
+			saa717x_write(client, 0x5a6, 0x00) &&
+			saa717x_write(client, 0x5a7, 0x01))
+		id = saa717x_read(client, 0x5a0);
+	if (id != 0xc2 && id != 0x32 && id != 0xf2 && id != 0x6c) {
+		v4l_dbg(1, debug, client, "saa717x not found (id=%02x)\n", id);
+		return -ENODEV;
+	}
+	if (id == 0xc2)
+		p = "saa7173";
+	else if (id == 0x32)
+		p = "saa7174A";
+	else if (id == 0x6c)
+		p = "saa7174HL";
+	else
+		p = "saa7171";
+	v4l_info(client, "%s found @ 0x%x (%s)\n", p,
+			client->addr << 1, client->adapter->name);
+
+	decoder = kzalloc(sizeof(struct saa717x_state), GFP_KERNEL);
+	i2c_set_clientdata(client, decoder);
+
+	if (decoder == NULL)
+		return -ENOMEM;
+	decoder->std = V4L2_STD_NTSC;
+	decoder->input = -1;
+	decoder->enable = 1;
+
+	/* tune these parameters */
+	decoder->bright = 0x80;
+	decoder->contrast = 0x44;
+	decoder->sat = 0x40;
+	decoder->hue = 0x00;
+
+	/* FIXME!! */
+	decoder->playback = 0;	/* initially capture mode used */
+	decoder->audio = 1; /* DECODER_AUDIO_48_KHZ */
+
+	decoder->audio_input = 2; /* FIXME!! */
+
+	decoder->tuner_audio_mode = TUNER_AUDIO_STEREO;
+	/* set volume, bass and treble */
+	decoder->audio_main_vol_l = 6;
+	decoder->audio_main_vol_r = 6;
+	decoder->audio_main_bass = 0;
+	decoder->audio_main_treble = 0;
+	decoder->audio_main_mute = 0;
+	decoder->audio_main_balance = 32768;
+	/* normalize (24 to -40 (not -84) -> 65535 to 0) */
+	decoder->audio_main_volume =
+		(decoder->audio_main_vol_r + 41) * 65535 / (24 - (-40));
+
+	v4l_dbg(1, debug, client, "writing init values\n");
+
+	/* FIXME!! */
+	saa717x_write_regs(client, reg_init_initialize);
+	set_video_output_level_regs(client, decoder);
+	/* set bass,treble to 0db 20041101 K.Ohta */
+	decoder->audio_main_bass = 0;
+	decoder->audio_main_treble = 0;
+	set_audio_regs(client, decoder);
+
+	set_current_state(TASK_INTERRUPTIBLE);
+	schedule_timeout(2*HZ);
+	return 0;
+}
+
+static int saa717x_remove(struct i2c_client *client)
+{
+	kfree(i2c_get_clientdata(client));
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+	.name = "saa717x",
+	.driverid = I2C_DRIVERID_SAA717X,
+	.command = saa717x_command,
+	.probe = saa717x_probe,
+	.remove = saa717x_remove,
+	.legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
+};
diff --git a/drivers/media/video/saa7185.c b/drivers/media/video/saa7185.c
index 41f7044..02fda4e 100644
--- a/drivers/media/video/saa7185.c
+++ b/drivers/media/video/saa7185.c
@@ -52,7 +52,7 @@
 #define I2C_NAME(s) (s)->name
 
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
diff --git a/drivers/media/video/se401.c b/drivers/media/video/se401.c
index d5d7d6c..1cd6293 100644
--- a/drivers/media/video/se401.c
+++ b/drivers/media/video/se401.c
@@ -35,7 +35,7 @@
 #include <linux/usb.h>
 #include "se401.h"
 
-static int flickerless=0;
+static int flickerless;
 static int video_nr = -1;
 
 static struct usb_device_id device_table [] = {
@@ -300,10 +300,10 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+		dbg("%s - urb shutting down with status: %d", __func__, urb->status);
 		return;
 	default:
-		dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+		dbg("%s - nonzero urb status received: %d", __func__, urb->status);
 		goto exit;
 	}
 
@@ -315,7 +315,7 @@
 	status = usb_submit_urb (urb, GFP_ATOMIC);
 	if (status)
 		err ("%s - usb_submit_urb failed with result %d",
-		     __FUNCTION__, status);
+		     __func__, status);
 }
 
 static void se401_video_irq(struct urb *urb)
@@ -1224,7 +1224,9 @@
 	.read =         se401_read,
 	.mmap =         se401_mmap,
 	.ioctl =        se401_ioctl,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl = v4l_compat_ioctl32,
+#endif
 	.llseek =       no_llseek,
 };
 static struct video_device se401_template = {
@@ -1279,7 +1281,7 @@
 	rc=se401_sndctrl(0, se401, SE401_REQ_GET_HEIGHT, 0, cp, sizeof(cp));
 	se401->cheight=cp[0]+cp[1]*256;
 
-	if (!cp[2] && SE401_FORMAT_BAYER) {
+	if (!(cp[2] & SE401_FORMAT_BAYER)) {
 		err("Bayer format not supported!");
 		return 1;
 	}
diff --git a/drivers/media/video/sn9c102/sn9c102.h b/drivers/media/video/sn9c102/sn9c102.h
index 2e3c3de..0c8d87d 100644
--- a/drivers/media/video/sn9c102/sn9c102.h
+++ b/drivers/media/video/sn9c102/sn9c102.h
@@ -176,7 +176,7 @@
 			dev_info(&cam->usbdev->dev, fmt "\n", ## args);       \
 		else if ((level) >= 3)                                        \
 			dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",      \
-				 __FUNCTION__, __LINE__ , ## args);           \
+				 __func__, __LINE__ , ## args);           \
 	}                                                                     \
 } while (0)
 #	define V4LDBG(level, name, cmd)                                       \
@@ -191,7 +191,7 @@
 			pr_info("sn9c102: " fmt "\n", ## args);               \
 		else if ((level) == 3)                                        \
 			pr_debug("sn9c102: [%s:%d] " fmt "\n",                \
-				 __FUNCTION__, __LINE__ , ## args);           \
+				 __func__, __LINE__ , ## args);           \
 	}                                                                     \
 } while (0)
 #else
@@ -202,7 +202,7 @@
 
 #undef PDBG
 #define PDBG(fmt, args...)                                                    \
-dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__,   \
+dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __func__,   \
 	 __LINE__ , ## args)
 
 #undef PDBGG
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
index c40ba3a..5748b1e 100644
--- a/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/drivers/media/video/sn9c102/sn9c102_core.c
@@ -464,9 +464,9 @@
 }
 
 
-int
-sn9c102_i2c_try_write(struct sn9c102_device* cam,
-		      const struct sn9c102_sensor* sensor, u8 address, u8 value)
+static int sn9c102_i2c_try_write(struct sn9c102_device* cam,
+				 const struct sn9c102_sensor* sensor,
+				 u8 address, u8 value)
 {
 	return sn9c102_i2c_try_raw_write(cam, sensor, 3,
 					 sensor->i2c_slave_id, address,
@@ -528,7 +528,7 @@
 
 		/* Search for the SOF marker (fixed part) in the header */
 		for (j = 0, b=cam->sof.bytesread; j+b < sizeof(marker); j++) {
-			if (unlikely(i+j) == len)
+			if (unlikely(i+j == len))
 				return NULL;
 			if (*(m+i+j) == marker[cam->sof.bytesread]) {
 				cam->sof.header[cam->sof.bytesread] = *(m+i+j);
@@ -3224,7 +3224,9 @@
 	.open = sn9c102_open,
 	.release = sn9c102_release,
 	.ioctl = sn9c102_ioctl,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl = v4l_compat_ioctl32,
+#endif
 	.read = sn9c102_read,
 	.poll = sn9c102_poll,
 	.mmap = sn9c102_mmap,
@@ -3239,7 +3241,7 @@
 {
 	struct usb_device *udev = interface_to_usbdev(intf);
 	struct sn9c102_device* cam;
-	static unsigned int dev_nr = 0;
+	static unsigned int dev_nr;
 	unsigned int i;
 	int err = 0, r;
 
diff --git a/drivers/media/video/sn9c102/sn9c102_sensor.h b/drivers/media/video/sn9c102/sn9c102_sensor.h
index 2dc7c68..4af7382 100644
--- a/drivers/media/video/sn9c102/sn9c102_sensor.h
+++ b/drivers/media/video/sn9c102/sn9c102_sensor.h
@@ -85,9 +85,6 @@
 */
 
 /* The "try" I2C I/O versions are used when probing the sensor */
-extern int sn9c102_i2c_try_write(struct sn9c102_device*,
-				 const struct sn9c102_sensor*, u8 address,
-				 u8 value);
 extern int sn9c102_i2c_try_read(struct sn9c102_device*,
 				const struct sn9c102_sensor*, u8 address);
 
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
new file mode 100644
index 0000000..a1b9244
--- /dev/null
+++ b/drivers/media/video/soc_camera.c
@@ -0,0 +1,1031 @@
+/*
+ * camera image capture (abstract) bus driver
+ *
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * This driver provides an interface between platform-specific camera
+ * busses and camera devices. It should be used if the camera is
+ * connected not over a "proper" bus like PCI or USB, but over a
+ * special bus, like, for example, the Quick Capture interface on PXA270
+ * SoCs. Later it should also be used for i.MX31 SoCs from Freescale.
+ * It can handle multiple cameras and / or multiple busses, which can
+ * be used, e.g., in stereo-vision applications.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/vmalloc.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/soc_camera.h>
+
+static LIST_HEAD(hosts);
+static LIST_HEAD(devices);
+static DEFINE_MUTEX(list_lock);
+static DEFINE_MUTEX(video_lock);
+
+const static struct soc_camera_data_format*
+format_by_fourcc(struct soc_camera_device *icd, unsigned int fourcc)
+{
+	unsigned int i;
+
+	for (i = 0; i < icd->num_formats; i++)
+		if (icd->formats[i].fourcc == fourcc)
+			return icd->formats + i;
+	return NULL;
+}
+
+static int soc_camera_try_fmt_cap(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	struct soc_camera_file *icf = file->private_data;
+	struct soc_camera_device *icd = icf->icd;
+	struct soc_camera_host *ici =
+		to_soc_camera_host(icd->dev.parent);
+	enum v4l2_field field;
+	const struct soc_camera_data_format *fmt;
+	int ret;
+
+	WARN_ON(priv != file->private_data);
+
+	fmt = format_by_fourcc(icd, f->fmt.pix.pixelformat);
+	if (!fmt) {
+		dev_dbg(&icd->dev, "invalid format 0x%08x\n",
+			f->fmt.pix.pixelformat);
+		return -EINVAL;
+	}
+
+	dev_dbg(&icd->dev, "fmt: 0x%08x\n", fmt->fourcc);
+
+	field = f->fmt.pix.field;
+
+	if (field == V4L2_FIELD_ANY) {
+		field = V4L2_FIELD_NONE;
+	} else if (V4L2_FIELD_NONE != field) {
+		dev_err(&icd->dev, "Field type invalid.\n");
+		return -EINVAL;
+	}
+
+	/* test physical bus parameters */
+	ret = ici->ops->try_bus_param(icd, f->fmt.pix.pixelformat);
+	if (ret)
+		return ret;
+
+	/* limit format to hardware capabilities */
+	ret = ici->ops->try_fmt_cap(icd, f);
+
+	/* calculate missing fields */
+	f->fmt.pix.field = field;
+	f->fmt.pix.bytesperline =
+		(f->fmt.pix.width * fmt->depth) >> 3;
+	f->fmt.pix.sizeimage =
+		f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+	return ret;
+}
+
+static int soc_camera_enum_input(struct file *file, void *priv,
+				 struct v4l2_input *inp)
+{
+	if (inp->index != 0)
+		return -EINVAL;
+
+	inp->type = V4L2_INPUT_TYPE_CAMERA;
+	inp->std = V4L2_STD_UNKNOWN;
+	strcpy(inp->name, "Camera");
+
+	return 0;
+}
+
+static int soc_camera_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	*i = 0;
+
+	return 0;
+}
+
+static int soc_camera_s_input(struct file *file, void *priv, unsigned int i)
+{
+	if (i > 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a)
+{
+	return 0;
+}
+
+static int soc_camera_reqbufs(struct file *file, void *priv,
+			      struct v4l2_requestbuffers *p)
+{
+	int ret;
+	struct soc_camera_file *icf = file->private_data;
+	struct soc_camera_device *icd = icf->icd;
+	struct soc_camera_host *ici =
+		to_soc_camera_host(icd->dev.parent);
+
+	WARN_ON(priv != file->private_data);
+
+	dev_dbg(&icd->dev, "%s: %d\n", __func__, p->memory);
+
+	ret = videobuf_reqbufs(&icf->vb_vidq, p);
+	if (ret < 0)
+		return ret;
+
+	return ici->ops->reqbufs(icf, p);
+}
+
+static int soc_camera_querybuf(struct file *file, void *priv,
+			       struct v4l2_buffer *p)
+{
+	struct soc_camera_file *icf = file->private_data;
+
+	WARN_ON(priv != file->private_data);
+
+	return videobuf_querybuf(&icf->vb_vidq, p);
+}
+
+static int soc_camera_qbuf(struct file *file, void *priv,
+			   struct v4l2_buffer *p)
+{
+	struct soc_camera_file *icf = file->private_data;
+
+	WARN_ON(priv != file->private_data);
+
+	return videobuf_qbuf(&icf->vb_vidq, p);
+}
+
+static int soc_camera_dqbuf(struct file *file, void *priv,
+			    struct v4l2_buffer *p)
+{
+	struct soc_camera_file *icf = file->private_data;
+
+	WARN_ON(priv != file->private_data);
+
+	return videobuf_dqbuf(&icf->vb_vidq, p, file->f_flags & O_NONBLOCK);
+}
+
+static int soc_camera_open(struct inode *inode, struct file *file)
+{
+	struct video_device *vdev;
+	struct soc_camera_device *icd;
+	struct soc_camera_host *ici;
+	struct soc_camera_file *icf;
+	spinlock_t *lock;
+	int ret;
+
+	icf = vmalloc(sizeof(*icf));
+	if (!icf)
+		return -ENOMEM;
+
+	/* Protect against icd->remove() until we module_get() both drivers. */
+	mutex_lock(&video_lock);
+
+	vdev = video_devdata(file);
+	icd = container_of(vdev->dev, struct soc_camera_device, dev);
+	ici = to_soc_camera_host(icd->dev.parent);
+
+	if (!try_module_get(icd->ops->owner)) {
+		dev_err(&icd->dev, "Couldn't lock sensor driver.\n");
+		ret = -EINVAL;
+		goto emgd;
+	}
+
+	if (!try_module_get(ici->ops->owner)) {
+		dev_err(&icd->dev, "Couldn't lock capture bus driver.\n");
+		ret = -EINVAL;
+		goto emgi;
+	}
+
+	icf->icd = icd;
+
+	icf->lock = ici->ops->spinlock_alloc(icf);
+	if (!icf->lock) {
+		ret = -ENOMEM;
+		goto esla;
+	}
+
+	icd->use_count++;
+
+	/* Now we really have to activate the camera */
+	if (icd->use_count == 1) {
+		ret = ici->ops->add(icd);
+		if (ret < 0) {
+			dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret);
+			icd->use_count--;
+			goto eiciadd;
+		}
+	}
+
+	mutex_unlock(&video_lock);
+
+	file->private_data = icf;
+	dev_dbg(&icd->dev, "camera device open\n");
+
+	/* We must pass NULL as dev pointer, then all pci_* dma operations
+	 * transform to normal dma_* ones. */
+	videobuf_queue_sg_init(&icf->vb_vidq, ici->vbq_ops, NULL, icf->lock,
+				V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
+				ici->msize, icd);
+
+	return 0;
+
+	/* All errors are entered with the video_lock held */
+eiciadd:
+	lock = icf->lock;
+	icf->lock = NULL;
+	if (ici->ops->spinlock_free)
+		ici->ops->spinlock_free(lock);
+esla:
+	module_put(ici->ops->owner);
+emgi:
+	module_put(icd->ops->owner);
+emgd:
+	mutex_unlock(&video_lock);
+	vfree(icf);
+	return ret;
+}
+
+static int soc_camera_close(struct inode *inode, struct file *file)
+{
+	struct soc_camera_file *icf = file->private_data;
+	struct soc_camera_device *icd = icf->icd;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+	struct video_device *vdev = icd->vdev;
+	spinlock_t *lock = icf->lock;
+
+	mutex_lock(&video_lock);
+	icd->use_count--;
+	if (!icd->use_count)
+		ici->ops->remove(icd);
+	icf->lock = NULL;
+	if (ici->ops->spinlock_free)
+		ici->ops->spinlock_free(lock);
+	module_put(icd->ops->owner);
+	module_put(ici->ops->owner);
+	mutex_unlock(&video_lock);
+
+	vfree(icf);
+
+	dev_dbg(vdev->dev, "camera device close\n");
+
+	return 0;
+}
+
+static ssize_t soc_camera_read(struct file *file, char __user *buf,
+			   size_t count, loff_t *ppos)
+{
+	struct soc_camera_file *icf = file->private_data;
+	struct soc_camera_device *icd = icf->icd;
+	struct video_device *vdev = icd->vdev;
+	int err = -EINVAL;
+
+	dev_err(vdev->dev, "camera device read not implemented\n");
+
+	return err;
+}
+
+static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct soc_camera_file *icf = file->private_data;
+	struct soc_camera_device *icd = icf->icd;
+	int err;
+
+	dev_dbg(&icd->dev, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
+
+	err = videobuf_mmap_mapper(&icf->vb_vidq, vma);
+
+	dev_dbg(&icd->dev, "vma start=0x%08lx, size=%ld, ret=%d\n",
+		(unsigned long)vma->vm_start,
+		(unsigned long)vma->vm_end - (unsigned long)vma->vm_start,
+		err);
+
+	return err;
+}
+
+static unsigned int soc_camera_poll(struct file *file, poll_table *pt)
+{
+	struct soc_camera_file *icf = file->private_data;
+	struct soc_camera_device *icd = icf->icd;
+	struct soc_camera_host *ici =
+		to_soc_camera_host(icd->dev.parent);
+
+	if (list_empty(&icf->vb_vidq.stream)) {
+		dev_err(&icd->dev, "Trying to poll with no queued buffers!\n");
+		return POLLERR;
+	}
+
+	return ici->ops->poll(file, pt);
+}
+
+
+static struct file_operations soc_camera_fops = {
+	.owner		= THIS_MODULE,
+	.open		= soc_camera_open,
+	.release	= soc_camera_close,
+	.ioctl		= video_ioctl2,
+	.read		= soc_camera_read,
+	.mmap		= soc_camera_mmap,
+	.poll		= soc_camera_poll,
+	.llseek		= no_llseek,
+};
+
+
+static int soc_camera_s_fmt_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct soc_camera_file *icf = file->private_data;
+	struct soc_camera_device *icd = icf->icd;
+	struct soc_camera_host *ici =
+		to_soc_camera_host(icd->dev.parent);
+	int ret;
+	struct v4l2_rect rect;
+	const static struct soc_camera_data_format *data_fmt;
+
+	WARN_ON(priv != file->private_data);
+
+	data_fmt = format_by_fourcc(icd, f->fmt.pix.pixelformat);
+	if (!data_fmt)
+		return -EINVAL;
+
+	/* buswidth may be further adjusted by the ici */
+	icd->buswidth = data_fmt->depth;
+
+	ret = soc_camera_try_fmt_cap(file, icf, f);
+	if (ret < 0)
+		return ret;
+
+	rect.left	= icd->x_current;
+	rect.top	= icd->y_current;
+	rect.width	= f->fmt.pix.width;
+	rect.height	= f->fmt.pix.height;
+	ret = ici->ops->set_fmt_cap(icd, f->fmt.pix.pixelformat, &rect);
+	if (ret < 0)
+		return ret;
+
+	icd->current_fmt	= data_fmt;
+	icd->width		= rect.width;
+	icd->height		= rect.height;
+	icf->vb_vidq.field	= f->fmt.pix.field;
+	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != f->type)
+		dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n",
+			 f->type);
+
+	dev_dbg(&icd->dev, "set width: %d height: %d\n",
+		icd->width, icd->height);
+
+	/* set physical bus parameters */
+	return ici->ops->set_bus_param(icd, f->fmt.pix.pixelformat);
+}
+
+static int soc_camera_enum_fmt_cap(struct file *file, void  *priv,
+				   struct v4l2_fmtdesc *f)
+{
+	struct soc_camera_file *icf = file->private_data;
+	struct soc_camera_device *icd = icf->icd;
+	const struct soc_camera_data_format *format;
+
+	WARN_ON(priv != file->private_data);
+
+	if (f->index >= icd->num_formats)
+		return -EINVAL;
+
+	format = &icd->formats[f->index];
+
+	strlcpy(f->description, format->name, sizeof(f->description));
+	f->pixelformat = format->fourcc;
+	return 0;
+}
+
+static int soc_camera_g_fmt_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct soc_camera_file *icf = file->private_data;
+	struct soc_camera_device *icd = icf->icd;
+
+	WARN_ON(priv != file->private_data);
+
+	f->fmt.pix.width	= icd->width;
+	f->fmt.pix.height	= icd->height;
+	f->fmt.pix.field	= icf->vb_vidq.field;
+	f->fmt.pix.pixelformat	= icd->current_fmt->fourcc;
+	f->fmt.pix.bytesperline	=
+		(f->fmt.pix.width * icd->current_fmt->depth) >> 3;
+	f->fmt.pix.sizeimage	=
+		f->fmt.pix.height * f->fmt.pix.bytesperline;
+	dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n",
+		icd->current_fmt->fourcc);
+	return 0;
+}
+
+static int soc_camera_querycap(struct file *file, void  *priv,
+			       struct v4l2_capability *cap)
+{
+	struct soc_camera_file *icf = file->private_data;
+	struct soc_camera_device *icd = icf->icd;
+	struct soc_camera_host *ici =
+		to_soc_camera_host(icd->dev.parent);
+
+	WARN_ON(priv != file->private_data);
+
+	strlcpy(cap->driver, ici->drv_name, sizeof(cap->driver));
+	return ici->ops->querycap(ici, cap);
+}
+
+static int soc_camera_streamon(struct file *file, void *priv,
+			       enum v4l2_buf_type i)
+{
+	struct soc_camera_file *icf = file->private_data;
+	struct soc_camera_device *icd = icf->icd;
+
+	WARN_ON(priv != file->private_data);
+
+	dev_dbg(&icd->dev, "%s\n", __func__);
+
+	if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	icd->ops->start_capture(icd);
+
+	/* This calls buf_queue from host driver's videobuf_queue_ops */
+	return videobuf_streamon(&icf->vb_vidq);
+}
+
+static int soc_camera_streamoff(struct file *file, void *priv,
+				enum v4l2_buf_type i)
+{
+	struct soc_camera_file *icf = file->private_data;
+	struct soc_camera_device *icd = icf->icd;
+
+	WARN_ON(priv != file->private_data);
+
+	dev_dbg(&icd->dev, "%s\n", __func__);
+
+	if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	/* This calls buf_release from host driver's videobuf_queue_ops for all
+	 * remaining buffers. When the last buffer is freed, stop capture */
+	videobuf_streamoff(&icf->vb_vidq);
+
+	icd->ops->stop_capture(icd);
+
+	return 0;
+}
+
+static int soc_camera_queryctrl(struct file *file, void *priv,
+				struct v4l2_queryctrl *qc)
+{
+	struct soc_camera_file *icf = file->private_data;
+	struct soc_camera_device *icd = icf->icd;
+	int i;
+
+	WARN_ON(priv != file->private_data);
+
+	if (!qc->id)
+		return -EINVAL;
+
+	for (i = 0; i < icd->ops->num_controls; i++)
+		if (qc->id == icd->ops->controls[i].id) {
+			memcpy(qc, &(icd->ops->controls[i]),
+				sizeof(*qc));
+			return 0;
+		}
+
+	return -EINVAL;
+}
+
+static int soc_camera_g_ctrl(struct file *file, void *priv,
+			     struct v4l2_control *ctrl)
+{
+	struct soc_camera_file *icf = file->private_data;
+	struct soc_camera_device *icd = icf->icd;
+
+	WARN_ON(priv != file->private_data);
+
+	switch (ctrl->id) {
+	case V4L2_CID_GAIN:
+		if (icd->gain == (unsigned short)~0)
+			return -EINVAL;
+		ctrl->value = icd->gain;
+		return 0;
+	case V4L2_CID_EXPOSURE:
+		if (icd->exposure == (unsigned short)~0)
+			return -EINVAL;
+		ctrl->value = icd->exposure;
+		return 0;
+	}
+
+	if (icd->ops->get_control)
+		return icd->ops->get_control(icd, ctrl);
+	return -EINVAL;
+}
+
+static int soc_camera_s_ctrl(struct file *file, void *priv,
+			     struct v4l2_control *ctrl)
+{
+	struct soc_camera_file *icf = file->private_data;
+	struct soc_camera_device *icd = icf->icd;
+
+	WARN_ON(priv != file->private_data);
+
+	if (icd->ops->set_control)
+		return icd->ops->set_control(icd, ctrl);
+	return -EINVAL;
+}
+
+static int soc_camera_cropcap(struct file *file, void *fh,
+			      struct v4l2_cropcap *a)
+{
+	struct soc_camera_file *icf = file->private_data;
+	struct soc_camera_device *icd = icf->icd;
+
+	a->type				= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	a->bounds.left			= icd->x_min;
+	a->bounds.top			= icd->y_min;
+	a->bounds.width			= icd->width_max;
+	a->bounds.height		= icd->height_max;
+	a->defrect.left			= icd->x_min;
+	a->defrect.top			= icd->y_min;
+	a->defrect.width		= 640;
+	a->defrect.height		= 480;
+	a->pixelaspect.numerator	= 1;
+	a->pixelaspect.denominator	= 1;
+
+	return 0;
+}
+
+static int soc_camera_g_crop(struct file *file, void *fh,
+			     struct v4l2_crop *a)
+{
+	struct soc_camera_file *icf = file->private_data;
+	struct soc_camera_device *icd = icf->icd;
+
+	a->type		= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	a->c.left	= icd->x_current;
+	a->c.top	= icd->y_current;
+	a->c.width	= icd->width;
+	a->c.height	= icd->height;
+
+	return 0;
+}
+
+static int soc_camera_s_crop(struct file *file, void *fh,
+			     struct v4l2_crop *a)
+{
+	struct soc_camera_file *icf = file->private_data;
+	struct soc_camera_device *icd = icf->icd;
+	struct soc_camera_host *ici =
+		to_soc_camera_host(icd->dev.parent);
+	int ret;
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	ret = ici->ops->set_fmt_cap(icd, 0, &a->c);
+	if (!ret) {
+		icd->width	= a->c.width;
+		icd->height	= a->c.height;
+		icd->x_current	= a->c.left;
+		icd->y_current	= a->c.top;
+	}
+
+	return ret;
+}
+
+static int soc_camera_g_chip_ident(struct file *file, void *fh,
+				   struct v4l2_chip_ident *id)
+{
+	struct soc_camera_file *icf = file->private_data;
+	struct soc_camera_device *icd = icf->icd;
+
+	if (!icd->ops->get_chip_id)
+		return -EINVAL;
+
+	return icd->ops->get_chip_id(icd, id);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int soc_camera_g_register(struct file *file, void *fh,
+				 struct v4l2_register *reg)
+{
+	struct soc_camera_file *icf = file->private_data;
+	struct soc_camera_device *icd = icf->icd;
+
+	if (!icd->ops->get_register)
+		return -EINVAL;
+
+	return icd->ops->get_register(icd, reg);
+}
+
+static int soc_camera_s_register(struct file *file, void *fh,
+				 struct v4l2_register *reg)
+{
+	struct soc_camera_file *icf = file->private_data;
+	struct soc_camera_device *icd = icf->icd;
+
+	if (!icd->ops->set_register)
+		return -EINVAL;
+
+	return icd->ops->set_register(icd, reg);
+}
+#endif
+
+static int device_register_link(struct soc_camera_device *icd)
+{
+	int ret = device_register(&icd->dev);
+
+	if (ret < 0) {
+		/* Prevent calling device_unregister() */
+		icd->dev.parent = NULL;
+		dev_err(&icd->dev, "Cannot register device: %d\n", ret);
+	/* Even if probe() was unsuccessful for all registered drivers,
+	 * device_register() returns 0, and we add the link, just to
+	 * document this camera's control device */
+	} else if (icd->control)
+		/* Have to sysfs_remove_link() before device_unregister()? */
+		if (sysfs_create_link(&icd->dev.kobj, &icd->control->kobj,
+				      "control"))
+			dev_warn(&icd->dev,
+				 "Failed creating the control symlink\n");
+	return ret;
+}
+
+/* So far this function cannot fail */
+static void scan_add_host(struct soc_camera_host *ici)
+{
+	struct soc_camera_device *icd;
+
+	mutex_lock(&list_lock);
+
+	list_for_each_entry(icd, &devices, list) {
+		if (icd->iface == ici->nr) {
+			icd->dev.parent = &ici->dev;
+			device_register_link(icd);
+		}
+	}
+
+	mutex_unlock(&list_lock);
+}
+
+/* return: 0 if no match found or a match found and
+ * device_register() successful, error code otherwise */
+static int scan_add_device(struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici;
+	int ret = 0;
+
+	mutex_lock(&list_lock);
+
+	list_add_tail(&icd->list, &devices);
+
+	/* Watch out for class_for_each_device / class_find_device API by
+	 * Dave Young <hidave.darkstar@gmail.com> */
+	list_for_each_entry(ici, &hosts, list) {
+		if (icd->iface == ici->nr) {
+			ret = 1;
+			icd->dev.parent = &ici->dev;
+			break;
+		}
+	}
+
+	mutex_unlock(&list_lock);
+
+	if (ret)
+		ret = device_register_link(icd);
+
+	return ret;
+}
+
+static int soc_camera_probe(struct device *dev)
+{
+	struct soc_camera_device *icd = to_soc_camera_dev(dev);
+	struct soc_camera_host *ici =
+		to_soc_camera_host(icd->dev.parent);
+	int ret;
+
+	if (!icd->ops->probe)
+		return -ENODEV;
+
+	/* We only call ->add() here to activate and probe the camera.
+	 * We shall ->remove() and deactivate it immediately afterwards. */
+	ret = ici->ops->add(icd);
+	if (ret < 0)
+		return ret;
+
+	ret = icd->ops->probe(icd);
+	if (ret >= 0) {
+		const struct v4l2_queryctrl *qctrl;
+
+		qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_GAIN);
+		icd->gain = qctrl ? qctrl->default_value : (unsigned short)~0;
+		qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
+		icd->exposure = qctrl ? qctrl->default_value :
+			(unsigned short)~0;
+	}
+	ici->ops->remove(icd);
+
+	return ret;
+}
+
+/* This is called on device_unregister, which only means we have to disconnect
+ * from the host, but not remove ourselves from the device list */
+static int soc_camera_remove(struct device *dev)
+{
+	struct soc_camera_device *icd = to_soc_camera_dev(dev);
+
+	if (icd->ops->remove)
+		icd->ops->remove(icd);
+
+	return 0;
+}
+
+static struct bus_type soc_camera_bus_type = {
+	.name		= "soc-camera",
+	.probe		= soc_camera_probe,
+	.remove		= soc_camera_remove,
+};
+
+static struct device_driver ic_drv = {
+	.name	= "camera",
+	.bus	= &soc_camera_bus_type,
+	.owner	= THIS_MODULE,
+};
+
+/*
+ * Image capture host - this is a host device, not a bus device, so,
+ * no bus reference, no probing.
+ */
+static struct class soc_camera_host_class = {
+	.owner		= THIS_MODULE,
+	.name		= "camera_host",
+};
+
+static void dummy_release(struct device *dev)
+{
+}
+
+static spinlock_t *spinlock_alloc(struct soc_camera_file *icf)
+{
+	spinlock_t *lock = kmalloc(sizeof(spinlock_t), GFP_KERNEL);
+
+	if (lock)
+		spin_lock_init(lock);
+
+	return lock;
+}
+
+static void spinlock_free(spinlock_t *lock)
+{
+	kfree(lock);
+}
+
+int soc_camera_host_register(struct soc_camera_host *ici)
+{
+	int ret;
+	struct soc_camera_host *ix;
+
+	if (!ici->vbq_ops || !ici->ops->add || !ici->ops->remove)
+		return -EINVAL;
+
+	/* Number might be equal to the platform device ID */
+	sprintf(ici->dev.bus_id, "camera_host%d", ici->nr);
+	ici->dev.class = &soc_camera_host_class;
+
+	mutex_lock(&list_lock);
+	list_for_each_entry(ix, &hosts, list) {
+		if (ix->nr == ici->nr) {
+			mutex_unlock(&list_lock);
+			return -EBUSY;
+		}
+	}
+
+	list_add_tail(&ici->list, &hosts);
+	mutex_unlock(&list_lock);
+
+	ici->dev.release = dummy_release;
+
+	ret = device_register(&ici->dev);
+
+	if (ret)
+		goto edevr;
+
+	if (!ici->ops->spinlock_alloc) {
+		ici->ops->spinlock_alloc = spinlock_alloc;
+		ici->ops->spinlock_free = spinlock_free;
+	}
+
+	scan_add_host(ici);
+
+	return 0;
+
+edevr:
+	mutex_lock(&list_lock);
+	list_del(&ici->list);
+	mutex_unlock(&list_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(soc_camera_host_register);
+
+/* Unregister all clients! */
+void soc_camera_host_unregister(struct soc_camera_host *ici)
+{
+	struct soc_camera_device *icd;
+
+	mutex_lock(&list_lock);
+
+	list_del(&ici->list);
+
+	list_for_each_entry(icd, &devices, list) {
+		if (icd->dev.parent == &ici->dev) {
+			device_unregister(&icd->dev);
+			/* Not before device_unregister(), .remove
+			 * needs parent to call ici->ops->remove() */
+			icd->dev.parent = NULL;
+			memset(&icd->dev.kobj, 0, sizeof(icd->dev.kobj));
+		}
+	}
+
+	mutex_unlock(&list_lock);
+
+	device_unregister(&ici->dev);
+}
+EXPORT_SYMBOL(soc_camera_host_unregister);
+
+/* Image capture device */
+int soc_camera_device_register(struct soc_camera_device *icd)
+{
+	struct soc_camera_device *ix;
+	int num = -1, i;
+
+	if (!icd)
+		return -EINVAL;
+
+	for (i = 0; i < 256 && num < 0; i++) {
+		num = i;
+		list_for_each_entry(ix, &devices, list) {
+			if (ix->iface == icd->iface && ix->devnum == i) {
+				num = -1;
+				break;
+			}
+		}
+	}
+
+	if (num < 0)
+		/* ok, we have 256 cameras on this host...
+		 * man, stay reasonable... */
+		return -ENOMEM;
+
+	icd->devnum = num;
+	icd->dev.bus = &soc_camera_bus_type;
+	snprintf(icd->dev.bus_id, sizeof(icd->dev.bus_id),
+		 "%u-%u", icd->iface, icd->devnum);
+
+	icd->dev.release = dummy_release;
+
+	return scan_add_device(icd);
+}
+EXPORT_SYMBOL(soc_camera_device_register);
+
+void soc_camera_device_unregister(struct soc_camera_device *icd)
+{
+	mutex_lock(&list_lock);
+	list_del(&icd->list);
+
+	/* The bus->remove will be eventually called */
+	if (icd->dev.parent)
+		device_unregister(&icd->dev);
+	mutex_unlock(&list_lock);
+}
+EXPORT_SYMBOL(soc_camera_device_unregister);
+
+int soc_camera_video_start(struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+	int err = -ENOMEM;
+	struct video_device *vdev;
+
+	if (!icd->dev.parent)
+		return -ENODEV;
+
+	vdev = video_device_alloc();
+	if (!vdev)
+		goto evidallocd;
+	dev_dbg(&ici->dev, "Allocated video_device %p\n", vdev);
+
+	strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name));
+	/* Maybe better &ici->dev */
+	vdev->dev		= &icd->dev;
+	vdev->type		= VID_TYPE_CAPTURE;
+	vdev->current_norm	= V4L2_STD_UNKNOWN;
+	vdev->fops		= &soc_camera_fops;
+	vdev->release		= video_device_release;
+	vdev->minor		= -1;
+	vdev->tvnorms		= V4L2_STD_UNKNOWN,
+	vdev->vidioc_querycap	= soc_camera_querycap;
+	vdev->vidioc_g_fmt_cap	= soc_camera_g_fmt_cap;
+	vdev->vidioc_enum_fmt_cap = soc_camera_enum_fmt_cap;
+	vdev->vidioc_s_fmt_cap	= soc_camera_s_fmt_cap;
+	vdev->vidioc_enum_input	= soc_camera_enum_input;
+	vdev->vidioc_g_input	= soc_camera_g_input;
+	vdev->vidioc_s_input	= soc_camera_s_input;
+	vdev->vidioc_s_std	= soc_camera_s_std;
+	vdev->vidioc_reqbufs	= soc_camera_reqbufs;
+	vdev->vidioc_try_fmt_cap = soc_camera_try_fmt_cap;
+	vdev->vidioc_querybuf	= soc_camera_querybuf;
+	vdev->vidioc_qbuf	= soc_camera_qbuf;
+	vdev->vidioc_dqbuf	= soc_camera_dqbuf;
+	vdev->vidioc_streamon	= soc_camera_streamon;
+	vdev->vidioc_streamoff	= soc_camera_streamoff;
+	vdev->vidioc_queryctrl	= soc_camera_queryctrl;
+	vdev->vidioc_g_ctrl	= soc_camera_g_ctrl;
+	vdev->vidioc_s_ctrl	= soc_camera_s_ctrl;
+	vdev->vidioc_cropcap	= soc_camera_cropcap;
+	vdev->vidioc_g_crop	= soc_camera_g_crop;
+	vdev->vidioc_s_crop	= soc_camera_s_crop;
+	vdev->vidioc_g_chip_ident = soc_camera_g_chip_ident;
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	vdev->vidioc_g_register	= soc_camera_g_register;
+	vdev->vidioc_s_register	= soc_camera_s_register;
+#endif
+
+	icd->current_fmt = &icd->formats[0];
+
+	err = video_register_device(vdev, VFL_TYPE_GRABBER, vdev->minor);
+	if (err < 0) {
+		dev_err(vdev->dev, "video_register_device failed\n");
+		goto evidregd;
+	}
+	icd->vdev = vdev;
+
+	return 0;
+
+evidregd:
+	video_device_release(vdev);
+evidallocd:
+	return err;
+}
+EXPORT_SYMBOL(soc_camera_video_start);
+
+void soc_camera_video_stop(struct soc_camera_device *icd)
+{
+	struct video_device *vdev = icd->vdev;
+
+	dev_dbg(&icd->dev, "%s\n", __func__);
+
+	if (!icd->dev.parent || !vdev)
+		return;
+
+	mutex_lock(&video_lock);
+	video_unregister_device(vdev);
+	icd->vdev = NULL;
+	mutex_unlock(&video_lock);
+}
+EXPORT_SYMBOL(soc_camera_video_stop);
+
+static int __init soc_camera_init(void)
+{
+	int ret = bus_register(&soc_camera_bus_type);
+	if (ret)
+		return ret;
+	ret = driver_register(&ic_drv);
+	if (ret)
+		goto edrvr;
+	ret = class_register(&soc_camera_host_class);
+	if (ret)
+		goto eclr;
+
+	return 0;
+
+eclr:
+	driver_unregister(&ic_drv);
+edrvr:
+	bus_unregister(&soc_camera_bus_type);
+	return ret;
+}
+
+static void __exit soc_camera_exit(void)
+{
+	class_unregister(&soc_camera_host_class);
+	driver_unregister(&ic_drv);
+	bus_unregister(&soc_camera_bus_type);
+}
+
+module_init(soc_camera_init);
+module_exit(soc_camera_exit);
+
+MODULE_DESCRIPTION("Image capture bus driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c
index ceba45a..9276ed9 100644
--- a/drivers/media/video/stk-webcam.c
+++ b/drivers/media/video/stk-webcam.c
@@ -1100,7 +1100,7 @@
 			&& i < ARRAY_SIZE(stk_sizes))
 		i++;
 	if (i == ARRAY_SIZE(stk_sizes)) {
-		STK_ERROR("Something is broken in %s\n", __FUNCTION__);
+		STK_ERROR("Something is broken in %s\n", __func__);
 		return -EFAULT;
 	}
 	/* This registers controls some timings, not sure of what. */
@@ -1465,7 +1465,7 @@
 }
 
 #ifdef CONFIG_PM
-int stk_camera_suspend(struct usb_interface *intf, pm_message_t message)
+static int stk_camera_suspend(struct usb_interface *intf, pm_message_t message)
 {
 	struct stk_camera *dev = usb_get_intfdata(intf);
 	if (is_streaming(dev)) {
@@ -1476,7 +1476,7 @@
 	return 0;
 }
 
-int stk_camera_resume(struct usb_interface *intf)
+static int stk_camera_resume(struct usb_interface *intf)
 {
 	struct stk_camera *dev = usb_get_intfdata(intf);
 	if (!is_initialised(dev))
diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c
index 3fb85af..c109511 100644
--- a/drivers/media/video/stradis.c
+++ b/drivers/media/video/stradis.c
@@ -58,7 +58,7 @@
 
 static struct saa7146 saa7146s[SAA7146_MAX];
 
-static int saa_num = 0;		/* number of SAA7146s in use */
+static int saa_num;		/* number of SAA7146s in use */
 
 static int video_nr = -1;
 module_param(video_nr, int, 0);
@@ -248,7 +248,7 @@
 			attach_inform(saa, i);
 }
 
-static int debiwait_maxwait = 0;
+static int debiwait_maxwait;
 
 static int wait_for_debi_done(struct saa7146 *saa)
 {
@@ -1906,7 +1906,9 @@
 	.open = saa_open,
 	.release = saa_release,
 	.ioctl = saa_ioctl,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl = v4l_compat_ioctl32,
+#endif
 	.read = saa_read,
 	.llseek = no_llseek,
 	.write = saa_write,
diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c
index afc32aa..d7f130b 100644
--- a/drivers/media/video/stv680.c
+++ b/drivers/media/video/stv680.c
@@ -72,15 +72,18 @@
 #include "stv680.h"
 
 static int video_nr = -1;
-static int swapRGB = 0;   /* default for auto sleect */
-static int swapRGB_on = 0; /* default to allow auto select; -1=swap never, +1= swap always */
 
-static unsigned int debug = 0;
+static int swapRGB;	/* 0 = default for auto select */
+
+/* 0 = default to allow auto select; -1 = swap never, +1 = swap always */
+static int swapRGB_on;
+
+static unsigned int debug;
 
 #define PDEBUG(level, fmt, args...) \
 	do { \
 	if (debug >= level)	\
-		info("[%s:%d] " fmt, __FUNCTION__, __LINE__ , ## args);	\
+		info("[%s:%d] " fmt, __func__, __LINE__ , ## args);	\
 	} while (0)
 
 
@@ -1391,7 +1394,9 @@
 	.read =		stv680_read,
 	.mmap =		stv680_mmap,
 	.ioctl =        stv680_ioctl,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl = v4l_compat_ioctl32,
+#endif
 	.llseek =       no_llseek,
 };
 static struct video_device stv680_template = {
diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c
index fb895f6..6943b44 100644
--- a/drivers/media/video/tcm825x.c
+++ b/drivers/media/video/tcm825x.c
@@ -906,7 +906,7 @@
 	rval = i2c_add_driver(&tcm825x_i2c_driver);
 	if (rval)
 		printk(KERN_INFO "%s: failed registering " TCM825X_NAME "\n",
-		       __FUNCTION__);
+		       __func__);
 
 	return rval;
 }
diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c
index 55bc89a..0ebb5b5 100644
--- a/drivers/media/video/tda8290.c
+++ b/drivers/media/video/tda8290.c
@@ -32,8 +32,6 @@
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
-#define PREFIX "tda8290"
-
 /* ---------------------------------------------------------------------- */
 
 struct tda8290_priv {
@@ -174,7 +172,7 @@
 	set_audio(fe, params);
 
 	if (priv->cfg.config)
-		tuner_dbg("tda827xa config is 0x%02x\n", *priv->cfg.config);
+		tuner_dbg("tda827xa config is 0x%02x\n", priv->cfg.config);
 	tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2);
 	tuner_i2c_xfer_send(&priv->i2c_props, agc_out_on, 2);
 	tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2);
@@ -365,7 +363,7 @@
 
 	set_audio(fe, params);
 
-	tuner_dbg("%s: freq = %d\n", __FUNCTION__, params->frequency);
+	tuner_dbg("%s: freq = %d\n", __func__, params->frequency);
 
 	tda8295_power(fe, 1);
 	tda8295_agc1_out(fe, 1);
@@ -444,8 +442,7 @@
 	unsigned char set_GP00_CF[] = { 0x20, 0x01 };
 	unsigned char set_GP01_CF[] = { 0x20, 0x0B };
 
-	if ((priv->cfg.config) &&
-	    ((*priv->cfg.config == 1) || (*priv->cfg.config == 2)))
+	if ((priv->cfg.config == 1) || (priv->cfg.config == 2))
 		tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2);
 	else
 		tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2);
@@ -590,8 +587,8 @@
 		else
 			priv->ver |= TDA8275A;
 
-		tda827x_attach(fe, priv->tda827x_addr,
-			       priv->i2c_props.adap, &priv->cfg);
+		tda827x_attach(fe, priv->tda827x_addr, priv->i2c_props.adap, &priv->cfg);
+		priv->cfg.switch_addr = priv->i2c_props.addr;
 	}
 	if (fe->ops.tuner_ops.init)
 		fe->ops.tuner_ops.init(fe);
@@ -616,7 +613,7 @@
 	if (tda8290_id[1] == TDA8290_ID) {
 		if (debug)
 			printk(KERN_DEBUG "%s: tda8290 detected @ %d-%04x\n",
-			       __FUNCTION__, i2c_adapter_id(i2c_props->adap),
+			       __func__, i2c_adapter_id(i2c_props->adap),
 			       i2c_props->addr);
 		return 0;
 	}
@@ -636,7 +633,7 @@
 	if (tda8295_id[1] == TDA8295_ID) {
 		if (debug)
 			printk(KERN_DEBUG "%s: tda8295 detected @ %d-%04x\n",
-			       __FUNCTION__, i2c_adapter_id(i2c_props->adap),
+			       __func__, i2c_adapter_id(i2c_props->adap),
 			       i2c_props->addr);
 		return 0;
 	}
@@ -674,6 +671,7 @@
 
 	priv->i2c_props.addr     = i2c_addr;
 	priv->i2c_props.adap     = i2c_adap;
+	priv->i2c_props.name     = "tda829x";
 	if (cfg) {
 		priv->cfg.config         = cfg->lna_cfg;
 		priv->cfg.tuner_callback = cfg->tuner_callback;
diff --git a/drivers/media/video/tda8290.h b/drivers/media/video/tda8290.h
index dc8ef31..d3bbf27 100644
--- a/drivers/media/video/tda8290.h
+++ b/drivers/media/video/tda8290.h
@@ -21,7 +21,7 @@
 #include "dvb_frontend.h"
 
 struct tda829x_config {
-	unsigned int *lna_cfg;
+	unsigned int lna_cfg;
 	int (*tuner_callback) (void *dev, int command, int arg);
 
 	unsigned int probe_tuner:1;
@@ -39,7 +39,7 @@
 #else
 static inline int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return -EINVAL;
 }
 
@@ -49,7 +49,7 @@
 						  struct tda829x_config *cfg)
 {
 	printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
-	       __FUNCTION__);
+	       __func__);
 	return NULL;
 }
 #endif
diff --git a/drivers/media/video/tda9840.c b/drivers/media/video/tda9840.c
index bdca5d2..0cee002 100644
--- a/drivers/media/video/tda9840.c
+++ b/drivers/media/video/tda9840.c
@@ -31,11 +31,11 @@
 
 #include "tda9840.h"
 
-static int debug = 0;		/* insmod parameter */
+static int debug;		/* insmod parameter */
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
 #define dprintk(args...) \
-	    do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __FUNCTION__, __LINE__); printk(args); } } while (0)
+	    do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __func__, __LINE__); printk(args); } } while (0)
 
 #define	SWITCH		0x00
 #define	LEVEL_ADJUST	0x02
diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c
index 106c93b..a0545ba 100644
--- a/drivers/media/video/tda9887.c
+++ b/drivers/media/video/tda9887.c
@@ -25,10 +25,12 @@
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
-#define PREFIX "tda9887"
+static DEFINE_MUTEX(tda9887_list_mutex);
+static LIST_HEAD(hybrid_tuner_instance_list);
 
 struct tda9887_priv {
 	struct tuner_i2c_props i2c_props;
+	struct list_head hybrid_tuner_instance_list;
 
 	unsigned char 	   data[4];
 	unsigned int       config;
@@ -644,7 +646,15 @@
 
 static void tda9887_release(struct dvb_frontend *fe)
 {
-	kfree(fe->analog_demod_priv);
+	struct tda9887_priv *priv = fe->analog_demod_priv;
+
+	mutex_lock(&tda9887_list_mutex);
+
+	if (priv)
+		hybrid_tuner_release_state(priv);
+
+	mutex_unlock(&tda9887_list_mutex);
+
 	fe->analog_demod_priv = NULL;
 }
 
@@ -665,17 +675,29 @@
 				    u8 i2c_addr)
 {
 	struct tda9887_priv *priv = NULL;
+	int instance;
 
-	priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL);
-	if (priv == NULL)
+	mutex_lock(&tda9887_list_mutex);
+
+	instance = hybrid_tuner_request_state(struct tda9887_priv, priv,
+					      hybrid_tuner_instance_list,
+					      i2c_adap, i2c_addr, "tda9887");
+	switch (instance) {
+	case 0:
+		mutex_unlock(&tda9887_list_mutex);
 		return NULL;
-	fe->analog_demod_priv = priv;
+		break;
+	case 1:
+		fe->analog_demod_priv = priv;
+		priv->mode = T_STANDBY;
+		tuner_info("tda988[5/6/7] found\n");
+		break;
+	default:
+		fe->analog_demod_priv = priv;
+		break;
+	}
 
-	priv->i2c_props.addr = i2c_addr;
-	priv->i2c_props.adap = i2c_adap;
-	priv->mode = T_STANDBY;
-
-	tuner_info("tda988[5/6/7] found\n");
+	mutex_unlock(&tda9887_list_mutex);
 
 	memcpy(&fe->ops.analog_ops, &tda9887_ops,
 	       sizeof(struct analog_demod_ops));
diff --git a/drivers/media/video/tda9887.h b/drivers/media/video/tda9887.h
index 8f873a8..be49dcb 100644
--- a/drivers/media/video/tda9887.h
+++ b/drivers/media/video/tda9887.h
@@ -30,7 +30,7 @@
 						  struct i2c_adapter *i2c_adap,
 						  u8 i2c_addr)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif
diff --git a/drivers/media/video/tea5761.c b/drivers/media/video/tea5761.c
index 5326eec..b93cdef 100644
--- a/drivers/media/video/tea5761.c
+++ b/drivers/media/video/tea5761.c
@@ -14,12 +14,10 @@
 #include "tuner-i2c.h"
 #include "tea5761.h"
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
-#define PREFIX "tea5761"
-
 struct tea5761_priv {
 	struct tuner_i2c_props i2c_props;
 
@@ -131,7 +129,7 @@
 
 	frq = 1000 * (div * 32768 / 1000 + FREQ_OFFSET + 225) / 4;	/* Freq in KHz */
 
-	printk(PREFIX "Frequency %d.%03d KHz (divider = 0x%04x)\n",
+	printk(KERN_INFO "tea5761: Frequency %d.%03d KHz (divider = 0x%04x)\n",
 	       frq / 1000, frq % 1000, div);
 }
 
@@ -249,14 +247,19 @@
 
 	if (16 != (rc = tuner_i2c_xfer_recv(&i2c, buffer, 16))) {
 		printk(KERN_WARNING "it is not a TEA5761. Received %i chars.\n", rc);
-		return EINVAL;
+		return -EINVAL;
 	}
 
-	if (!((buffer[13] != 0x2b) || (buffer[14] != 0x57) || (buffer[15] != 0x061))) {
-		printk(KERN_WARNING "Manufacturer ID= 0x%02x, Chip ID = %02x%02x. It is not a TEA5761\n",buffer[13],buffer[14],buffer[15]);
-		return EINVAL;
+	if ((buffer[13] != 0x2b) || (buffer[14] != 0x57) || (buffer[15] != 0x061)) {
+		printk(KERN_WARNING "Manufacturer ID= 0x%02x, Chip ID = %02x%02x."
+				    " It is not a TEA5761\n",
+				    buffer[13], buffer[14], buffer[15]);
+		return -EINVAL;
 	}
-	printk(KERN_WARNING "TEA5761 detected.\n");
+	printk(KERN_WARNING "tea5761: TEA%02x%02x detected. "
+			    "Manufacturer ID= 0x%02x\n",
+			    buffer[14], buffer[15], buffer[13]);
+
 	return 0;
 }
 
@@ -302,6 +305,7 @@
 
 	priv->i2c_props.addr = i2c_addr;
 	priv->i2c_props.adap = i2c_adap;
+	priv->i2c_props.name = "tea5761";
 
 	memcpy(&fe->ops.tuner_ops, &tea5761_tuner_ops,
 	       sizeof(struct dvb_tuner_ops));
diff --git a/drivers/media/video/tea5761.h b/drivers/media/video/tea5761.h
index 73a03b4..8eb6272 100644
--- a/drivers/media/video/tea5761.h
+++ b/drivers/media/video/tea5761.h
@@ -31,7 +31,7 @@
 					u8 i2c_addr)
 {
 	printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
-	       __FUNCTION__);
+	       __func__);
 	return -EINVAL;
 }
 
@@ -39,7 +39,7 @@
 						   struct i2c_adapter* i2c_adap,
 						   u8 i2c_addr)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif
diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c
index e1b48d8..f6e7d7a 100644
--- a/drivers/media/video/tea5767.c
+++ b/drivers/media/video/tea5767.c
@@ -16,12 +16,10 @@
 #include "tuner-i2c.h"
 #include "tea5767.h"
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
-#define PREFIX "tea5767"
-
 /*****************************************************************************/
 
 struct tea5767_priv {
@@ -137,14 +135,14 @@
 	unsigned int div, frq;
 
 	if (TEA5767_READY_FLAG_MASK & buffer[0])
-		printk(PREFIX "Ready Flag ON\n");
+		tuner_info("Ready Flag ON\n");
 	else
-		printk(PREFIX "Ready Flag OFF\n");
+		tuner_info("Ready Flag OFF\n");
 
 	if (TEA5767_BAND_LIMIT_MASK & buffer[0])
-		printk(PREFIX "Tuner at band limit\n");
+		tuner_info("Tuner at band limit\n");
 	else
-		printk(PREFIX "Tuner not at band limit\n");
+		tuner_info("Tuner not at band limit\n");
 
 	div = ((buffer[0] & 0x3f) << 8) | buffer[1];
 
@@ -166,23 +164,23 @@
 	buffer[0] = (div >> 8) & 0x3f;
 	buffer[1] = div & 0xff;
 
-	printk(PREFIX "Frequency %d.%03d KHz (divider = 0x%04x)\n",
-	       frq / 1000, frq % 1000, div);
+	tuner_info("Frequency %d.%03d KHz (divider = 0x%04x)\n",
+		   frq / 1000, frq % 1000, div);
 
 	if (TEA5767_STEREO_MASK & buffer[2])
-		printk(PREFIX "Stereo\n");
+		tuner_info("Stereo\n");
 	else
-		printk(PREFIX "Mono\n");
+		tuner_info("Mono\n");
 
-	printk(PREFIX "IF Counter = %d\n", buffer[2] & TEA5767_IF_CNTR_MASK);
+	tuner_info("IF Counter = %d\n", buffer[2] & TEA5767_IF_CNTR_MASK);
 
-	printk(PREFIX "ADC Level = %d\n",
-	       (buffer[3] & TEA5767_ADC_LEVEL_MASK) >> 4);
+	tuner_info("ADC Level = %d\n",
+		   (buffer[3] & TEA5767_ADC_LEVEL_MASK) >> 4);
 
-	printk(PREFIX "Chip ID = %d\n", (buffer[3] & TEA5767_CHIP_ID_MASK));
+	tuner_info("Chip ID = %d\n", (buffer[3] & TEA5767_CHIP_ID_MASK));
 
-	printk(PREFIX "Reserved = 0x%02x\n",
-	       (buffer[4] & TEA5767_RESERVED_MASK));
+	tuner_info("Reserved = 0x%02x\n",
+		   (buffer[4] & TEA5767_RESERVED_MASK));
 }
 
 /* Freq should be specifyed at 62.5 Hz */
@@ -395,11 +393,6 @@
 		return EINVAL;
 	}
 
-	/* It seems that tea5767 returns 0xff after the 5th byte */
-	if ((buffer[5] != 0xff) || (buffer[6] != 0xff)) {
-		printk(KERN_WARNING "Returned more than 5 bytes. It is not a TEA5767\n");
-		return EINVAL;
-	}
 
 	return 0;
 }
@@ -456,6 +449,8 @@
 
 	priv->i2c_props.addr  = i2c_addr;
 	priv->i2c_props.adap  = i2c_adap;
+	priv->i2c_props.name  = "tea5767";
+
 	priv->ctrl.xtal_freq  = TEA5767_HIGH_LO_32768;
 	priv->ctrl.port1      = 1;
 	priv->ctrl.port2      = 1;
diff --git a/drivers/media/video/tea5767.h b/drivers/media/video/tea5767.h
index a44451f..7b547c0 100644
--- a/drivers/media/video/tea5767.h
+++ b/drivers/media/video/tea5767.h
@@ -50,7 +50,7 @@
 					u8 i2c_addr)
 {
 	printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
-	       __FUNCTION__);
+	       __func__);
 	return -EINVAL;
 }
 
@@ -58,7 +58,7 @@
 						   struct i2c_adapter* i2c_adap,
 						   u8 i2c_addr)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif
diff --git a/drivers/media/video/tea6415c.c b/drivers/media/video/tea6415c.c
index df2fad9..9513d86 100644
--- a/drivers/media/video/tea6415c.c
+++ b/drivers/media/video/tea6415c.c
@@ -33,11 +33,11 @@
 
 #include "tea6415c.h"
 
-static int debug = 0;		/* insmod parameter */
+static int debug;		/* insmod parameter */
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
 #define dprintk(args...) \
-	    do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __FUNCTION__, __LINE__); printk(args); } } while (0)
+	    do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __func__, __LINE__); printk(args); } } while (0)
 
 #define TEA6415C_NUM_INPUTS	8
 #define TEA6415C_NUM_OUTPUTS	6
diff --git a/drivers/media/video/tea6420.c b/drivers/media/video/tea6420.c
index 4ff6c63..7fd5336 100644
--- a/drivers/media/video/tea6420.c
+++ b/drivers/media/video/tea6420.c
@@ -33,11 +33,11 @@
 
 #include "tea6420.h"
 
-static int debug = 0;		/* insmod parameter */
+static int debug;		/* insmod parameter */
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
 #define dprintk(args...) \
-	    do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __FUNCTION__, __LINE__); printk(args); } } while (0)
+	    do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __func__, __LINE__); printk(args); } } while (0)
 
 /* addresses to scan, found only at 0x4c and/or 0x4d (7-Bit) */
 static unsigned short normal_i2c[] = { I2C_ADDR_TEA6420_1, I2C_ADDR_TEA6420_2, I2C_CLIENT_END };
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 78a09a2..529e009 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -68,9 +68,9 @@
 I2C_CLIENT_INSMOD;
 
 /* insmod options used at init time => read/only */
-static unsigned int addr = 0;
-static unsigned int no_autodetect = 0;
-static unsigned int show_i2c = 0;
+static unsigned int addr;
+static unsigned int no_autodetect;
+static unsigned int show_i2c;
 
 /* insmod options used at runtime => read/write */
 static int tuner_debug;
@@ -313,24 +313,14 @@
 	tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n");
 	tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n");
 	tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n",
-		   t->i2c->adapter->name, t->i2c->addr, t->type,
-		   tuners[t->type].name);
+		   t->i2c->adapter->name, t->i2c->addr, t->type, t->i2c->name);
 	tuner_warn("====================== WARNING! ======================\n");
 }
 
-static void attach_simple_tuner(struct tuner *t)
-{
-	struct simple_tuner_config cfg = {
-		.type = t->type,
-		.tun  = &tuners[t->type]
-	};
-	simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg);
-}
-
 static void attach_tda829x(struct tuner *t)
 {
 	struct tda829x_config cfg = {
-		.lna_cfg        = &t->config,
+		.lna_cfg        = t->config,
 		.tuner_callback = t->tuner_callback,
 	};
 	tda829x_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg);
@@ -352,11 +342,6 @@
 		return;
 	}
 
-	if (type >= tuner_count) {
-		tuner_warn ("tuner 0x%02x: Tuner count greater than %d\n",c->addr,tuner_count);
-		return;
-	}
-
 	t->type = type;
 	t->config = new_config;
 	if (tuner_callback != NULL) {
@@ -409,7 +394,12 @@
 		buffer[2] = 0x86;
 		buffer[3] = 0x54;
 		i2c_master_send(c, buffer, 4);
-		attach_simple_tuner(t);
+		if (simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr,
+					t->type) == NULL) {
+			t->type = TUNER_ABSENT;
+			t->mode_mask = T_UNINITIALIZED;
+			return;
+		}
 		break;
 	case TUNER_PHILIPS_TD1316:
 		buffer[0] = 0x0b;
@@ -417,14 +407,18 @@
 		buffer[2] = 0x86;
 		buffer[3] = 0xa4;
 		i2c_master_send(c,buffer,4);
-		attach_simple_tuner(t);
+		if (simple_tuner_attach(&t->fe, t->i2c->adapter,
+					t->i2c->addr, t->type) == NULL) {
+			t->type = TUNER_ABSENT;
+			t->mode_mask = T_UNINITIALIZED;
+			return;
+		}
 		break;
 	case TUNER_XC2028:
 	{
 		struct xc2028_config cfg = {
 			.i2c_adap  = t->i2c->adapter,
 			.i2c_addr  = t->i2c->addr,
-			.video_dev = c->adapter->algo_data,
 			.callback  = t->tuner_callback,
 		};
 		if (!xc2028_attach(&t->fe, &cfg)) {
@@ -455,7 +449,12 @@
 		}
 		break;
 	default:
-		attach_simple_tuner(t);
+		if (simple_tuner_attach(&t->fe, t->i2c->adapter,
+					t->i2c->addr, t->type) == NULL) {
+			t->type = TUNER_ABSENT;
+			t->mode_mask = T_UNINITIALIZED;
+			return;
+		}
 		break;
 	}
 
@@ -759,7 +758,7 @@
 		if (analog_ops->standby)
 			analog_ops->standby(&t->fe);
 		break;
-#ifdef CONFIG_VIDEO_V4L1
+#ifdef CONFIG_VIDEO_ALLOW_V4L1
 	case VIDIOCSAUDIO:
 		if (check_mode(t, "VIDIOCSAUDIO") == EINVAL)
 			return 0;
@@ -1112,8 +1111,8 @@
 	if (!no_autodetect) {
 		switch (client->addr) {
 		case 0x10:
-			if (tea5761_autodetection(t->i2c->adapter, t->i2c->addr)
-					!= EINVAL) {
+			if (tea5761_autodetection(t->i2c->adapter,
+						  t->i2c->addr) >= 0) {
 				t->type = TUNER_TEA5761;
 				t->mode_mask = T_RADIO;
 				t->mode = T_STANDBY;
@@ -1125,7 +1124,7 @@
 
 				goto register_client;
 			}
-			break;
+			return -ENODEV;
 		case 0x42:
 		case 0x43:
 		case 0x4a:
diff --git a/drivers/media/video/tuner-i2c.h b/drivers/media/video/tuner-i2c.h
index de52e8f..3ad6c8e 100644
--- a/drivers/media/video/tuner-i2c.h
+++ b/drivers/media/video/tuner-i2c.h
@@ -26,6 +26,10 @@
 struct tuner_i2c_props {
 	u8 addr;
 	struct i2c_adapter *adap;
+
+	/* used for tuner instance management */
+	int count;
+	char *name;
 };
 
 static inline int tuner_i2c_xfer_send(struct tuner_i2c_props *props, char *buf, int len)
@@ -59,29 +63,111 @@
 	return (ret == 2) ? ilen : ret;
 }
 
-#define tuner_warn(fmt, arg...) do {					\
-	printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX,			\
-			i2c_adapter_id(priv->i2c_props.adap),		\
-			priv->i2c_props.addr, ##arg);			\
+/* Callers must declare as a global for the module:
+ *
+ * static LIST_HEAD(hybrid_tuner_instance_list);
+ *
+ * hybrid_tuner_instance_list should be the third argument
+ * passed into hybrid_tuner_request_state().
+ *
+ * state structure must contain the following:
+ *
+ * 	struct list_head	hybrid_tuner_instance_list;
+ *	struct tuner_i2c_props	i2c_props;
+ *
+ * hybrid_tuner_instance_list (both within state structure and globally)
+ * is only required if the driver is using hybrid_tuner_request_state
+ * and hybrid_tuner_release_state to manage state sharing between
+ * multiple instances of hybrid tuners.
+ */
+
+#define tuner_printk(kernlvl, i2cprops, fmt, arg...) do {		\
+	printk(kernlvl "%s %d-%04x: " fmt, i2cprops.name,		\
+			i2cprops.adap ?					\
+				i2c_adapter_id(i2cprops.adap) : -1,	\
+			i2cprops.addr, ##arg);				\
 	 } while (0)
 
-#define tuner_info(fmt, arg...) do {					\
-	printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX,			\
-			i2c_adapter_id(priv->i2c_props.adap),		\
-			priv->i2c_props.addr , ##arg);			\
+/* TO DO: convert all callers of these macros to pass in
+ * struct tuner_i2c_props, then remove the macro wrappers */
+
+#define __tuner_warn(i2cprops, fmt, arg...) do {			\
+	tuner_printk(KERN_WARNING, i2cprops, fmt, ##arg);		\
 	} while (0)
 
-#define tuner_err(fmt, arg...) do {					\
-	printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX, 			\
-			i2c_adapter_id(priv->i2c_props.adap),		\
-			priv->i2c_props.addr , ##arg);			\
+#define __tuner_info(i2cprops, fmt, arg...) do {			\
+	tuner_printk(KERN_INFO, i2cprops, fmt, ##arg);			\
 	} while (0)
 
-#define tuner_dbg(fmt, arg...) do {					\
+#define __tuner_err(i2cprops, fmt, arg...) do {				\
+	tuner_printk(KERN_ERR, i2cprops, fmt, ##arg);			\
+	} while (0)
+
+#define __tuner_dbg(i2cprops, fmt, arg...) do {				\
 	if ((debug))							\
-		printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX,		\
-			i2c_adapter_id(priv->i2c_props.adap),		\
-			priv->i2c_props.addr , ##arg);			\
+		tuner_printk(KERN_DEBUG, i2cprops, fmt, ##arg);		\
 	} while (0)
 
+#define tuner_warn(fmt, arg...) __tuner_warn(priv->i2c_props, fmt, ##arg)
+#define tuner_info(fmt, arg...) __tuner_info(priv->i2c_props, fmt, ##arg)
+#define tuner_err(fmt, arg...) __tuner_err(priv->i2c_props, fmt, ##arg)
+#define tuner_dbg(fmt, arg...) __tuner_dbg(priv->i2c_props, fmt, ##arg)
+
+/****************************************************************************/
+
+/* The return value of hybrid_tuner_request_state indicates the number of
+ * instances using this tuner object.
+ *
+ * 0 - no instances, indicates an error - kzalloc must have failed
+ *
+ * 1 - one instance, indicates that the tuner object was created successfully
+ *
+ * 2 (or more) instances, indicates that an existing tuner object was found
+ */
+
+#define hybrid_tuner_request_state(type, state, list, i2cadap, i2caddr, devname)\
+({									\
+	int __ret = 0;							\
+	list_for_each_entry(state, &list, hybrid_tuner_instance_list) {	\
+		if (((i2cadap) && (state->i2c_props.adap)) &&		\
+		    ((i2c_adapter_id(state->i2c_props.adap) ==		\
+		      i2c_adapter_id(i2cadap)) &&			\
+		     (i2caddr == state->i2c_props.addr))) {		\
+			__tuner_info(state->i2c_props,			\
+				     "attaching existing instance\n");	\
+			state->i2c_props.count++;			\
+			__ret = state->i2c_props.count;			\
+			break;						\
+		}							\
+	}								\
+	if (0 == __ret) {						\
+		state = kzalloc(sizeof(type), GFP_KERNEL);		\
+		if (NULL == state)					\
+			goto __fail;					\
+		state->i2c_props.addr = i2caddr;			\
+		state->i2c_props.adap = i2cadap;			\
+		state->i2c_props.name = devname;			\
+		__tuner_info(state->i2c_props,				\
+			     "creating new instance\n");		\
+		list_add_tail(&state->hybrid_tuner_instance_list, &list);\
+		state->i2c_props.count++;				\
+		__ret = state->i2c_props.count;				\
+	}								\
+__fail:									\
+	__ret;								\
+})
+
+#define hybrid_tuner_release_state(state)				\
+({									\
+	int __ret;							\
+	state->i2c_props.count--;					\
+	__ret = state->i2c_props.count;					\
+	if (!state->i2c_props.count) {					\
+		__tuner_info(state->i2c_props, "destroying instance\n");\
+		list_del(&state->hybrid_tuner_instance_list);		\
+		kfree(state);						\
+	}								\
+	__ret;								\
+})
+
 #endif /* __TUNER_I2C_H__ */
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
index c1db576..be8d903 100644
--- a/drivers/media/video/tuner-simple.c
+++ b/drivers/media/video/tuner-simple.c
@@ -13,15 +13,25 @@
 #include "tuner-i2c.h"
 #include "tuner-simple.h"
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
-#define PREFIX "tuner-simple"
+#define TUNER_SIMPLE_MAX 64
+static unsigned int simple_devcount;
 
-static int offset = 0;
+static int offset;
 module_param(offset, int, 0664);
-MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner");
+MODULE_PARM_DESC(offset, "Allows to specify an offset for tuner");
+
+static unsigned int atv_input[TUNER_SIMPLE_MAX] = \
+			{ [0 ... (TUNER_SIMPLE_MAX-1)] = 0 };
+static unsigned int dtv_input[TUNER_SIMPLE_MAX] = \
+			{ [0 ... (TUNER_SIMPLE_MAX-1)] = 0 };
+module_param_array(atv_input, int, NULL, 0644);
+module_param_array(dtv_input, int, NULL, 0644);
+MODULE_PARM_DESC(atv_input, "specify atv rf input, 0 for autoselect");
+MODULE_PARM_DESC(dtv_input, "specify dtv rf input, 0 for autoselect");
 
 /* ---------------------------------------------------------------------- */
 
@@ -36,8 +46,8 @@
  */
 #define TEMIC_SET_PAL_I         0x05
 #define TEMIC_SET_PAL_DK        0x09
-#define TEMIC_SET_PAL_L         0x0a // SECAM ?
-#define TEMIC_SET_PAL_L2        0x0b // change IF !
+#define TEMIC_SET_PAL_L         0x0a /* SECAM ? */
+#define TEMIC_SET_PAL_L2        0x0b /* change IF ! */
 #define TEMIC_SET_PAL_BG        0x0c
 
 /* tv tuner system standard selection for Philips FQ1216ME
@@ -90,14 +100,21 @@
 #define TUNER_PLL_LOCKED   0x40
 #define TUNER_STEREO_MK3   0x04
 
+static DEFINE_MUTEX(tuner_simple_list_mutex);
+static LIST_HEAD(hybrid_tuner_instance_list);
+
 struct tuner_simple_priv {
+	unsigned int nr;
 	u16 last_div;
+
 	struct tuner_i2c_props i2c_props;
+	struct list_head hybrid_tuner_instance_list;
 
 	unsigned int type;
 	struct tunertype *tun;
 
 	u32 frequency;
+	u32 bandwidth;
 };
 
 /* ---------------------------------------------------------------------- */
@@ -107,7 +124,7 @@
 	struct tuner_simple_priv *priv = fe->tuner_priv;
 	unsigned char byte;
 
-	if (1 != tuner_i2c_xfer_recv(&priv->i2c_props,&byte,1))
+	if (1 != tuner_i2c_xfer_recv(&priv->i2c_props, &byte, 1))
 		return 0;
 
 	return byte;
@@ -121,13 +138,13 @@
 static inline int tuner_stereo(const int type, const int status)
 {
 	switch (type) {
-		case TUNER_PHILIPS_FM1216ME_MK3:
-		case TUNER_PHILIPS_FM1236_MK3:
-		case TUNER_PHILIPS_FM1256_IH3:
-		case TUNER_LG_NTSC_TAPE:
-			return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
-		default:
-			return status & TUNER_STEREO;
+	case TUNER_PHILIPS_FM1216ME_MK3:
+	case TUNER_PHILIPS_FM1236_MK3:
+	case TUNER_PHILIPS_FM1256_IH3:
+	case TUNER_LG_NTSC_TAPE:
+		return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
+	default:
+		return status & TUNER_STEREO;
 	}
 }
 
@@ -145,7 +162,12 @@
 static int simple_get_status(struct dvb_frontend *fe, u32 *status)
 {
 	struct tuner_simple_priv *priv = fe->tuner_priv;
-	int tuner_status = tuner_read_status(fe);
+	int tuner_status;
+
+	if (priv->i2c_props.adap == NULL)
+		return -EINVAL;
+
+	tuner_status = tuner_read_status(fe);
 
 	*status = 0;
 
@@ -162,7 +184,12 @@
 static int simple_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
 {
 	struct tuner_simple_priv *priv = fe->tuner_priv;
-	int signal = tuner_signal(tuner_read_status(fe));
+	int signal;
+
+	if (priv->i2c_props.adap == NULL)
+		return -EINVAL;
+
+	signal = tuner_signal(tuner_read_status(fe));
 
 	*strength = signal;
 
@@ -173,15 +200,331 @@
 
 /* ---------------------------------------------------------------------- */
 
+static inline char *tuner_param_name(enum param_type type)
+{
+	char *name;
+
+	switch (type) {
+	case TUNER_PARAM_TYPE_RADIO:
+		name = "radio";
+		break;
+	case TUNER_PARAM_TYPE_PAL:
+		name = "pal";
+		break;
+	case TUNER_PARAM_TYPE_SECAM:
+		name = "secam";
+		break;
+	case TUNER_PARAM_TYPE_NTSC:
+		name = "ntsc";
+		break;
+	case TUNER_PARAM_TYPE_DIGITAL:
+		name = "digital";
+		break;
+	default:
+		name = "unknown";
+		break;
+	}
+	return name;
+}
+
+static struct tuner_params *simple_tuner_params(struct dvb_frontend *fe,
+						enum param_type desired_type)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+	struct tunertype *tun = priv->tun;
+	int i;
+
+	for (i = 0; i < tun->count; i++)
+		if (desired_type == tun->params[i].type)
+			break;
+
+	/* use default tuner params if desired_type not available */
+	if (i == tun->count) {
+		tuner_dbg("desired params (%s) undefined for tuner %d\n",
+			  tuner_param_name(desired_type), priv->type);
+		i = 0;
+	}
+
+	tuner_dbg("using tuner params #%d (%s)\n", i,
+		  tuner_param_name(tun->params[i].type));
+
+	return &tun->params[i];
+}
+
+static int simple_config_lookup(struct dvb_frontend *fe,
+				struct tuner_params *t_params,
+				int *frequency, u8 *config, u8 *cb)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+	int i;
+
+	for (i = 0; i < t_params->count; i++) {
+		if (*frequency > t_params->ranges[i].limit)
+			continue;
+		break;
+	}
+	if (i == t_params->count) {
+		tuner_dbg("frequency out of range (%d > %d)\n",
+			  *frequency, t_params->ranges[i - 1].limit);
+		*frequency = t_params->ranges[--i].limit;
+	}
+	*config = t_params->ranges[i].config;
+	*cb     = t_params->ranges[i].cb;
+
+	tuner_dbg("freq = %d.%02d (%d), range = %d, "
+		  "config = 0x%02x, cb = 0x%02x\n",
+		  *frequency / 16, *frequency % 16 * 100 / 16, *frequency,
+		  i, *config, *cb);
+
+	return i;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void simple_set_rf_input(struct dvb_frontend *fe,
+				u8 *config, u8 *cb, unsigned int rf)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+
+	switch (priv->type) {
+	case TUNER_PHILIPS_TUV1236D:
+		switch (rf) {
+		case 1:
+			*cb |= 0x08;
+			break;
+		default:
+			*cb &= ~0x08;
+			break;
+		}
+		break;
+	case TUNER_PHILIPS_FCV1236D:
+		switch (rf) {
+		case 1:
+			*cb |= 0x01;
+			break;
+		default:
+			*cb &= ~0x01;
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+static int simple_std_setup(struct dvb_frontend *fe,
+			    struct analog_parameters *params,
+			    u8 *config, u8 *cb)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+	u8 tuneraddr;
+	int rc;
+
+	/* tv norm specific stuff for multi-norm tuners */
+	switch (priv->type) {
+	case TUNER_PHILIPS_SECAM: /* FI1216MF */
+		/* 0x01 -> ??? no change ??? */
+		/* 0x02 -> PAL BDGHI / SECAM L */
+		/* 0x04 -> ??? PAL others / SECAM others ??? */
+		*cb &= ~0x03;
+		if (params->std & V4L2_STD_SECAM_L)
+			/* also valid for V4L2_STD_SECAM */
+			*cb |= PHILIPS_MF_SET_STD_L;
+		else if (params->std & V4L2_STD_SECAM_LC)
+			*cb |= PHILIPS_MF_SET_STD_LC;
+		else /* V4L2_STD_B|V4L2_STD_GH */
+			*cb |= PHILIPS_MF_SET_STD_BG;
+		break;
+
+	case TUNER_TEMIC_4046FM5:
+		*cb &= ~0x0f;
+
+		if (params->std & V4L2_STD_PAL_BG) {
+			*cb |= TEMIC_SET_PAL_BG;
+
+		} else if (params->std & V4L2_STD_PAL_I) {
+			*cb |= TEMIC_SET_PAL_I;
+
+		} else if (params->std & V4L2_STD_PAL_DK) {
+			*cb |= TEMIC_SET_PAL_DK;
+
+		} else if (params->std & V4L2_STD_SECAM_L) {
+			*cb |= TEMIC_SET_PAL_L;
+
+		}
+		break;
+
+	case TUNER_PHILIPS_FQ1216ME:
+		*cb &= ~0x0f;
+
+		if (params->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) {
+			*cb |= PHILIPS_SET_PAL_BGDK;
+
+		} else if (params->std & V4L2_STD_PAL_I) {
+			*cb |= PHILIPS_SET_PAL_I;
+
+		} else if (params->std & V4L2_STD_SECAM_L) {
+			*cb |= PHILIPS_SET_PAL_L;
+
+		}
+		break;
+
+	case TUNER_PHILIPS_FCV1236D:
+		/* 0x00 -> ATSC antenna input 1 */
+		/* 0x01 -> ATSC antenna input 2 */
+		/* 0x02 -> NTSC antenna input 1 */
+		/* 0x03 -> NTSC antenna input 2 */
+		*cb &= ~0x03;
+		if (!(params->std & V4L2_STD_ATSC))
+			*cb |= 2;
+		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 */
+		u8 buffer[4] = { 0x14, 0x00, 0x17, 0x00};
+		*cb &= ~0x40;
+		if (params->std & V4L2_STD_ATSC) {
+			*cb |= 0x40;
+			buffer[1] = 0x04;
+		}
+		/* set to the correct mode (analog or digital) */
+		tuneraddr = priv->i2c_props.addr;
+		priv->i2c_props.addr = 0x0a;
+		rc = tuner_i2c_xfer_send(&priv->i2c_props, &buffer[0], 2);
+		if (2 != rc)
+			tuner_warn("i2c i/o error: rc == %d "
+				   "(should be 2)\n", rc);
+		rc = tuner_i2c_xfer_send(&priv->i2c_props, &buffer[2], 2);
+		if (2 != rc)
+			tuner_warn("i2c i/o error: rc == %d "
+				   "(should be 2)\n", rc);
+		priv->i2c_props.addr = tuneraddr;
+		break;
+	}
+	}
+	if (atv_input[priv->nr])
+		simple_set_rf_input(fe, config, cb, atv_input[priv->nr]);
+
+	return 0;
+}
+
+static int simple_post_tune(struct dvb_frontend *fe, u8 *buffer,
+			    u16 div, u8 config, u8 cb)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+	int rc;
+
+	switch (priv->type) {
+	case TUNER_LG_TDVS_H06XF:
+		/* Set the Auxiliary Byte. */
+		buffer[0] = buffer[2];
+		buffer[0] &= ~0x20;
+		buffer[0] |= 0x18;
+		buffer[1] = 0x20;
+		tuner_dbg("tv 0x%02x 0x%02x\n", buffer[0], buffer[1]);
+
+		rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 2);
+		if (2 != rc)
+			tuner_warn("i2c i/o error: rc == %d "
+				   "(should be 2)\n", rc);
+		break;
+	case TUNER_MICROTUNE_4042FI5:
+	{
+		/* FIXME - this may also work for other tuners */
+		unsigned long timeout = jiffies + msecs_to_jiffies(1);
+		u8 status_byte = 0;
+
+		/* Wait until the PLL locks */
+		for (;;) {
+			if (time_after(jiffies, timeout))
+				return 0;
+			rc = tuner_i2c_xfer_recv(&priv->i2c_props,
+						 &status_byte, 1);
+			if (1 != rc) {
+				tuner_warn("i2c i/o read error: rc == %d "
+					   "(should be 1)\n", rc);
+				break;
+			}
+			if (status_byte & TUNER_PLL_LOCKED)
+				break;
+			udelay(10);
+		}
+
+		/* Set the charge pump for optimized phase noise figure */
+		config &= ~TUNER_CHARGE_PUMP;
+		buffer[0] = (div>>8) & 0x7f;
+		buffer[1] = div      & 0xff;
+		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]);
+
+		rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
+		if (4 != rc)
+			tuner_warn("i2c i/o error: rc == %d "
+				   "(should be 4)\n", rc);
+		break;
+	}
+	}
+
+	return 0;
+}
+
+static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+
+	switch (priv->type) {
+	case TUNER_TENA_9533_DI:
+	case TUNER_YMEC_TVF_5533MF:
+		tuner_dbg("This tuner doesn't have FM. "
+			  "Most cards have a TEA5767 for FM\n");
+		return 0;
+	case TUNER_PHILIPS_FM1216ME_MK3:
+	case TUNER_PHILIPS_FM1236_MK3:
+	case TUNER_PHILIPS_FMD1216ME_MK3:
+	case TUNER_LG_NTSC_TAPE:
+	case TUNER_PHILIPS_FM1256_IH3:
+		buffer[3] = 0x19;
+		break;
+	case TUNER_TNF_5335MF:
+		buffer[3] = 0x11;
+		break;
+	case TUNER_LG_PAL_FM:
+		buffer[3] = 0xa5;
+		break;
+	case TUNER_THOMSON_DTT761X:
+		buffer[3] = 0x39;
+		break;
+	case TUNER_MICROTUNE_4049FM5:
+	default:
+		buffer[3] = 0xa4;
+		break;
+	}
+
+	return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
 static int simple_set_tv_freq(struct dvb_frontend *fe,
 			      struct analog_parameters *params)
 {
 	struct tuner_simple_priv *priv = fe->tuner_priv;
-	u8 config, cb, tuneraddr;
+	u8 config, cb;
 	u16 div;
 	struct tunertype *tun;
 	u8 buffer[4];
-	int rc, IFPCoff, i, j;
+	int rc, IFPCoff, i;
 	enum param_type desired_type;
 	struct tuner_params *t_params;
 
@@ -214,133 +557,21 @@
 		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_t_params if desired_type not available */
-	if (desired_type != tun->params[j].type) {
-		tuner_dbg("IFPCoff = %d: tuner_t_params undefined for tuner %d\n",
-			  IFPCoff, priv->type);
-		j = 0;
-	}
-	t_params = &tun->params[j];
+	t_params = simple_tuner_params(fe, desired_type);
 
-	for (i = 0; i < t_params->count; i++) {
-		if (params->frequency > t_params->ranges[i].limit)
-			continue;
-		break;
-	}
-	if (i == t_params->count) {
-		tuner_dbg("TV frequency out of range (%d > %d)",
-				params->frequency, t_params->ranges[i - 1].limit);
-		params->frequency = t_params->ranges[--i].limit;
-	}
-	config = t_params->ranges[i].config;
-	cb     = t_params->ranges[i].cb;
-	/*  i == 0 -> VHF_LO
-	 *  i == 1 -> VHF_HI
-	 *  i == 2 -> UHF     */
-	tuner_dbg("tv: param %d, range %d\n",j,i);
+	i = simple_config_lookup(fe, t_params, &params->frequency,
+				 &config, &cb);
 
-	div=params->frequency + IFPCoff + offset;
+	div = params->frequency + IFPCoff + offset;
 
-	tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, Offset=%d.%02d MHz, div=%0d\n",
-					params->frequency / 16, params->frequency % 16 * 100 / 16,
-					IFPCoff / 16, IFPCoff % 16 * 100 / 16,
-					offset / 16, offset % 16 * 100 / 16,
-					div);
+	tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, "
+		  "Offset=%d.%02d MHz, div=%0d\n",
+		  params->frequency / 16, params->frequency % 16 * 100 / 16,
+		  IFPCoff / 16, IFPCoff % 16 * 100 / 16,
+		  offset / 16, offset % 16 * 100 / 16, div);
 
 	/* tv norm specific stuff for multi-norm tuners */
-	switch (priv->type) {
-	case TUNER_PHILIPS_SECAM: // FI1216MF
-		/* 0x01 -> ??? no change ??? */
-		/* 0x02 -> PAL BDGHI / SECAM L */
-		/* 0x04 -> ??? PAL others / SECAM others ??? */
-		cb &= ~0x03;
-		if (params->std & V4L2_STD_SECAM_L) //also valid for V4L2_STD_SECAM
-			cb |= PHILIPS_MF_SET_STD_L;
-		else if (params->std & V4L2_STD_SECAM_LC)
-			cb |= PHILIPS_MF_SET_STD_LC;
-		else /* V4L2_STD_B|V4L2_STD_GH */
-			cb |= PHILIPS_MF_SET_STD_BG;
-		break;
-
-	case TUNER_TEMIC_4046FM5:
-		cb &= ~0x0f;
-
-		if (params->std & V4L2_STD_PAL_BG) {
-			cb |= TEMIC_SET_PAL_BG;
-
-		} else if (params->std & V4L2_STD_PAL_I) {
-			cb |= TEMIC_SET_PAL_I;
-
-		} else if (params->std & V4L2_STD_PAL_DK) {
-			cb |= TEMIC_SET_PAL_DK;
-
-		} else if (params->std & V4L2_STD_SECAM_L) {
-			cb |= TEMIC_SET_PAL_L;
-
-		}
-		break;
-
-	case TUNER_PHILIPS_FQ1216ME:
-		cb &= ~0x0f;
-
-		if (params->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) {
-			cb |= PHILIPS_SET_PAL_BGDK;
-
-		} else if (params->std & V4L2_STD_PAL_I) {
-			cb |= PHILIPS_SET_PAL_I;
-
-		} else if (params->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 (!(params->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 (params->std & V4L2_STD_ATSC) {
-			cb |= 0x40;
-			buffer[1] = 0x04;
-		}
-		/* set to the correct mode (analog or digital) */
-		tuneraddr = priv->i2c_props.addr;
-		priv->i2c_props.addr = 0x0a;
-		if (2 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,&buffer[0],2)))
-			tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
-		if (2 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,&buffer[2],2)))
-			tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
-		priv->i2c_props.addr = tuneraddr;
-		/* FIXME: input */
-		break;
-	}
+	simple_std_setup(fe, params, &config, &cb);
 
 	if (t_params->cb_first_if_lower_freq && div < priv->last_div) {
 		buffer[0] = config;
@@ -357,8 +588,10 @@
 	if (t_params->has_tda9887) {
 		struct v4l2_priv_tun_config tda9887_cfg;
 		int config = 0;
-		int is_secam_l = (params->std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) &&
-			!(params->std & ~(V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC));
+		int is_secam_l = (params->std & (V4L2_STD_SECAM_L |
+						 V4L2_STD_SECAM_LC)) &&
+			!(params->std & ~(V4L2_STD_SECAM_L |
+					  V4L2_STD_SECAM_LC));
 
 		tda9887_cfg.tuner = TUNER_TDA9887;
 		tda9887_cfg.priv  = &config;
@@ -368,8 +601,7 @@
 				config |= TDA9887_PORT1_ACTIVE;
 			if (t_params->port2_active ^ t_params->port2_invert_for_secam_lc)
 				config |= TDA9887_PORT2_ACTIVE;
-		}
-		else {
+		} else {
 			if (t_params->port1_active)
 				config |= TDA9887_PORT1_ACTIVE;
 			if (t_params->port2_active)
@@ -384,8 +616,7 @@
 				config |= TDA9887_TOP(t_params->default_top_secam_mid);
 			else if (t_params->default_top_secam_high)
 				config |= TDA9887_TOP(t_params->default_top_secam_high);
-		}
-		else {
+		} else {
 			if (i == 0 && t_params->default_top_low)
 				config |= TDA9887_TOP(t_params->default_top_low);
 			else if (i == 1 && t_params->default_top_mid)
@@ -399,56 +630,14 @@
 				    &tda9887_cfg);
 	}
 	tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
-		  buffer[0],buffer[1],buffer[2],buffer[3]);
+		  buffer[0], buffer[1], buffer[2], buffer[3]);
 
-	if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4)))
-		tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
+	rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
+	if (4 != rc)
+		tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc);
 
-	switch (priv->type) {
-	case TUNER_LG_TDVS_H06XF:
-		/* Set the Auxiliary Byte. */
-		buffer[0] = buffer[2];
-		buffer[0] &= ~0x20;
-		buffer[0] |= 0x18;
-		buffer[1] = 0x20;
-		tuner_dbg("tv 0x%02x 0x%02x\n",buffer[0],buffer[1]);
+	simple_post_tune(fe, &buffer[0], div, config, cb);
 
-		if (2 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,2)))
-			tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
-		break;
-	case TUNER_MICROTUNE_4042FI5:
-	{
-		// FIXME - this may also work for other tuners
-		unsigned long timeout = jiffies + msecs_to_jiffies(1);
-		u8 status_byte = 0;
-
-		/* Wait until the PLL locks */
-		for (;;) {
-			if (time_after(jiffies,timeout))
-				return 0;
-			if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,&status_byte,1))) {
-				tuner_warn("i2c i/o read error: rc == %d (should be 1)\n",rc);
-				break;
-			}
-			if (status_byte & TUNER_PLL_LOCKED)
-				break;
-			udelay(10);
-		}
-
-		/* Set the charge pump for optimized phase noise figure */
-		config &= ~TUNER_CHARGE_PUMP;
-		buffer[0] = (div>>8) & 0x7f;
-		buffer[1] = div      & 0xff;
-		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]);
-
-		if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4)))
-			tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
-		break;
-	}
-	}
 	return 0;
 }
 
@@ -483,37 +672,13 @@
 		freq += (unsigned int)(41.3*16000);
 		break;
 	default:
-		tuner_warn("Unsupported radio_if value %d\n", t_params->radio_if);
+		tuner_warn("Unsupported radio_if value %d\n",
+			   t_params->radio_if);
 		return 0;
 	}
 
 	/* Bandswitch byte */
-	switch (priv->type) {
-	case TUNER_TENA_9533_DI:
-	case TUNER_YMEC_TVF_5533MF:
-		tuner_dbg("This tuner doesn't have FM. Most cards have a TEA5767 for FM\n");
-		return 0;
-	case TUNER_PHILIPS_FM1216ME_MK3:
-	case TUNER_PHILIPS_FM1236_MK3:
-	case TUNER_PHILIPS_FMD1216ME_MK3:
-	case TUNER_LG_NTSC_TAPE:
-	case TUNER_PHILIPS_FM1256_IH3:
-		buffer[3] = 0x19;
-		break;
-	case TUNER_TNF_5335MF:
-		buffer[3] = 0x11;
-		break;
-	case TUNER_LG_PAL_FM:
-		buffer[3] = 0xa5;
-		break;
-	case TUNER_THOMSON_DTT761X:
-		buffer[3] = 0x39;
-		break;
-	case TUNER_MICROTUNE_4049FM5:
-	default:
-		buffer[3] = 0xa4;
-		break;
-	}
+	simple_radio_bandswitch(fe, &buffer[0]);
 
 	buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) |
 		    TUNER_RATIO_SELECT_50; /* 50 kHz step */
@@ -534,7 +699,7 @@
 	}
 
 	tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n",
-	       buffer[0],buffer[1],buffer[2],buffer[3]);
+	       buffer[0], buffer[1], buffer[2], buffer[3]);
 	priv->last_div = div;
 
 	if (t_params->has_tda9887) {
@@ -544,9 +709,11 @@
 		tda9887_cfg.tuner = TUNER_TDA9887;
 		tda9887_cfg.priv = &config;
 
-		if (t_params->port1_active && !t_params->port1_fm_high_sensitivity)
+		if (t_params->port1_active &&
+		    !t_params->port1_fm_high_sensitivity)
 			config |= TDA9887_PORT1_ACTIVE;
-		if (t_params->port2_active && !t_params->port2_fm_high_sensitivity)
+		if (t_params->port2_active &&
+		    !t_params->port2_fm_high_sensitivity)
 			config |= TDA9887_PORT2_ACTIVE;
 		if (t_params->intercarrier_mode)
 			config |= TDA9887_INTERCARRIER;
@@ -557,10 +724,11 @@
 		if (t_params->radio_if == 2)
 			config |= TDA9887_RIF_41_3;
 		i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,
-					&tda9887_cfg);
+				    &tda9887_cfg);
 	}
-	if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4)))
-		tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
+	rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
+	if (4 != rc)
+		tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc);
 
 	return 0;
 }
@@ -571,6 +739,9 @@
 	struct tuner_simple_priv *priv = fe->tuner_priv;
 	int ret = -EINVAL;
 
+	if (priv->i2c_props.adap == NULL)
+		return -EINVAL;
+
 	switch (params->mode) {
 	case V4L2_TUNER_RADIO:
 		ret = simple_set_radio_freq(fe, params);
@@ -582,14 +753,210 @@
 		priv->frequency = params->frequency * 62500;
 		break;
 	}
+	priv->bandwidth = 0;
 
 	return ret;
 }
 
+static void simple_set_dvb(struct dvb_frontend *fe, u8 *buf,
+			   const struct dvb_frontend_parameters *params)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+
+	switch (priv->type) {
+	case TUNER_PHILIPS_FMD1216ME_MK3:
+		if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ &&
+		    params->frequency >= 158870000)
+			buf[3] |= 0x08;
+		break;
+	case TUNER_PHILIPS_TD1316:
+		/* determine band */
+		buf[3] |= (params->frequency < 161000000) ? 1 :
+			  (params->frequency < 444000000) ? 2 : 4;
+
+		/* setup PLL filter */
+		if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
+			buf[3] |= 1 << 3;
+		break;
+	case TUNER_PHILIPS_TUV1236D:
+	case TUNER_PHILIPS_FCV1236D:
+	{
+		unsigned int new_rf;
+
+		if (dtv_input[priv->nr])
+			new_rf = dtv_input[priv->nr];
+		else
+			switch (params->u.vsb.modulation) {
+			case QAM_64:
+			case QAM_256:
+				new_rf = 1;
+				break;
+			case VSB_8:
+			default:
+				new_rf = 0;
+				break;
+			}
+		simple_set_rf_input(fe, &buf[2], &buf[3], new_rf);
+		break;
+	}
+	default:
+		break;
+	}
+}
+
+static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf,
+				const struct dvb_frontend_parameters *params)
+{
+	/* This function returns the tuned frequency on success, 0 on error */
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+	struct tunertype *tun = priv->tun;
+	static struct tuner_params *t_params;
+	u8 config, cb;
+	u32 div;
+	int ret, frequency = params->frequency / 62500;
+
+	t_params = simple_tuner_params(fe, TUNER_PARAM_TYPE_DIGITAL);
+	ret = simple_config_lookup(fe, t_params, &frequency, &config, &cb);
+	if (ret < 0)
+		return 0; /* failure */
+
+	div = ((frequency + t_params->iffreq) * 62500 + offset +
+	       tun->stepsize/2) / tun->stepsize;
+
+	buf[0] = div >> 8;
+	buf[1] = div & 0xff;
+	buf[2] = config;
+	buf[3] = cb;
+
+	simple_set_dvb(fe, buf, params);
+
+	tuner_dbg("%s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
+		  tun->name, div, buf[0], buf[1], buf[2], buf[3]);
+
+	/* calculate the frequency we set it to */
+	return (div * tun->stepsize) - t_params->iffreq;
+}
+
+static int simple_dvb_calc_regs(struct dvb_frontend *fe,
+				struct dvb_frontend_parameters *params,
+				u8 *buf, int buf_len)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+	u32 frequency;
+
+	if (buf_len < 5)
+		return -EINVAL;
+
+	frequency = simple_dvb_configure(fe, buf+1, params);
+	if (frequency == 0)
+		return -EINVAL;
+
+	buf[0] = priv->i2c_props.addr;
+
+	priv->frequency = frequency;
+	priv->bandwidth = (fe->ops.info.type == FE_OFDM) ?
+		params->u.ofdm.bandwidth : 0;
+
+	return 5;
+}
+
+static int simple_dvb_set_params(struct dvb_frontend *fe,
+				 struct dvb_frontend_parameters *params)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+	u32 prev_freq, prev_bw;
+	int ret;
+	u8 buf[5];
+
+	if (priv->i2c_props.adap == NULL)
+		return -EINVAL;
+
+	prev_freq = priv->frequency;
+	prev_bw   = priv->bandwidth;
+
+	ret = simple_dvb_calc_regs(fe, params, buf, 5);
+	if (ret != 5)
+		goto fail;
+
+	/* put analog demod in standby when tuning digital */
+	if (fe->ops.analog_ops.standby)
+		fe->ops.analog_ops.standby(fe);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	/* buf[0] contains the i2c address, but *
+	 * we already have it in i2c_props.addr */
+	ret = tuner_i2c_xfer_send(&priv->i2c_props, buf+1, 4);
+	if (ret != 4)
+		goto fail;
+
+	return 0;
+fail:
+	/* calc_regs sets frequency and bandwidth. if we failed, unset them */
+	priv->frequency = prev_freq;
+	priv->bandwidth = prev_bw;
+
+	return ret;
+}
+
+static int simple_init(struct dvb_frontend *fe)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+
+	if (priv->i2c_props.adap == NULL)
+		return -EINVAL;
+
+	if (priv->tun->initdata) {
+		int ret;
+
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+
+		ret = tuner_i2c_xfer_send(&priv->i2c_props,
+					  priv->tun->initdata + 1,
+					  priv->tun->initdata[0]);
+		if (ret != priv->tun->initdata[0])
+			return ret;
+	}
+
+	return 0;
+}
+
+static int simple_sleep(struct dvb_frontend *fe)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+
+	if (priv->i2c_props.adap == NULL)
+		return -EINVAL;
+
+	if (priv->tun->sleepdata) {
+		int ret;
+
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+
+		ret = tuner_i2c_xfer_send(&priv->i2c_props,
+					  priv->tun->sleepdata + 1,
+					  priv->tun->sleepdata[0]);
+		if (ret != priv->tun->sleepdata[0])
+			return ret;
+	}
+
+	return 0;
+}
 
 static int simple_release(struct dvb_frontend *fe)
 {
-	kfree(fe->tuner_priv);
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+
+	mutex_lock(&tuner_simple_list_mutex);
+
+	if (priv)
+		hybrid_tuner_release_state(priv);
+
+	mutex_unlock(&tuner_simple_list_mutex);
+
 	fe->tuner_priv = NULL;
 
 	return 0;
@@ -602,10 +969,22 @@
 	return 0;
 }
 
+static int simple_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+	*bandwidth = priv->bandwidth;
+	return 0;
+}
+
 static struct dvb_tuner_ops simple_tuner_ops = {
+	.init              = simple_init,
+	.sleep             = simple_sleep,
 	.set_analog_params = simple_set_params,
+	.set_params        = simple_dvb_set_params,
+	.calc_regs         = simple_dvb_calc_regs,
 	.release           = simple_release,
 	.get_frequency     = simple_get_frequency,
+	.get_bandwidth     = simple_get_bandwidth,
 	.get_status        = simple_get_status,
 	.get_rf_strength   = simple_get_rf_strength,
 };
@@ -613,30 +992,92 @@
 struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
 					 struct i2c_adapter *i2c_adap,
 					 u8 i2c_addr,
-					 struct simple_tuner_config *cfg)
+					 unsigned int type)
 {
 	struct tuner_simple_priv *priv = NULL;
+	int instance;
 
-	priv = kzalloc(sizeof(struct tuner_simple_priv), GFP_KERNEL);
-	if (priv == NULL)
+	if (type >= tuner_count) {
+		printk(KERN_WARNING "%s: invalid tuner type: %d (max: %d)\n",
+		       __func__, type, tuner_count-1);
 		return NULL;
-	fe->tuner_priv = priv;
+	}
 
-	priv->i2c_props.addr = i2c_addr;
-	priv->i2c_props.adap = i2c_adap;
-	priv->type = cfg->type;
-	priv->tun  = cfg->tun;
+	/* If i2c_adap is set, check that the tuner is at the correct address.
+	 * Otherwise, if i2c_adap is NULL, the tuner will be programmed directly
+	 * by the digital demod via calc_regs.
+	 */
+	if (i2c_adap != NULL) {
+		u8 b[1];
+		struct i2c_msg msg = {
+			.addr = i2c_addr, .flags = I2C_M_RD,
+			.buf = b, .len = 1,
+		};
 
-	memcpy(&fe->ops.tuner_ops, &simple_tuner_ops, sizeof(struct dvb_tuner_ops));
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
 
-	tuner_info("type set to %d (%s)\n", cfg->type, cfg->tun->name);
+		if (1 != i2c_transfer(i2c_adap, &msg, 1))
+			tuner_warn("unable to probe %s, proceeding anyway.",
+				   tuners[type].name);
 
-	strlcpy(fe->ops.tuner_ops.info.name, cfg->tun->name, sizeof(fe->ops.tuner_ops.info.name));
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	mutex_lock(&tuner_simple_list_mutex);
+
+	instance = hybrid_tuner_request_state(struct tuner_simple_priv, priv,
+					      hybrid_tuner_instance_list,
+					      i2c_adap, i2c_addr,
+					      "tuner-simple");
+	switch (instance) {
+	case 0:
+		mutex_unlock(&tuner_simple_list_mutex);
+		return NULL;
+		break;
+	case 1:
+		fe->tuner_priv = priv;
+
+		priv->type = type;
+		priv->tun  = &tuners[type];
+		priv->nr   = simple_devcount++;
+		break;
+	default:
+		fe->tuner_priv = priv;
+		break;
+	}
+
+	mutex_unlock(&tuner_simple_list_mutex);
+
+	memcpy(&fe->ops.tuner_ops, &simple_tuner_ops,
+	       sizeof(struct dvb_tuner_ops));
+
+	tuner_info("type set to %d (%s)\n", type, priv->tun->name);
+
+	if ((debug) || ((atv_input[priv->nr] > 0) ||
+			(dtv_input[priv->nr] > 0))) {
+		if (0 == atv_input[priv->nr])
+			tuner_info("tuner %d atv rf input will be "
+				   "autoselected\n", priv->nr);
+		else
+			tuner_info("tuner %d atv rf input will be "
+				   "set to input %d (insmod option)\n",
+				   priv->nr, atv_input[priv->nr]);
+		if (0 == dtv_input[priv->nr])
+			tuner_info("tuner %d dtv rf input will be "
+				   "autoselected\n", priv->nr);
+		else
+			tuner_info("tuner %d dtv rf input will be "
+				   "set to input %d (insmod option)\n",
+				   priv->nr, dtv_input[priv->nr]);
+	}
+
+	strlcpy(fe->ops.tuner_ops.info.name, priv->tun->name,
+		sizeof(fe->ops.tuner_ops.info.name));
 
 	return fe;
 }
-
-
 EXPORT_SYMBOL_GPL(simple_tuner_attach);
 
 MODULE_DESCRIPTION("Simple 4-control-bytes style tuner driver");
diff --git a/drivers/media/video/tuner-simple.h b/drivers/media/video/tuner-simple.h
index 9089939..e46cf01 100644
--- a/drivers/media/video/tuner-simple.h
+++ b/drivers/media/video/tuner-simple.h
@@ -20,25 +20,18 @@
 #include <linux/i2c.h>
 #include "dvb_frontend.h"
 
-struct simple_tuner_config
-{
-	/* chip type */
-	unsigned int type;
-	struct tunertype *tun;
-};
-
 #if defined(CONFIG_TUNER_SIMPLE) || (defined(CONFIG_TUNER_SIMPLE_MODULE) && defined(MODULE))
 extern struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
 						struct i2c_adapter *i2c_adap,
 						u8 i2c_addr,
-						struct simple_tuner_config *cfg);
+						unsigned int type);
 #else
 static inline struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
 						       struct i2c_adapter *i2c_adap,
 						       u8 i2c_addr,
-						       struct simple_tuner_config *cfg)
+						       unsigned int type)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 	return NULL;
 }
 #endif
diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c
index 883047f..10dddca 100644
--- a/drivers/media/video/tuner-types.c
+++ b/drivers/media/video/tuner-types.c
@@ -35,6 +35,27 @@
  *	based on the video standard in use.
  */
 
+/* The following was taken from dvb-pll.c: */
+
+/* Set AGC TOP value to 103 dBuV:
+ *	0x80 = Control Byte
+ *	0x40 = 250 uA charge pump (irrelevant)
+ *	0x18 = Aux Byte to follow
+ *	0x06 = 64.5 kHz divider (irrelevant)
+ *	0x01 = Disable Vt (aka sleep)
+ *
+ *	0x00 = AGC Time constant 2s Iagc = 300 nA (vs 0x80 = 9 nA)
+ *	0x50 = AGC Take over point = 103 dBuV
+ */
+static u8 tua603x_agc103[] = { 2, 0x80|0x40|0x18|0x06|0x01, 0x00|0x50 };
+
+/*	0x04 = 166.67 kHz divider
+ *
+ *	0x80 = AGC Time constant 50ms Iagc = 9 uA
+ *	0x20 = AGC Take over point = 112 dBuV
+ */
+static u8 tua603x_agc112[] = { 2, 0x80|0x40|0x18|0x04|0x01, 0x80|0x20 };
+
 /* 0-9 */
 /* ------------ TUNER_TEMIC_PAL - TEMIC PAL ------------ */
 
@@ -594,19 +615,31 @@
 	},
 };
 
-/* ---- TUNER_PHILIPS_ATSC - Philips FCV1236D (ATSC/NTSC) ---- */
+/* ---- TUNER_PHILIPS_FCV1236D - Philips FCV1236D (ATSC/NTSC) ---- */
 
-static struct tuner_range tuner_philips_fcv1236d_ranges[] = {
-	{ 16 * 157.25 /*MHz*/, 0x8e, 0xa0, },
-	{ 16 * 451.25 /*MHz*/, 0x8e, 0x90, },
+static struct tuner_range tuner_philips_fcv1236d_ntsc_ranges[] = {
+	{ 16 * 157.25 /*MHz*/, 0x8e, 0xa2, },
+	{ 16 * 451.25 /*MHz*/, 0x8e, 0x92, },
+	{ 16 * 999.99        , 0x8e, 0x32, },
+};
+
+static struct tuner_range tuner_philips_fcv1236d_atsc_ranges[] = {
+	{ 16 * 159.00 /*MHz*/, 0x8e, 0xa0, },
+	{ 16 * 453.00 /*MHz*/, 0x8e, 0x90, },
 	{ 16 * 999.99        , 0x8e, 0x30, },
 };
 
 static struct tuner_params tuner_philips_fcv1236d_params[] = {
 	{
 		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_philips_fcv1236d_ranges,
-		.count  = ARRAY_SIZE(tuner_philips_fcv1236d_ranges),
+		.ranges = tuner_philips_fcv1236d_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_philips_fcv1236d_ntsc_ranges),
+	},
+	{
+		.type   = TUNER_PARAM_TYPE_DIGITAL,
+		.ranges = tuner_philips_fcv1236d_atsc_ranges,
+		.count  = ARRAY_SIZE(tuner_philips_fcv1236d_atsc_ranges),
+		.iffreq = 16 * 44.00,
 	},
 };
 
@@ -701,12 +734,24 @@
 	{ 16 * 999.99        , 0x8e, 0x31, },
 };
 
+static struct tuner_range tuner_microtune_4042fi5_atsc_ranges[] = {
+	{ 16 * 162.00 /*MHz*/, 0x8e, 0xa1, },
+	{ 16 * 457.00 /*MHz*/, 0x8e, 0x91, },
+	{ 16 * 999.99        , 0x8e, 0x31, },
+};
+
 static struct tuner_params tuner_microtune_4042fi5_params[] = {
 	{
 		.type   = TUNER_PARAM_TYPE_NTSC,
 		.ranges = tuner_microtune_4042fi5_ntsc_ranges,
 		.count  = ARRAY_SIZE(tuner_microtune_4042fi5_ntsc_ranges),
 	},
+	{
+		.type   = TUNER_PARAM_TYPE_DIGITAL,
+		.ranges = tuner_microtune_4042fi5_atsc_ranges,
+		.count  = ARRAY_SIZE(tuner_microtune_4042fi5_atsc_ranges),
+		.iffreq = 16 * 44.00 /*MHz*/,
+	},
 };
 
 /* 50-59 */
@@ -740,6 +785,7 @@
 
 /* ------------ TUNER_THOMSON_DTT7610 - THOMSON ATSC ------------ */
 
+/* single range used for both ntsc and atsc */
 static struct tuner_range tuner_thomson_dtt7610_ntsc_ranges[] = {
 	{ 16 * 157.25 /*MHz*/, 0x8e, 0x39, },
 	{ 16 * 454.00 /*MHz*/, 0x8e, 0x3a, },
@@ -752,6 +798,12 @@
 		.ranges = tuner_thomson_dtt7610_ntsc_ranges,
 		.count  = ARRAY_SIZE(tuner_thomson_dtt7610_ntsc_ranges),
 	},
+	{
+		.type   = TUNER_PARAM_TYPE_DIGITAL,
+		.ranges = tuner_thomson_dtt7610_ntsc_ranges,
+		.count  = ARRAY_SIZE(tuner_thomson_dtt7610_ntsc_ranges),
+		.iffreq = 16 * 44.00 /*MHz*/,
+	},
 };
 
 /* ------------ TUNER_PHILIPS_FQ1286 - Philips NTSC ------------ */
@@ -855,6 +907,11 @@
 	{ 16 * 999.99        , 0x8e, 0x3c, },
 };
 
+static struct tuner_range tuner_thomson_dtt761x_atsc_ranges[] = {
+	{ 16 * 147.00 /*MHz*/, 0x8e, 0x39, },
+	{ 16 * 417.00 /*MHz*/, 0x8e, 0x3a, },
+	{ 16 * 999.99        , 0x8e, 0x3c, },
+};
 
 static struct tuner_params tuner_thomson_dtt761x_params[] = {
 	{
@@ -865,6 +922,12 @@
 		.fm_gain_normal = 1,
 		.radio_if = 2, /* 41.3 MHz */
 	},
+	{
+		.type   = TUNER_PARAM_TYPE_DIGITAL,
+		.ranges = tuner_thomson_dtt761x_atsc_ranges,
+		.count  = ARRAY_SIZE(tuner_thomson_dtt761x_atsc_ranges),
+		.iffreq = 16 * 44.00, /*MHz*/
+	},
 };
 
 /* ------------ TUNER_TENA_9533_DI - Philips PAL ------------ */
@@ -891,6 +954,15 @@
 	{ 16 * 999.99        , 0x86, 0x54, },
 };
 
+static struct tuner_range tuner_philips_fmd1216me_mk3_dvb_ranges[] = {
+	{ 16 * 143.87 /*MHz*/, 0xbc, 0x41 },
+	{ 16 * 158.87 /*MHz*/, 0xf4, 0x41 },
+	{ 16 * 329.87 /*MHz*/, 0xbc, 0x42 },
+	{ 16 * 441.87 /*MHz*/, 0xf4, 0x42 },
+	{ 16 * 625.87 /*MHz*/, 0xbc, 0x44 },
+	{ 16 * 803.87 /*MHz*/, 0xf4, 0x44 },
+	{ 16 * 999.99        , 0xfc, 0x44 },
+};
 
 static struct tuner_params tuner_philips_fmd1216me_mk3_params[] = {
 	{
@@ -904,6 +976,12 @@
 		.port2_invert_for_secam_lc = 1,
 		.port1_set_for_fm_mono = 1,
 	},
+	{
+		.type   = TUNER_PARAM_TYPE_DIGITAL,
+		.ranges = tuner_philips_fmd1216me_mk3_dvb_ranges,
+		.count  = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_dvb_ranges),
+		.iffreq = 16 * 36.125, /*MHz*/
+	},
 };
 
 
@@ -915,6 +993,11 @@
 	{ 16 * 999.99        , 0x8e, 0x04 },
 };
 
+static struct tuner_range tuner_tua6034_atsc_ranges[] = {
+	{ 16 * 165.00 /*MHz*/, 0xce, 0x01 },
+	{ 16 * 450.00 /*MHz*/, 0xce, 0x02 },
+	{ 16 * 999.99        , 0xce, 0x04 },
+};
 
 static struct tuner_params tuner_lg_tdvs_h06xf_params[] = {
 	{
@@ -922,6 +1005,12 @@
 		.ranges = tuner_tua6034_ntsc_ranges,
 		.count  = ARRAY_SIZE(tuner_tua6034_ntsc_ranges),
 	},
+	{
+		.type   = TUNER_PARAM_TYPE_DIGITAL,
+		.ranges = tuner_tua6034_atsc_ranges,
+		.count  = ARRAY_SIZE(tuner_tua6034_atsc_ranges),
+		.iffreq = 16 * 44.00,
+	},
 };
 
 /* ------------ TUNER_YMEC_TVF66T5_B_DFF - Philips PAL ------------ */
@@ -974,12 +1063,30 @@
 	{ 16 * 999.99        , 0xc8, 0xa4, },
 };
 
+static struct tuner_range tuner_philips_td1316_dvb_ranges[] = {
+	{ 16 *  93.834 /*MHz*/, 0xca, 0x60, },
+	{ 16 * 123.834 /*MHz*/, 0xca, 0xa0, },
+	{ 16 * 163.834 /*MHz*/, 0xca, 0xc0, },
+	{ 16 * 253.834 /*MHz*/, 0xca, 0x60, },
+	{ 16 * 383.834 /*MHz*/, 0xca, 0xa0, },
+	{ 16 * 443.834 /*MHz*/, 0xca, 0xc0, },
+	{ 16 * 583.834 /*MHz*/, 0xca, 0x60, },
+	{ 16 * 793.834 /*MHz*/, 0xca, 0xa0, },
+	{ 16 * 999.999        , 0xca, 0xe0, },
+};
+
 static struct tuner_params tuner_philips_td1316_params[] = {
 	{
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_philips_td1316_pal_ranges,
 		.count  = ARRAY_SIZE(tuner_philips_td1316_pal_ranges),
 	},
+	{
+		.type   = TUNER_PARAM_TYPE_DIGITAL,
+		.ranges = tuner_philips_td1316_dvb_ranges,
+		.count  = ARRAY_SIZE(tuner_philips_td1316_dvb_ranges),
+		.iffreq = 16 * 36.166667 /*MHz*/,
+	},
 };
 
 /* ------------ TUNER_PHILIPS_TUV1236D - Philips ATSC ------------ */
@@ -990,6 +1097,11 @@
 	{ 16 * 999.99        , 0xce, 0x04, },
 };
 
+static struct tuner_range tuner_tuv1236d_atsc_ranges[] = {
+	{ 16 * 157.25 /*MHz*/, 0xc6, 0x41, },
+	{ 16 * 454.00 /*MHz*/, 0xc6, 0x42, },
+	{ 16 * 999.99        , 0xc6, 0x44, },
+};
 
 static struct tuner_params tuner_tuv1236d_params[] = {
 	{
@@ -997,6 +1109,12 @@
 		.ranges = tuner_tuv1236d_ntsc_ranges,
 		.count  = ARRAY_SIZE(tuner_tuv1236d_ntsc_ranges),
 	},
+	{
+		.type   = TUNER_PARAM_TYPE_DIGITAL,
+		.ranges = tuner_tuv1236d_atsc_ranges,
+		.count  = ARRAY_SIZE(tuner_tuv1236d_atsc_ranges),
+		.iffreq = 16 * 44.00,
+	},
 };
 
 /* ------------ TUNER_TNF_xxx5  - Texas Instruments--------- */
@@ -1050,17 +1168,30 @@
 
 /* ------------ TUNER_THOMSON_FE6600 - DViCO Hybrid PAL ------------ */
 
-static struct tuner_range tuner_thomson_fe6600_ranges[] = {
+static struct tuner_range tuner_thomson_fe6600_pal_ranges[] = {
 	{ 16 * 160.00 /*MHz*/, 0xfe, 0x11, },
 	{ 16 * 442.00 /*MHz*/, 0xf6, 0x12, },
 	{ 16 * 999.99        , 0xf6, 0x18, },
 };
 
+static struct tuner_range tuner_thomson_fe6600_dvb_ranges[] = {
+	{ 16 * 250.00 /*MHz*/, 0xb4, 0x12, },
+	{ 16 * 455.00 /*MHz*/, 0xfe, 0x11, },
+	{ 16 * 775.50 /*MHz*/, 0xbc, 0x18, },
+	{ 16 * 999.99        , 0xf4, 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),
+		.ranges = tuner_thomson_fe6600_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_thomson_fe6600_pal_ranges),
+	},
+	{
+		.type   = TUNER_PARAM_TYPE_DIGITAL,
+		.ranges = tuner_thomson_fe6600_dvb_ranges,
+		.count  = ARRAY_SIZE(tuner_thomson_fe6600_dvb_ranges),
+		.iffreq = 16 * 36.125 /*MHz*/,
 	},
 };
 
@@ -1303,10 +1434,13 @@
 		.params = tuner_philips_pal_mk_params,
 		.count  = ARRAY_SIZE(tuner_philips_pal_mk_params),
 	},
-	[TUNER_PHILIPS_ATSC] = { /* Philips ATSC */
+	[TUNER_PHILIPS_FCV1236D] = { /* Philips ATSC */
 		.name   = "Philips FCV1236D ATSC/NTSC dual in",
 		.params = tuner_philips_fcv1236d_params,
 		.count  = ARRAY_SIZE(tuner_philips_fcv1236d_params),
+		.min = 16 *  53.00,
+		.max = 16 * 803.00,
+		.stepsize = 62500,
 	},
 	[TUNER_PHILIPS_FM1236_MK3] = { /* Philips NTSC */
 		.name   = "Philips NTSC MK3 (FM1236MK3 or FM1236/F)",
@@ -1342,6 +1476,9 @@
 		.name   = "Microtune 4042 FI5 ATSC/NTSC dual in",
 		.params = tuner_microtune_4042fi5_params,
 		.count  = ARRAY_SIZE(tuner_microtune_4042fi5_params),
+		.min    = 16 *  57.00,
+		.max    = 16 * 858.00,
+		.stepsize = 62500,
 	},
 
 	/* 50-59 */
@@ -1359,6 +1496,9 @@
 		.name   = "Thomson DTT 7610 (ATSC/NTSC)",
 		.params = tuner_thomson_dtt7610_params,
 		.count  = ARRAY_SIZE(tuner_thomson_dtt7610_params),
+		.min    = 16 *  44.00,
+		.max    = 16 * 958.00,
+		.stepsize = 62500,
 	},
 	[TUNER_PHILIPS_FQ1286] = { /* Philips NTSC */
 		.name   = "Philips FQ1286",
@@ -1400,6 +1540,10 @@
 		.name   = "Thomson DTT 761X (ATSC/NTSC)",
 		.params = tuner_thomson_dtt761x_params,
 		.count  = ARRAY_SIZE(tuner_thomson_dtt761x_params),
+		.min    = 16 *  57.00,
+		.max    = 16 * 863.00,
+		.stepsize = 62500,
+		.initdata = tua603x_agc103,
 	},
 	[TUNER_TENA_9533_DI] = { /* Philips PAL */
 		.name   = "Tena TNF9533-D/IF/TNF9533-B/DF",
@@ -1414,11 +1558,20 @@
 		.name   = "Philips FMD1216ME MK3 Hybrid Tuner",
 		.params = tuner_philips_fmd1216me_mk3_params,
 		.count  = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_params),
+		.min = 16 *  50.87,
+		.max = 16 * 858.00,
+		.stepsize = 166667,
+		.initdata = tua603x_agc112,
+		.sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 },
 	},
 	[TUNER_LG_TDVS_H06XF] = { /* LGINNOTEK ATSC */
 		.name   = "LG TDVS-H06xF", /* H061F, H062F & H064F */
 		.params = tuner_lg_tdvs_h06xf_params,
 		.count  = ARRAY_SIZE(tuner_lg_tdvs_h06xf_params),
+		.min    = 16 *  54.00,
+		.max    = 16 * 863.00,
+		.stepsize = 62500,
+		.initdata = tua603x_agc103,
 	},
 	[TUNER_YMEC_TVF66T5_B_DFF] = { /* Philips PAL */
 		.name   = "Ymec TVF66T5-B/DFF",
@@ -1434,11 +1587,17 @@
 		.name   = "Philips TD1316 Hybrid Tuner",
 		.params = tuner_philips_td1316_params,
 		.count  = ARRAY_SIZE(tuner_philips_td1316_params),
+		.min    = 16 *  87.00,
+		.max    = 16 * 895.00,
+		.stepsize = 166667,
 	},
 	[TUNER_PHILIPS_TUV1236D] = { /* Philips ATSC */
 		.name   = "Philips TUV1236D ATSC/NTSC dual in",
 		.params = tuner_tuv1236d_params,
 		.count  = ARRAY_SIZE(tuner_tuv1236d_params),
+		.min    = 16 *  54.00,
+		.max    = 16 * 864.00,
+		.stepsize = 62500,
 	},
 	[TUNER_TNF_5335MF] = { /* Tenna PAL/NTSC */
 		.name   = "Tena TNF 5335 and similar models",
@@ -1460,6 +1619,9 @@
 		.name   = "Thomson FE6600",
 		.params = tuner_thomson_fe6600_params,
 		.count  = ARRAY_SIZE(tuner_thomson_fe6600_params),
+		.min    = 16 *  44.25,
+		.max    = 16 * 858.00,
+		.stepsize = 166667,
 	},
 	[TUNER_SAMSUNG_TCPG_6121P30A] = { /* Samsung PAL */
 		.name   = "Samsung TCPG 6121P30A",
@@ -1480,5 +1642,11 @@
 		/* see xc5000.c for details */
 	},
 };
+EXPORT_SYMBOL(tuners);
 
 unsigned const int tuner_count = ARRAY_SIZE(tuners);
+EXPORT_SYMBOL(tuner_count);
+
+MODULE_DESCRIPTION("Simple tuner device type database");
+MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/tuner-xc2028-types.h b/drivers/media/video/tuner-xc2028-types.h
index d0057fb..74dc46a 100644
--- a/drivers/media/video/tuner-xc2028-types.h
+++ b/drivers/media/video/tuner-xc2028-types.h
@@ -1,6 +1,9 @@
 /* tuner-xc2028_types
  *
- * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This file includes internal tipes to be used inside tuner-xc2028.
+ * Shouldn't be included outside tuner-xc2028
+ *
+ * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org)
  * This code is placed under the terms of the GNU General Public License v2
  */
 
@@ -54,11 +57,13 @@
 /* LCD firmwares exist only for MTS STD/MN (PAL or NTSC/M)
 	and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr)
 	There are variants both with and without NOGD
+	Those firmwares produce better result with LCD displays
  */
 #define LCD		(1<<12)
 
 /* NOGD firmwares exist only for MTS STD/MN (PAL or NTSC/M)
 	and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr)
+	The NOGD firmwares don't have group delay compensation filter
  */
 #define NOGD		(1<<13)
 
@@ -85,11 +90,19 @@
 /* This flag identifies that the scode table has a new format */
 #define HAS_IF         (1 << 30)
 
-#define SCODE_TYPES	(MTS|DTV6|QAM|DTV7|DTV78|DTV8|LCD|NOGD|MONO|ATSC|IF| \
-			 LG60|ATI638|OREN538|OREN36|TOYOTA388|TOYOTA794|     \
-			 DIBCOM52|ZARLINK456|CHINA|F6MHZ|SCODE)
+/* There are different scode tables for MTS and non-MTS.
+   The MTS firmwares support mono only
+  */
+#define SCODE_TYPES (SCODE | MTS)
 
-/* Newer types to be moved to videodev2.h */
+
+/* Newer types not defined on videodev2.h.
+   The original idea were to move all those types to videodev2.h, but
+   it seemed overkill, since, with the exception of SECAM/K3, the other
+   types seem to be autodetected.
+   It is not clear where secam/k3 is used, nor we have a feedback of this
+   working or being autodetected by the standard secam firmware.
+ */
 
 #define V4L2_STD_SECAM_K3	(0x04000000)
 
diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c
index 50cf876..cc3db7d 100644
--- a/drivers/media/video/tuner-xc2028.c
+++ b/drivers/media/video/tuner-xc2028.c
@@ -1,6 +1,6 @@
 /* tuner-xc2028
  *
- * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org)
  *
  * Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com)
  *       - frontend interface
@@ -23,8 +23,6 @@
 #include "dvb_frontend.h"
 
 
-#define PREFIX "xc2028"
-
 static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable verbose debug messages");
@@ -43,6 +41,11 @@
 	"NICAM/A\n"
 	"NICAM/B\n");
 
+static char firmware_name[FIRMWARE_NAME_MAX];
+module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0);
+MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the "
+				"default firmware name\n");
+
 static LIST_HEAD(xc2028_list);
 static DEFINE_MUTEX(xc2028_list_mutex);
 
@@ -127,12 +130,12 @@
 	_rc;								\
 })
 
-static unsigned int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val)
+static int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val)
 {
 	unsigned char buf[2];
 	unsigned char ibuf[2];
 
-	tuner_dbg("%s %04x called\n", __FUNCTION__, reg);
+	tuner_dbg("%s %04x called\n", __func__, reg);
 
 	buf[0] = reg >> 8;
 	buf[1] = (unsigned char) reg;
@@ -145,7 +148,7 @@
 }
 
 #define dump_firm_type(t) 	dump_firm_type_and_int_freq(t, 0)
-void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq)
+static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq)
 {
 	 if (type & BASE)
 		printk("BASE ");
@@ -232,6 +235,7 @@
 static void free_firmware(struct xc2028_data *priv)
 {
 	int i;
+	tuner_dbg("%s called\n", __func__);
 
 	if (!priv->firm)
 		return;
@@ -255,19 +259,24 @@
 	int                   rc = 0;
 	int		      n, n_array;
 	char		      name[33];
+	char		      *fname;
 
-	tuner_dbg("%s called\n", __FUNCTION__);
+	tuner_dbg("%s called\n", __func__);
 
-	tuner_dbg("Reading firmware %s\n", priv->ctrl.fname);
-	rc = request_firmware(&fw, priv->ctrl.fname,
-			      &priv->i2c_props.adap->dev);
+	if (!firmware_name[0])
+		fname = priv->ctrl.fname;
+	else
+		fname = firmware_name;
+
+	tuner_dbg("Reading firmware %s\n", fname);
+	rc = request_firmware(&fw, fname, &priv->i2c_props.adap->dev);
 	if (rc < 0) {
 		if (rc == -ENOENT)
 			tuner_err("Error: firmware %s not found.\n",
-				   priv->ctrl.fname);
+				   fname);
 		else
 			tuner_err("Error %d while requesting firmware %s \n",
-				   rc, priv->ctrl.fname);
+				   rc, fname);
 
 		return rc;
 	}
@@ -276,7 +285,7 @@
 
 	if (fw->size < sizeof(name) - 1 + 2 + 2) {
 		tuner_err("Error: firmware file %s has invalid size!\n",
-			  priv->ctrl.fname);
+			  fname);
 		goto corrupt;
 	}
 
@@ -291,7 +300,7 @@
 	p += 2;
 
 	tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n",
-		   n_array, priv->ctrl.fname, name,
+		   n_array, fname, name,
 		   priv->firm_version >> 8, priv->firm_version & 0xff);
 
 	priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL);
@@ -395,9 +404,9 @@
 {
 	struct xc2028_data *priv = fe->tuner_priv;
 	int                 i, best_i = -1, best_nr_matches = 0;
-	unsigned int        ign_firm_type_mask = 0;
+	unsigned int        type_mask = 0;
 
-	tuner_dbg("%s called, want type=", __FUNCTION__);
+	tuner_dbg("%s called, want type=", __func__);
 	if (debug) {
 		dump_firm_type(type);
 		printk("(%x), id %016llx.\n", type, (unsigned long long)*id);
@@ -412,18 +421,23 @@
 		*id = V4L2_STD_PAL;
 
 	if (type & BASE)
-		type &= BASE_TYPES;
+		type_mask = BASE_TYPES;
 	else if (type & SCODE) {
 		type &= SCODE_TYPES;
-		ign_firm_type_mask = HAS_IF;
+		type_mask = SCODE_TYPES & ~HAS_IF;
 	} else if (type & DTV_TYPES)
-		type &= DTV_TYPES;
+		type_mask = DTV_TYPES;
 	else if (type & STD_SPECIFIC_TYPES)
-		type &= STD_SPECIFIC_TYPES;
+		type_mask = STD_SPECIFIC_TYPES;
+
+	type &= type_mask;
+
+	if (!type & SCODE)
+		type_mask = ~0;
 
 	/* Seek for exact match */
 	for (i = 0; i < priv->firm_size; i++) {
-		if ((type == (priv->firm[i].type & ~ign_firm_type_mask)) &&
+		if ((type == (priv->firm[i].type & type_mask)) &&
 		    (*id == priv->firm[i].id))
 			goto found;
 	}
@@ -433,7 +447,7 @@
 		v4l2_std_id match_mask;
 		int nr_matches;
 
-		if (type != (priv->firm[i].type & ~ign_firm_type_mask))
+		if (type != (priv->firm[i].type & type_mask))
 			continue;
 
 		match_mask = *id & priv->firm[i].id;
@@ -483,7 +497,7 @@
 	int                pos, rc;
 	unsigned char      *p, *endp, buf[priv->ctrl.max_len];
 
-	tuner_dbg("%s called\n", __FUNCTION__);
+	tuner_dbg("%s called\n", __func__);
 
 	pos = seek_firmware(fe, type, id);
 	if (pos < 0)
@@ -586,7 +600,7 @@
 	int                pos, rc;
 	unsigned char	   *p;
 
-	tuner_dbg("%s called\n", __FUNCTION__);
+	tuner_dbg("%s called\n", __func__);
 
 	if (!int_freq) {
 		pos = seek_firmware(fe, type, id);
@@ -650,7 +664,7 @@
 	u16			   version, hwmodel;
 	v4l2_std_id		   std0;
 
-	tuner_dbg("%s called\n", __FUNCTION__);
+	tuner_dbg("%s called\n", __func__);
 
 	if (!priv->firm) {
 		if (!priv->ctrl.fname) {
@@ -770,10 +784,10 @@
 		goto fail;
 	}
 
-	tuner_info("Device is Xceive %d version %d.%d, "
-		   "firmware version %d.%d\n",
-		   hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8,
-		   (version & 0xf0) >> 4, version & 0xf);
+	tuner_dbg("Device is Xceive %d version %d.%d, "
+		  "firmware version %d.%d\n",
+		  hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8,
+		  (version & 0xf0) >> 4, version & 0xf);
 
 	/* Check firmware version against what we downloaded. */
 	if (priv->firm_version != ((version & 0xf0) << 4 | (version & 0x0f))) {
@@ -824,27 +838,34 @@
 	u16                 frq_lock, signal = 0;
 	int                 rc;
 
-	tuner_dbg("%s called\n", __FUNCTION__);
+	tuner_dbg("%s called\n", __func__);
 
 	mutex_lock(&priv->lock);
 
 	/* Sync Lock Indicator */
 	rc = xc2028_get_reg(priv, 0x0002, &frq_lock);
-	if (rc < 0 || frq_lock == 0)
+	if (rc < 0)
 		goto ret;
 
-	/* Frequency is locked. Return signal quality */
+	/* Frequency is locked */
+	if (frq_lock == 1)
+		signal = 32768;
 
 	/* Get SNR of the video signal */
 	rc = xc2028_get_reg(priv, 0x0040, &signal);
 	if (rc < 0)
-		signal = -frq_lock;
+		goto ret;
+
+	/* Use both frq_lock and signal to generate the result */
+	signal = signal || ((signal & 0x07) << 12);
 
 ret:
 	mutex_unlock(&priv->lock);
 
 	*strength = signal;
 
+	tuner_dbg("signal strength is %d\n", signal);
+
 	return rc;
 }
 
@@ -861,7 +882,7 @@
 	unsigned char	   buf[4];
 	u32		   div, offset = 0;
 
-	tuner_dbg("%s called\n", __FUNCTION__);
+	tuner_dbg("%s called\n", __func__);
 
 	mutex_lock(&priv->lock);
 
@@ -906,9 +927,11 @@
 	if (rc < 0)
 		goto ret;
 
-	rc = priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1);
-	if (rc < 0)
-		goto ret;
+	/* Return code shouldn't be checked.
+	   The reset CLK is needed only with tm6000.
+	   Driver should work fine even if this fails.
+	 */
+	priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1);
 
 	msleep(10);
 
@@ -942,7 +965,7 @@
 	struct xc2028_data *priv = fe->tuner_priv;
 	unsigned int       type=0;
 
-	tuner_dbg("%s called\n", __FUNCTION__);
+	tuner_dbg("%s called\n", __func__);
 
 	if (p->mode == V4L2_TUNER_RADIO) {
 		type |= FM;
@@ -975,7 +998,7 @@
 	fe_bandwidth_t     bw = BANDWIDTH_8_MHZ;
 	u16                demod = 0;
 
-	tuner_dbg("%s called\n", __FUNCTION__);
+	tuner_dbg("%s called\n", __func__);
 
 	if (priv->ctrl.d2633)
 		type |= D2633;
@@ -1040,33 +1063,12 @@
 				T_DIGITAL_TV, type, 0, demod);
 }
 
-static int xc2028_sleep(struct dvb_frontend *fe)
-{
-	struct xc2028_data *priv = fe->tuner_priv;
-	int rc = 0;
-
-	tuner_dbg("%s called\n", __FUNCTION__);
-
-	mutex_lock(&priv->lock);
-
-	if (priv->firm_version < 0x0202)
-		rc = send_seq(priv, {0x00, 0x08, 0x00, 0x00});
-	else
-		rc = send_seq(priv, {0x80, 0x08, 0x00, 0x00});
-
-	priv->cur_fw.type = 0;	/* need firmware reload */
-
-	mutex_unlock(&priv->lock);
-
-	return rc;
-}
-
 
 static int xc2028_dvb_release(struct dvb_frontend *fe)
 {
 	struct xc2028_data *priv = fe->tuner_priv;
 
-	tuner_dbg("%s called\n", __FUNCTION__);
+	tuner_dbg("%s called\n", __func__);
 
 	mutex_lock(&xc2028_list_mutex);
 
@@ -1091,7 +1093,7 @@
 {
 	struct xc2028_data *priv = fe->tuner_priv;
 
-	tuner_dbg("%s called\n", __FUNCTION__);
+	tuner_dbg("%s called\n", __func__);
 
 	*frequency = priv->frequency;
 
@@ -1104,25 +1106,25 @@
 	struct xc2028_ctrl *p    = priv_cfg;
 	int                 rc   = 0;
 
-	tuner_dbg("%s called\n", __FUNCTION__);
+	tuner_dbg("%s called\n", __func__);
 
 	mutex_lock(&priv->lock);
 
-	kfree(priv->ctrl.fname);
-	free_firmware(priv);
-
 	memcpy(&priv->ctrl, p, sizeof(priv->ctrl));
-	priv->ctrl.fname = NULL;
+	if (priv->ctrl.max_len < 9)
+		priv->ctrl.max_len = 13;
 
 	if (p->fname) {
+		if (priv->ctrl.fname && strcmp(p->fname, priv->ctrl.fname)) {
+			kfree(priv->ctrl.fname);
+			free_firmware(priv);
+		}
+
 		priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL);
 		if (priv->ctrl.fname == NULL)
 			rc = -ENOMEM;
 	}
 
-	if (priv->ctrl.max_len < 9)
-		priv->ctrl.max_len = 13;
-
 	mutex_unlock(&priv->lock);
 
 	return rc;
@@ -1142,8 +1144,6 @@
 	.get_frequency     = xc2028_get_frequency,
 	.get_rf_strength   = xc2028_signal,
 	.set_params        = xc2028_set_params,
-	.sleep             = xc2028_sleep,
-
 };
 
 struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
@@ -1153,23 +1153,29 @@
 	void               *video_dev;
 
 	if (debug)
-		printk(KERN_DEBUG PREFIX ": Xcv2028/3028 init called!\n");
+		printk(KERN_DEBUG "xc2028: Xcv2028/3028 init called!\n");
 
-	if (NULL == cfg || NULL == cfg->video_dev)
+	if (NULL == cfg)
 		return NULL;
 
 	if (!fe) {
-		printk(KERN_ERR PREFIX ": No frontend!\n");
+		printk(KERN_ERR "xc2028: No frontend!\n");
 		return NULL;
 	}
 
-	video_dev = cfg->video_dev;
+	video_dev = cfg->i2c_adap->algo_data;
+
+	if (debug)
+		printk(KERN_DEBUG "xc2028: video_dev =%p\n", video_dev);
 
 	mutex_lock(&xc2028_list_mutex);
 
 	list_for_each_entry(priv, &xc2028_list, xc2028_list) {
-		if (priv->video_dev == cfg->video_dev) {
+		if (&priv->i2c_props.adap->dev == &cfg->i2c_adap->dev) {
 			video_dev = NULL;
+			if (debug)
+				printk(KERN_DEBUG "xc2028: reusing device\n");
+
 			break;
 		}
 	}
@@ -1183,6 +1189,8 @@
 
 		priv->i2c_props.addr = cfg->i2c_addr;
 		priv->i2c_props.adap = cfg->i2c_adap;
+		priv->i2c_props.name = "xc2028";
+
 		priv->video_dev = video_dev;
 		priv->tuner_callback = cfg->callback;
 		priv->ctrl.max_len = 13;
@@ -1195,6 +1203,9 @@
 	fe->tuner_priv = priv;
 	priv->count++;
 
+	if (debug)
+		printk(KERN_DEBUG "xc2028: usage count is %i\n", priv->count);
+
 	memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops,
 	       sizeof(xc2028_dvb_tuner_ops));
 
diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/video/tuner-xc2028.h
index 3eb8420..fc2f132 100644
--- a/drivers/media/video/tuner-xc2028.h
+++ b/drivers/media/video/tuner-xc2028.h
@@ -1,6 +1,6 @@
 /* tuner-xc2028
  *
- * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org)
  * This code is placed under the terms of the GNU General Public License v2
  */
 
@@ -12,7 +12,7 @@
 #define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw"
 
 /*      Dmoduler		IF (kHz) */
-#define	XC3028_FE_DEFAULT	0
+#define	XC3028_FE_DEFAULT	0		/* Don't load SCODE */
 #define XC3028_FE_LG60		6000
 #define	XC3028_FE_ATI638	6380
 #define	XC3028_FE_OREN538	5380
@@ -55,7 +55,7 @@
 						 struct xc2028_config *cfg)
 {
 	printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
-	       __FUNCTION__);
+	       __func__);
 	return NULL;
 }
 #endif
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index 01ebcec..f29a2cd 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -38,7 +38,7 @@
 /* ---------------------------------------------------------------------- */
 /* insmod args                                                            */
 
-static int debug = 0;	/* insmod parameter */
+static int debug;	/* insmod parameter */
 module_param(debug, int, 0644);
 
 MODULE_DESCRIPTION("device driver for various i2c TV sound decoder / audiomux chips");
@@ -1235,11 +1235,11 @@
 static int tda9855  = 1;
 static int tda9873  = 1;
 static int tda9874a = 1;
-static int tea6300  = 0;  /* address clash with msp34xx */
-static int tea6320  = 0;  /* address clash with msp34xx */
+static int tea6300;	/* default 0 - address clash with msp34xx */
+static int tea6320;	/* default 0 - address clash with msp34xx */
 static int tea6420  = 1;
 static int pic16c54 = 1;
-static int ta8874z  = 0;  /* address clash with tda9840 */
+static int ta8874z;	/* default 0 - address clash with tda9840 */
 
 module_param(tda8425, int, 0444);
 module_param(tda9840, int, 0444);
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index dc0da44..3cf8a8e 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -745,109 +745,6 @@
 }
 EXPORT_SYMBOL(tveeprom_read);
 
-/* ----------------------------------------------------------------------- */
-/* needed for ivtv.sf.net at the moment.  Should go away in the long       */
-/* run, just call the exported tveeprom_* directly, there is no point in   */
-/* using the indirect way via i2c_driver->command()                        */
-
-static unsigned short normal_i2c[] = {
-	0xa0 >> 1,
-	I2C_CLIENT_END,
-};
-
-I2C_CLIENT_INSMOD;
-
-static struct i2c_driver i2c_driver_tveeprom;
-
-static int
-tveeprom_command(struct i2c_client *client,
-		 unsigned int       cmd,
-		 void              *arg)
-{
-	struct tveeprom eeprom;
-	u32 *eeprom_props = arg;
-	u8 *buf;
-
-	switch (cmd) {
-	case 0:
-		buf = kzalloc(256, GFP_KERNEL);
-		tveeprom_read(client, buf, 256);
-		tveeprom_hauppauge_analog(client, &eeprom, buf);
-		kfree(buf);
-		eeprom_props[0] = eeprom.tuner_type;
-		eeprom_props[1] = eeprom.tuner_formats;
-		eeprom_props[2] = eeprom.model;
-		eeprom_props[3] = eeprom.revision;
-		eeprom_props[4] = eeprom.has_radio;
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static int
-tveeprom_detect_client(struct i2c_adapter *adapter,
-		       int                 address,
-		       int                 kind)
-{
-	struct i2c_client *client;
-
-	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-	if (NULL == client)
-		return -ENOMEM;
-	client->addr = address;
-	client->adapter = adapter;
-	client->driver = &i2c_driver_tveeprom;
-	snprintf(client->name, sizeof(client->name), "tveeprom");
-	i2c_attach_client(client);
-
-	return 0;
-}
-
-static int
-tveeprom_attach_adapter(struct i2c_adapter *adapter)
-{
-	if (adapter->class & I2C_CLASS_TV_ANALOG)
-		return i2c_probe(adapter, &addr_data, tveeprom_detect_client);
-	return 0;
-}
-
-static int
-tveeprom_detach_client(struct i2c_client *client)
-{
-	int err;
-
-	err = i2c_detach_client(client);
-	if (err < 0)
-		return err;
-	kfree(client);
-	return 0;
-}
-
-static struct i2c_driver i2c_driver_tveeprom = {
-	.driver = {
-		.name   = "tveeprom",
-	},
-	.id             = I2C_DRIVERID_TVEEPROM,
-	.attach_adapter = tveeprom_attach_adapter,
-	.detach_client  = tveeprom_detach_client,
-	.command        = tveeprom_command,
-};
-
-static int __init tveeprom_init(void)
-{
-	return i2c_add_driver(&i2c_driver_tveeprom);
-}
-
-static void __exit tveeprom_exit(void)
-{
-	i2c_del_driver(&i2c_driver_tveeprom);
-}
-
-module_init(tveeprom_init);
-module_exit(tveeprom_exit);
-
 /*
  * Local variables:
  * c-basic-offset: 8
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
index b6e24e7..6a3af10 100644
--- a/drivers/media/video/tvp5150.c
+++ b/drivers/media/video/tvp5150.c
@@ -27,7 +27,7 @@
 
 I2C_CLIENT_INSMOD;
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
diff --git a/drivers/media/video/usbvideo/ibmcam.c b/drivers/media/video/usbvideo/ibmcam.c
index 14db95e..59166b7 100644
--- a/drivers/media/video/usbvideo/ibmcam.c
+++ b/drivers/media/video/usbvideo/ibmcam.c
@@ -121,7 +121,7 @@
 
 /* 01.01.08 - Added for RCA video in support -LO */
 /* Settings for camera model 3 */
-static int init_model3_input = 0;
+static int init_model3_input;
 
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
@@ -802,6 +802,21 @@
 		return scan_Continue;
 }
 
+/*
+ * ibmcam_model3_parse_lines()
+ *
+ * | Even lines |     Odd Lines       |
+ * -----------------------------------|
+ * |YYY........Y|UYVYUYVY.........UYVY|
+ * |YYY........Y|UYVYUYVY.........UYVY|
+ * |............|.....................|
+ * |YYY........Y|UYVYUYVY.........UYVY|
+ * |------------+---------------------|
+ *
+ * There is one (U, V) chroma pair for every four luma (Y) values.  This
+ * function reads a pair of lines at a time and obtains missing chroma values
+ * from adjacent pixels.
+ */
 static enum ParseState ibmcam_model3_parse_lines(
 	struct uvd *uvd,
 	struct usbvideo_frame *frame,
@@ -816,6 +831,7 @@
 	const int ccm = 128; /* Color correction median - see below */
 	int i, u, v, rw, data_w=0, data_h=0, color_corr;
 	static unsigned char lineBuffer[640*3];
+	int line;
 
 	color_corr = (uvd->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
 	RESTRICT_TO_RANGE(color_corr, -ccm, ccm+1);
@@ -869,15 +885,15 @@
 		return scan_NextFrame;
 	}
 
-	/* Make sure there's enough data for the entire line */
-	len = 3 * data_w; /* <y-data> <uv-data> */
+	/* Make sure that lineBuffer can store two lines of data */
+	len = 3 * data_w; /* <y-data> <uyvy-data> */
 	assert(len <= sizeof(lineBuffer));
 
-	/* Make sure there's enough data for the entire line */
+	/* Make sure there's enough data for two lines */
 	if (RingQueue_GetLength(&uvd->dp) < len)
 		return scan_Out;
 
-	/* Suck one line out of the ring queue */
+	/* Suck two lines of data out of the ring queue */
 	RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
 
 	data = lineBuffer;
@@ -887,15 +903,23 @@
 	rw = (int)VIDEOSIZE_Y(frame->request) - (int)(frame->curline) - 1;
 	RESTRICT_TO_RANGE(rw, 0, VIDEOSIZE_Y(frame->request)-1);
 
-	for (i = 0; i < VIDEOSIZE_X(frame->request); i++) {
-		int y, rv, gv, bv;	/* RGB components */
+	/* Iterate over two lines. */
+	for (line = 0; line < 2; line++) {
+		for (i = 0; i < VIDEOSIZE_X(frame->request); i++) {
+			int y;
+			int rv, gv, bv;	/* RGB components */
 
-		if (i < data_w) {
-			y = data[i];	/* Luminosity is the first line */
+			if (i >= data_w) {
+				RGB24_PUTPIXEL(frame, i, rw, 0, 0, 0);
+				continue;
+			}
+
+			/* first line is YYY...Y; second is UYVY...UYVY */
+			y = data[(line == 0) ? i : (i*2 + 1)];
 
 			/* Apply static color correction */
-			u = color[i*2] + hue_corr;
-			v = color[i*2 + 1] + hue2_corr;
+			u = color[(i/2)*4] + hue_corr;
+			v = color[(i/2)*4 + 2] + hue2_corr;
 
 			/* Apply color correction */
 			if (color_corr != 0) {
@@ -903,13 +927,21 @@
 				u = 128 + ((ccm + color_corr) * (u - 128)) / ccm;
 				v = 128 + ((ccm + color_corr) * (v - 128)) / ccm;
 			}
-		} else
-			y = 0, u = v = 128;
 
-		YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv);
-		RGB24_PUTPIXEL(frame, i, rw, rv, gv, bv); /* Done by deinterlacing now */
+
+			YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv);
+			RGB24_PUTPIXEL(frame, i, rw, rv, gv, bv);  /* No deinterlacing */
+		}
+
+		/* Check for the end of requested data */
+		if (rw == 0)
+			break;
+
+		/* Prepare for the second line */
+		rw--;
+		data = lineBuffer + data_w;
 	}
-	frame->deinterlace = Deinterlace_FillEvenLines;
+	frame->deinterlace = Deinterlace_None;
 
 	/*
 	 * Account for number of bytes that we wrote into output V4L frame.
diff --git a/drivers/media/video/usbvideo/konicawc.c b/drivers/media/video/usbvideo/konicawc.c
index 719b17c..1c18028 100644
--- a/drivers/media/video/usbvideo/konicawc.c
+++ b/drivers/media/video/usbvideo/konicawc.c
@@ -57,11 +57,11 @@
 static int debug;
 #define DEBUG(n, format, arg...) \
 	if (n <= debug) {	 \
-		printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \
+		printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __func__ , ## arg); \
 	}
 #else
 #define DEBUG(n, arg...)
-static const int debug = 0;
+static const int debug;
 #endif
 
 
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c
index a2acba0..32e536e 100644
--- a/drivers/media/video/usbvideo/quickcam_messenger.c
+++ b/drivers/media/video/usbvideo/quickcam_messenger.c
@@ -46,11 +46,11 @@
 static int debug;
 #define DEBUG(n, format, arg...) \
 	if (n <= debug) {	 \
-		printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \
+		printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __func__ , ## arg); \
 	}
 #else
 #define DEBUG(n, arg...)
-static const int debug = 0;
+static const int debug;
 #endif
 
 #define DRIVER_VERSION "v0.01"
diff --git a/drivers/media/video/usbvideo/ultracam.c b/drivers/media/video/usbvideo/ultracam.c
index 95453c1..9544e64 100644
--- a/drivers/media/video/usbvideo/ultracam.c
+++ b/drivers/media/video/usbvideo/ultracam.c
@@ -28,9 +28,9 @@
 
 static struct usbvideo *cams = NULL;
 
-static int debug = 0;
+static int debug;
 
-static int flags = 0; /* FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */
+static int flags; /* FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */
 
 static const int min_canvasWidth  = 8;
 static const int min_canvasHeight = 4;
diff --git a/drivers/media/video/usbvideo/usbvideo.c b/drivers/media/video/usbvideo/usbvideo.c
index 5d363be..4128ee2 100644
--- a/drivers/media/video/usbvideo/usbvideo.c
+++ b/drivers/media/video/usbvideo/usbvideo.c
@@ -522,14 +522,14 @@
 	struct usbvideo_frame *frame;
 	int num_cell = 0;
 	int scan_length = 0;
-	static int num_pass = 0;
+	static int num_pass;
 
 	if (uvd == NULL) {
-		err("%s: uvd == NULL", __FUNCTION__);
+		err("%s: uvd == NULL", __func__);
 		return;
 	}
 	if ((uvd->curframe < 0) || (uvd->curframe >= USBVIDEO_NUMFRAMES)) {
-		err("%s: uvd->curframe=%d.", __FUNCTION__, uvd->curframe);
+		err("%s: uvd->curframe=%d.", __func__, uvd->curframe);
 		return;
 	}
 
@@ -630,15 +630,15 @@
 static int usbvideo_ClientIncModCount(struct uvd *uvd)
 {
 	if (uvd == NULL) {
-		err("%s: uvd == NULL", __FUNCTION__);
+		err("%s: uvd == NULL", __func__);
 		return -EINVAL;
 	}
 	if (uvd->handle == NULL) {
-		err("%s: uvd->handle == NULL", __FUNCTION__);
+		err("%s: uvd->handle == NULL", __func__);
 		return -EINVAL;
 	}
 	if (!try_module_get(uvd->handle->md_module)) {
-		err("%s: try_module_get() == 0", __FUNCTION__);
+		err("%s: try_module_get() == 0", __func__);
 		return -ENODEV;
 	}
 	return 0;
@@ -647,15 +647,15 @@
 static void usbvideo_ClientDecModCount(struct uvd *uvd)
 {
 	if (uvd == NULL) {
-		err("%s: uvd == NULL", __FUNCTION__);
+		err("%s: uvd == NULL", __func__);
 		return;
 	}
 	if (uvd->handle == NULL) {
-		err("%s: uvd->handle == NULL", __FUNCTION__);
+		err("%s: uvd->handle == NULL", __func__);
 		return;
 	}
 	if (uvd->handle->md_module == NULL) {
-		err("%s: uvd->handle->md_module == NULL", __FUNCTION__);
+		err("%s: uvd->handle->md_module == NULL", __func__);
 		return;
 	}
 	module_put(uvd->handle->md_module);
@@ -675,13 +675,13 @@
 
 	/* Check parameters for sanity */
 	if ((num_cams <= 0) || (pCams == NULL) || (cbTbl == NULL)) {
-		err("%s: Illegal call", __FUNCTION__);
+		err("%s: Illegal call", __func__);
 		return -EINVAL;
 	}
 
 	/* Check registration callback - must be set! */
 	if (cbTbl->probe == NULL) {
-		err("%s: probe() is required!", __FUNCTION__);
+		err("%s: probe() is required!", __func__);
 		return -EINVAL;
 	}
 
@@ -692,7 +692,7 @@
 		return -ENOMEM;
 	}
 	dbg("%s: Allocated $%p (%d. bytes) for %d. cameras",
-	    __FUNCTION__, cams, base_size, num_cams);
+	    __func__, cams, base_size, num_cams);
 
 	/* Copy callbacks, apply defaults for those that are not set */
 	memmove(&cams->cb, cbTbl, sizeof(cams->cb));
@@ -721,7 +721,7 @@
 			up->user_data = kmalloc(up->user_size, GFP_KERNEL);
 			if (up->user_data == NULL) {
 				err("%s: Failed to allocate user_data (%d. bytes)",
-				    __FUNCTION__, up->user_size);
+				    __func__, up->user_size);
 				while (i) {
 					up = &cams->cam[--i];
 					kfree(up->user_data);
@@ -730,7 +730,7 @@
 				return -ENOMEM;
 			}
 			dbg("%s: Allocated cams[%d].user_data=$%p (%d. bytes)",
-			     __FUNCTION__, i, up->user_data, up->user_size);
+			     __func__, i, up->user_data, up->user_size);
 		}
 	}
 
@@ -776,19 +776,19 @@
 	int i;
 
 	if (pCams == NULL) {
-		err("%s: pCams == NULL", __FUNCTION__);
+		err("%s: pCams == NULL", __func__);
 		return;
 	}
 	cams = *pCams;
 	if (cams == NULL) {
-		err("%s: cams == NULL", __FUNCTION__);
+		err("%s: cams == NULL", __func__);
 		return;
 	}
 
-	dbg("%s: Deregistering %s driver.", __FUNCTION__, cams->drvName);
+	dbg("%s: Deregistering %s driver.", __func__, cams->drvName);
 	usb_deregister(&cams->usbdrv);
 
-	dbg("%s: Deallocating cams=$%p (%d. cameras)", __FUNCTION__, cams, cams->num_cameras);
+	dbg("%s: Deallocating cams=$%p (%d. cameras)", __func__, cams, cams->num_cameras);
 	for (i=0; i < cams->num_cameras; i++) {
 		struct uvd *up = &cams->cam[i];
 		int warning = 0;
@@ -802,16 +802,16 @@
 		}
 		if (warning) {
 			err("%s: Warning: user_data=$%p user_size=%d.",
-			    __FUNCTION__, up->user_data, up->user_size);
+			    __func__, up->user_data, up->user_size);
 		} else {
 			dbg("%s: Freeing %d. $%p->user_data=$%p",
-			    __FUNCTION__, i, up, up->user_data);
+			    __func__, i, up, up->user_data);
 			kfree(up->user_data);
 		}
 	}
 	/* Whole array was allocated in one chunk */
 	dbg("%s: Freed %d uvd structures",
-	    __FUNCTION__, cams->num_cameras);
+	    __func__, cams->num_cameras);
 	kfree(cams);
 	*pCams = NULL;
 }
@@ -846,7 +846,7 @@
 	int i;
 
 	if (uvd == NULL) {
-		err("%s($%p): Illegal call.", __FUNCTION__, intf);
+		err("%s($%p): Illegal call.", __func__, intf);
 		return;
 	}
 
@@ -854,7 +854,7 @@
 
 	usbvideo_ClientIncModCount(uvd);
 	if (uvd->debug > 0)
-		info("%s(%p.)", __FUNCTION__, intf);
+		info("%s(%p.)", __func__, intf);
 
 	mutex_lock(&uvd->lock);
 	uvd->remove_pending = 1; /* Now all ISO data will be ignored */
@@ -870,10 +870,10 @@
 
 	video_unregister_device(&uvd->vdev);
 	if (uvd->debug > 0)
-		info("%s: Video unregistered.", __FUNCTION__);
+		info("%s: Video unregistered.", __func__);
 
 	if (uvd->user)
-		info("%s: In use, disconnect pending.", __FUNCTION__);
+		info("%s: In use, disconnect pending.", __func__);
 	else
 		usbvideo_CameraRelease(uvd);
 	mutex_unlock(&uvd->lock);
@@ -895,7 +895,7 @@
 static void usbvideo_CameraRelease(struct uvd *uvd)
 {
 	if (uvd == NULL) {
-		err("%s: Illegal call", __FUNCTION__);
+		err("%s: Illegal call", __func__);
 		return;
 	}
 
@@ -946,7 +946,9 @@
 	.read =   usbvideo_v4l_read,
 	.mmap =   usbvideo_v4l_mmap,
 	.ioctl =  usbvideo_v4l_ioctl,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl = v4l_compat_ioctl32,
+#endif
 	.llseek = no_llseek,
 };
 static const struct video_device usbvideo_template = {
@@ -1011,18 +1013,18 @@
 	char tmp1[20], tmp2[20];	/* Buffers for printing */
 
 	if (uvd == NULL) {
-		err("%s: Illegal call.", __FUNCTION__);
+		err("%s: Illegal call.", __func__);
 		return -EINVAL;
 	}
 	if (uvd->video_endp == 0) {
-		info("%s: No video endpoint specified; data pump disabled.", __FUNCTION__);
+		info("%s: No video endpoint specified; data pump disabled.", __func__);
 	}
 	if (uvd->paletteBits == 0) {
-		err("%s: No palettes specified!", __FUNCTION__);
+		err("%s: No palettes specified!", __func__);
 		return -EINVAL;
 	}
 	if (uvd->defaultPalette == 0) {
-		info("%s: No default palette!", __FUNCTION__);
+		info("%s: No default palette!", __func__);
 	}
 
 	uvd->max_frame_size = VIDEOSIZE_X(uvd->canvas) *
@@ -1032,19 +1034,19 @@
 
 	if (uvd->debug > 0) {
 		info("%s: iface=%d. endpoint=$%02x paletteBits=$%08lx",
-		     __FUNCTION__, uvd->iface, uvd->video_endp, uvd->paletteBits);
+		     __func__, uvd->iface, uvd->video_endp, uvd->paletteBits);
 	}
 	if (uvd->dev == NULL) {
-		err("%s: uvd->dev == NULL", __FUNCTION__);
+		err("%s: uvd->dev == NULL", __func__);
 		return -EINVAL;
 	}
-	uvd->vdev.dev=&(uvd->dev->dev);
+	uvd->vdev.dev = &uvd->dev->dev;
 	if (video_register_device(&uvd->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
-		err("%s: video_register_device failed", __FUNCTION__);
+		err("%s: video_register_device failed", __func__);
 		return -EPIPE;
 	}
 	if (uvd->debug > 1) {
-		info("%s: video_register_device() successful", __FUNCTION__);
+		info("%s: video_register_device() successful", __func__);
 	}
 
 	info("%s on /dev/video%d: canvas=%s videosize=%s",
@@ -1111,14 +1113,14 @@
 	int i, errCode = 0;
 
 	if (uvd->debug > 1)
-		info("%s($%p)", __FUNCTION__, dev);
+		info("%s($%p)", __func__, dev);
 
 	if (0 < usbvideo_ClientIncModCount(uvd))
 		return -ENODEV;
 	mutex_lock(&uvd->lock);
 
 	if (uvd->user) {
-		err("%s: Someone tried to open an already opened device!", __FUNCTION__);
+		err("%s: Someone tried to open an already opened device!", __func__);
 		errCode = -EBUSY;
 	} else {
 		/* Clear statistics */
@@ -1134,7 +1136,7 @@
 		RingQueue_Allocate(&uvd->dp, RING_QUEUE_SIZE);
 		if ((uvd->fbuf == NULL) ||
 		    (!RingQueue_IsAllocated(&uvd->dp))) {
-			err("%s: Failed to allocate fbuf or dp", __FUNCTION__);
+			err("%s: Failed to allocate fbuf or dp", __func__);
 			errCode = -ENOMEM;
 		} else {
 			/* Allocate all buffers */
@@ -1178,19 +1180,19 @@
 		if (errCode == 0) {
 			if (VALID_CALLBACK(uvd, setupOnOpen)) {
 				if (uvd->debug > 1)
-					info("%s: setupOnOpen callback", __FUNCTION__);
+					info("%s: setupOnOpen callback", __func__);
 				errCode = GET_CALLBACK(uvd, setupOnOpen)(uvd);
 				if (errCode < 0) {
 					err("%s: setupOnOpen callback failed (%d.).",
-					    __FUNCTION__, errCode);
+					    __func__, errCode);
 				} else if (uvd->debug > 1) {
-					info("%s: setupOnOpen callback successful", __FUNCTION__);
+					info("%s: setupOnOpen callback successful", __func__);
 				}
 			}
 			if (errCode == 0) {
 				uvd->settingsAdjusted = 0;
 				if (uvd->debug > 1)
-					info("%s: Open succeeded.", __FUNCTION__);
+					info("%s: Open succeeded.", __func__);
 				uvd->user++;
 				file->private_data = uvd;
 			}
@@ -1200,7 +1202,7 @@
 	if (errCode != 0)
 		usbvideo_ClientDecModCount(uvd);
 	if (uvd->debug > 0)
-		info("%s: Returning %d.", __FUNCTION__, errCode);
+		info("%s: Returning %d.", __func__, errCode);
 	return errCode;
 }
 
@@ -1223,7 +1225,7 @@
 	int i;
 
 	if (uvd->debug > 1)
-		info("%s($%p)", __FUNCTION__, dev);
+		info("%s($%p)", __func__, dev);
 
 	mutex_lock(&uvd->lock);
 	GET_CALLBACK(uvd, stopDataPump)(uvd);
@@ -1250,7 +1252,7 @@
 	usbvideo_ClientDecModCount(uvd);
 
 	if (uvd->debug > 1)
-		info("%s: Completed.", __FUNCTION__);
+		info("%s: Completed.", __func__);
 	file->private_data = NULL;
 	return 0;
 }
@@ -1504,7 +1506,7 @@
 		return -EFAULT;
 
 	if (uvd->debug >= 1)
-		info("%s: %Zd. bytes, noblock=%d.", __FUNCTION__, count, noblock);
+		info("%s: %Zd. bytes, noblock=%d.", __func__, count, noblock);
 
 	mutex_lock(&uvd->lock);
 
@@ -1551,7 +1553,7 @@
 	 */
 	if (frmx == -1) {
 		if (uvd->defaultPalette == 0) {
-			err("%s: No default palette; don't know what to do!", __FUNCTION__);
+			err("%s: No default palette; don't know what to do!", __func__);
 			count = -EFAULT;
 			goto read_done;
 		}
@@ -1623,7 +1625,7 @@
 	frame->seqRead_Index += count;
 	if (uvd->debug >= 1) {
 		err("%s: {copy} count used=%Zd, new seqRead_Index=%ld",
-			__FUNCTION__, count, frame->seqRead_Index);
+			__func__, count, frame->seqRead_Index);
 	}
 
 	/* Finally check if the frame is done with and "release" it */
@@ -1634,7 +1636,7 @@
 		/* Mark it as available to be used again. */
 		uvd->frame[frmx].frameState = FrameState_Unused;
 		if (usbvideo_NewFrame(uvd, (frmx + 1) % USBVIDEO_NUMFRAMES)) {
-			err("%s: usbvideo_NewFrame failed.", __FUNCTION__);
+			err("%s: usbvideo_NewFrame failed.", __func__);
 		}
 	}
 read_done:
@@ -1741,10 +1743,10 @@
 	int i, errFlag;
 
 	if (uvd->debug > 1)
-		info("%s($%p)", __FUNCTION__, uvd);
+		info("%s($%p)", __func__, uvd);
 
 	if (!CAMERA_IS_OPERATIONAL(uvd)) {
-		err("%s: Camera is not operational", __FUNCTION__);
+		err("%s: Camera is not operational", __func__);
 		return -EFAULT;
 	}
 	uvd->curframe = -1;
@@ -1752,14 +1754,14 @@
 	/* Alternate interface 1 is is the biggest frame size */
 	i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive);
 	if (i < 0) {
-		err("%s: usb_set_interface error", __FUNCTION__);
+		err("%s: usb_set_interface error", __func__);
 		uvd->last_error = i;
 		return -EBUSY;
 	}
 	if (VALID_CALLBACK(uvd, videoStart))
 		GET_CALLBACK(uvd, videoStart)(uvd);
 	else
-		err("%s: videoStart not set", __FUNCTION__);
+		err("%s: videoStart not set", __func__);
 
 	/* We double buffer the Iso lists */
 	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
@@ -1784,12 +1786,12 @@
 	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
 		errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
 		if (errFlag)
-			err("%s: usb_submit_isoc(%d) ret %d", __FUNCTION__, i, errFlag);
+			err("%s: usb_submit_isoc(%d) ret %d", __func__, i, errFlag);
 	}
 
 	uvd->streaming = 1;
 	if (uvd->debug > 1)
-		info("%s: streaming=1 video_endp=$%02x", __FUNCTION__, uvd->video_endp);
+		info("%s: streaming=1 video_endp=$%02x", __func__, uvd->video_endp);
 	return 0;
 }
 
@@ -1811,14 +1813,14 @@
 		return;
 
 	if (uvd->debug > 1)
-		info("%s($%p)", __FUNCTION__, uvd);
+		info("%s($%p)", __func__, uvd);
 
 	/* Unschedule all of the iso td's */
 	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
 		usb_kill_urb(uvd->sbuf[i].urb);
 	}
 	if (uvd->debug > 1)
-		info("%s: streaming=0", __FUNCTION__);
+		info("%s: streaming=0", __func__);
 	uvd->streaming = 0;
 
 	if (!uvd->remove_pending) {
@@ -1826,12 +1828,12 @@
 		if (VALID_CALLBACK(uvd, videoStop))
 			GET_CALLBACK(uvd, videoStop)(uvd);
 		else
-			err("%s: videoStop not set", __FUNCTION__);
+			err("%s: videoStop not set", __func__);
 
 		/* Set packet size to 0 */
 		j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive);
 		if (j < 0) {
-			err("%s: usb_set_interface() error %d.", __FUNCTION__, j);
+			err("%s: usb_set_interface() error %d.", __func__, j);
 			uvd->last_error = j;
 		}
 	}
@@ -1955,12 +1957,12 @@
 	struct usbvideo_frame *frame = &uvd->frame[frameNum];
 
 	if (uvd->debug >= 2)
-		info("%s($%p,%d.)", __FUNCTION__, uvd, frameNum);
+		info("%s($%p,%d.)", __func__, uvd, frameNum);
 
 	switch (frame->frameState) {
 	case FrameState_Unused:
 		if (uvd->debug >= 2)
-			info("%s: FrameState_Unused", __FUNCTION__);
+			info("%s: FrameState_Unused", __func__);
 		return -EINVAL;
 	case FrameState_Ready:
 	case FrameState_Grabbing:
@@ -1970,7 +1972,7 @@
 	redo:
 		if (!CAMERA_IS_OPERATIONAL(uvd)) {
 			if (uvd->debug >= 2)
-				info("%s: Camera is not operational (1)", __FUNCTION__);
+				info("%s: Camera is not operational (1)", __func__);
 			return -EIO;
 		}
 		ntries = 0;
@@ -1979,24 +1981,24 @@
 			signalPending = signal_pending(current);
 			if (!CAMERA_IS_OPERATIONAL(uvd)) {
 				if (uvd->debug >= 2)
-					info("%s: Camera is not operational (2)", __FUNCTION__);
+					info("%s: Camera is not operational (2)", __func__);
 				return -EIO;
 			}
 			assert(uvd->fbuf != NULL);
 			if (signalPending) {
 				if (uvd->debug >= 2)
-					info("%s: Signal=$%08x", __FUNCTION__, signalPending);
+					info("%s: Signal=$%08x", __func__, signalPending);
 				if (uvd->flags & FLAGS_RETRY_VIDIOCSYNC) {
 					usbvideo_TestPattern(uvd, 1, 0);
 					uvd->curframe = -1;
 					uvd->stats.frame_num++;
 					if (uvd->debug >= 2)
-						info("%s: Forced test pattern screen", __FUNCTION__);
+						info("%s: Forced test pattern screen", __func__);
 					return 0;
 				} else {
 					/* Standard answer: Interrupted! */
 					if (uvd->debug >= 2)
-						info("%s: Interrupted!", __FUNCTION__);
+						info("%s: Interrupted!", __func__);
 					return -EINTR;
 				}
 			} else {
@@ -2006,17 +2008,17 @@
 				else if (VALID_CALLBACK(uvd, processData))
 					GET_CALLBACK(uvd, processData)(uvd, frame);
 				else
-					err("%s: processData not set", __FUNCTION__);
+					err("%s: processData not set", __func__);
 			}
 		} while (frame->frameState == FrameState_Grabbing);
 		if (uvd->debug >= 2) {
 			info("%s: Grabbing done; state=%d. (%lu. bytes)",
-			     __FUNCTION__, frame->frameState, frame->seqRead_Length);
+			     __func__, frame->frameState, frame->seqRead_Length);
 		}
 		if (frame->frameState == FrameState_Error) {
 			int ret = usbvideo_NewFrame(uvd, frameNum);
 			if (ret < 0) {
-				err("%s: usbvideo_NewFrame() failed (%d.)", __FUNCTION__, ret);
+				err("%s: usbvideo_NewFrame() failed (%d.)", __func__, ret);
 				return ret;
 			}
 			goto redo;
@@ -2048,7 +2050,7 @@
 		}
 		frame->frameState = FrameState_Done_Hold;
 		if (uvd->debug >= 2)
-			info("%s: Entered FrameState_Done_Hold state.", __FUNCTION__);
+			info("%s: Entered FrameState_Done_Hold state.", __func__);
 		return 0;
 
 	case FrameState_Done_Hold:
@@ -2059,12 +2061,12 @@
 		 * it will be released back into the wild to roam freely.
 		 */
 		if (uvd->debug >= 2)
-			info("%s: FrameState_Done_Hold state.", __FUNCTION__);
+			info("%s: FrameState_Done_Hold state.", __func__);
 		return 0;
 	}
 
 	/* Catch-all for other cases. We shall not be here. */
-	err("%s: Invalid state %d.", __FUNCTION__, frame->frameState);
+	err("%s: Invalid state %d.", __func__, frame->frameState);
 	frame->frameState = FrameState_Unused;
 	return 0;
 }
@@ -2160,7 +2162,7 @@
 	const int ccm = 128; /* Color correction median - see below */
 
 	if ((uvd == NULL) || (frame == NULL)) {
-		err("%s: Illegal call.", __FUNCTION__);
+		err("%s: Illegal call.", __func__);
 		return;
 	}
 	adj = (uvd->vpic.contrast - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c
index da1ba02..6481935 100644
--- a/drivers/media/video/usbvideo/vicam.c
+++ b/drivers/media/video/usbvideo/vicam.c
@@ -48,7 +48,7 @@
 // #define VICAM_DEBUG
 
 #ifdef VICAM_DEBUG
-#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __FUNCTION__, lineno, ##args)
+#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __func__, lineno, ##args)
 #define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args)
 #else
 #define DBG(fmn,args...) do {} while(0)
@@ -1066,7 +1066,9 @@
 	.read		= vicam_read,
 	.mmap		= vicam_mmap,
 	.ioctl		= vicam_ioctl,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
+#endif
 	.llseek		= no_llseek,
 };
 
diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c
index 56775ab..a9c5e5a 100644
--- a/drivers/media/video/usbvision/usbvision-core.c
+++ b/drivers/media/video/usbvision/usbvision-core.c
@@ -53,19 +53,21 @@
 
 #include "usbvision.h"
 
-static unsigned int core_debug = 0;
+static unsigned int core_debug;
 module_param(core_debug,int,0644);
 MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
 
-static unsigned int force_testpattern = 0;
+static unsigned int force_testpattern;
 module_param(force_testpattern,int,0644);
 MODULE_PARM_DESC(force_testpattern,"enable test pattern display [core]");
 
-static int adjustCompression = 1;			// Set the compression to be adaptive
+static int adjustCompression = 1;	/* Set the compression to be adaptive */
 module_param(adjustCompression, int, 0444);
 MODULE_PARM_DESC(adjustCompression, " Set the ADPCM compression for the device.  Default: 1 (On)");
 
-static int SwitchSVideoInput = 0;			// To help people with Black and White output with using s-video input.  Some cables and input device are wired differently.
+/* To help people with Black and White output with using s-video input.
+ * Some cables and input device are wired differently. */
+static int SwitchSVideoInput;
 module_param(SwitchSVideoInput, int, 0444);
 MODULE_PARM_DESC(SwitchSVideoInput, " Set the S-Video input.  Some cables and input device are wired differently. Default: 0 (Off)");
 
@@ -82,8 +84,10 @@
 
 
 #ifdef USBVISION_DEBUG
-	#define PDEBUG(level, fmt, args...) \
-		if (core_debug & (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args)
+	#define PDEBUG(level, fmt, args...) { \
+		if (core_debug & (level)) \
+			info("[%s:%d] " fmt, __func__, __LINE__ , ## args); \
+	}
 #else
 	#define PDEBUG(level, fmt, args...) do {} while(0)
 #endif
@@ -384,7 +388,7 @@
 	scratch_reset(usbvision);
 	if(usbvision->scratch == NULL) {
 		err("%s: unable to allocate %d bytes for scratch",
-		    __FUNCTION__, scratch_buf_size);
+		    __func__, scratch_buf_size);
 		return -ENOMEM;
 	}
 	return 0;
@@ -418,7 +422,7 @@
 	unsigned char *f;
 	int num_cell = 0;
 	int scan_length = 0;
-	static int num_pass = 0;
+	static int num_pass;
 
 	if (usbvision == NULL) {
 		printk(KERN_ERR "%s: usbvision == NULL\n", proc);
@@ -493,7 +497,8 @@
 	int IFB_size = MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT * 3 / 2;
 	usbvision->IntraFrameBuffer = vmalloc_32(IFB_size);
 	if (usbvision->IntraFrameBuffer == NULL) {
-		err("%s: unable to allocate %d for compr. frame buffer", __FUNCTION__, IFB_size);
+		err("%s: unable to allocate %d for compr. frame buffer",
+		    __func__, IFB_size);
 		return -ENOMEM;
 	}
 	return 0;
@@ -1430,7 +1435,7 @@
 	}
 #if ENABLE_HEXDUMP
 	if (totlen > 0) {
-		static int foo = 0;
+		static int foo;
 		if (foo < 1) {
 			printk(KERN_DEBUG "+%d.\n", usbvision->scratchlen);
 			usbvision_hexdump(data0, (totlen > 64) ? 64 : totlen);
@@ -1516,7 +1521,7 @@
 
 	if(errCode) {
 		err("%s: usb_submit_urb failed: error %d",
-		    __FUNCTION__, errCode);
+		    __func__, errCode);
 	}
 
 	return;
@@ -1547,7 +1552,7 @@
 				0, (__u16) reg, buffer, 1, HZ);
 
 	if (errCode < 0) {
-		err("%s: failed: error %d", __FUNCTION__, errCode);
+		err("%s: failed: error %d", __func__, errCode);
 		return errCode;
 	}
 	return buffer[0];
@@ -1575,7 +1580,7 @@
 				USB_RECIP_ENDPOINT, 0, (__u16) reg, &value, 1, HZ);
 
 	if (errCode < 0) {
-		err("%s: failed: error %d", __FUNCTION__, errCode);
+		err("%s: failed: error %d", __func__, errCode);
 	}
 	return errCode;
 }
@@ -1851,7 +1856,7 @@
 				 0, (__u16) USBVISION_LXSIZE_O, value, 4, HZ);
 
 		if (errCode < 0) {
-			err("%s failed: error %d", __FUNCTION__, errCode);
+			err("%s failed: error %d", __func__, errCode);
 			return errCode;
 		}
 		usbvision->curwidth = usbvision->stretch_width * UsbWidth;
@@ -2237,7 +2242,7 @@
 			     (__u16) USBVISION_DRM_PRM1, value, 8, HZ);
 
 	if (rc < 0) {
-		err("%sERROR=%d", __FUNCTION__, rc);
+		err("%sERROR=%d", __func__, rc);
 		return rc;
 	}
 
@@ -2486,7 +2491,7 @@
 
 		urb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL);
 		if (urb == NULL) {
-			err("%s: usb_alloc_urb() failed", __FUNCTION__);
+			err("%s: usb_alloc_urb() failed", __func__);
 			return -ENOMEM;
 		}
 		usbvision->sbuf[bufIdx].urb = urb;
@@ -2520,13 +2525,13 @@
 						 GFP_KERNEL);
 		if (errCode) {
 			err("%s: usb_submit_urb(%d) failed: error %d",
-			    __FUNCTION__, bufIdx, errCode);
+			    __func__, bufIdx, errCode);
 		}
 	}
 
 	usbvision->streaming = Stream_Idle;
 	PDEBUG(DBG_ISOC, "%s: streaming=1 usbvision->video_endp=$%02x",
-	       __FUNCTION__,
+	       __func__,
 	       usbvision->video_endp);
 	return 0;
 }
@@ -2560,7 +2565,7 @@
 	}
 
 
-	PDEBUG(DBG_ISOC, "%s: streaming=Stream_Off\n", __FUNCTION__);
+	PDEBUG(DBG_ISOC, "%s: streaming=Stream_Off\n", __func__);
 	usbvision->streaming = Stream_Off;
 
 	if (!usbvision->remove_pending) {
@@ -2571,7 +2576,7 @@
 					    usbvision->ifaceAlt);
 		if (errCode < 0) {
 			err("%s: usb_set_interface() failed: error %d",
-			    __FUNCTION__, errCode);
+			    __func__, errCode);
 			usbvision->last_error = errCode;
 		}
 		regValue = (16-usbvision_read_reg(usbvision, USBVISION_ALTER_REG)) & 0x0F;
diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c
index aabc42c..e2274d7 100644
--- a/drivers/media/video/usbvision/usbvision-i2c.c
+++ b/drivers/media/video/usbvision/usbvision-i2c.c
@@ -40,13 +40,15 @@
 
 #define DBG_I2C		1<<0
 
-static int i2c_debug = 0;
+static int i2c_debug;
 
 module_param (i2c_debug, int, 0644);			// debug_i2c_usb mode of the device driver
 MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
 
-#define PDEBUG(level, fmt, args...) \
-		if (i2c_debug & (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args)
+#define PDEBUG(level, fmt, args...) { \
+		if (i2c_debug & (level)) \
+			info("[%s:%d] " fmt, __func__, __LINE__ , ## args); \
+	}
 
 static int usbvision_i2c_write(struct usb_usbvision *usbvision, unsigned char addr, char *buf,
 			    short len);
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
index df52f8a..d97261a 100644
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -97,10 +97,10 @@
 
 
 #ifdef USBVISION_DEBUG
-	#define PDEBUG(level, fmt, args...) \
+	#define PDEBUG(level, fmt, args...) { \
 		if (video_debug & (level)) \
-			info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ ,\
-				## args)
+			info("[%s:%d] " fmt, __func__, __LINE__ , ## args); \
+	}
 #else
 	#define PDEBUG(level, fmt, args...) do {} while(0)
 #endif
@@ -115,7 +115,7 @@
 
 
 /* sequential number of usbvision device */
-static int usbvision_nr = 0;
+static int usbvision_nr;
 
 static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = {
 	{ 1, 1,  8, V4L2_PIX_FMT_GREY    , "GREY" },
@@ -135,7 +135,7 @@
 /* Set the default format for ISOC endpoint */
 static int isocMode = ISOC_MODE_COMPRESS;
 /* Set the default Debug Mode of the device driver */
-static int video_debug = 0;
+static int video_debug;
 /* Set the default device to power on at startup */
 static int PowerOnAtOpen = 1;
 /* Sequential Number of Video Device */
@@ -343,7 +343,7 @@
 			return;
 	} while (0);
 
-	err("%s error: %d\n", __FUNCTION__, res);
+	err("%s error: %d\n", __func__, res);
 }
 
 static void usbvision_remove_sysfs(struct video_device *vdev)
@@ -490,7 +490,7 @@
 	mutex_unlock(&usbvision->lock);
 
 	if (usbvision->remove_pending) {
-		printk(KERN_INFO "%s: Final disconnect\n", __FUNCTION__);
+		printk(KERN_INFO "%s: Final disconnect\n", __func__);
 		usbvision_release(usbvision);
 	}
 
@@ -522,7 +522,7 @@
 	errCode = usbvision_read_reg(usbvision, reg->reg&0xff);
 	if (errCode < 0) {
 		err("%s: VIDIOC_DBG_G_REGISTER failed: error %d",
-		    __FUNCTION__, errCode);
+		    __func__, errCode);
 		return errCode;
 	}
 	reg->val = errCode;
@@ -543,7 +543,7 @@
 	errCode = usbvision_write_reg(usbvision, reg->reg&0xff, reg->val);
 	if (errCode < 0) {
 		err("%s: VIDIOC_DBG_S_REGISTER failed: error %d",
-		    __FUNCTION__, errCode);
+		    __func__, errCode);
 		return errCode;
 	}
 	return 0;
@@ -1102,7 +1102,7 @@
 	int ret,i;
 	struct usbvision_frame *frame;
 
-	PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __FUNCTION__,
+	PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __func__,
 	       (unsigned long)count, noblock);
 
 	if (!USBVISION_IS_OPERATIONAL(usbvision) || (buf == NULL))
@@ -1171,7 +1171,7 @@
 	}
 
 	PDEBUG(DBG_IO, "%s: frmx=%d, bytes_read=%ld, scanlength=%ld",
-	       __FUNCTION__,
+	       __func__,
 	       frame->index, frame->bytes_read, frame->scanlength);
 
 	/* copy bytes to user space; we allow for partials reads */
@@ -1184,7 +1184,7 @@
 
 	frame->bytes_read += count;
 	PDEBUG(DBG_IO, "%s: {copy} count used=%ld, new bytes_read=%ld",
-	       __FUNCTION__,
+	       __func__,
 	       (unsigned long)count, frame->bytes_read);
 
 	/* For now, forget the frame if it has not been read in one shot. */
@@ -1269,12 +1269,12 @@
 		(struct usb_usbvision *) video_get_drvdata(dev);
 	int errCode = 0;
 
-	PDEBUG(DBG_IO, "%s:", __FUNCTION__);
+	PDEBUG(DBG_IO, "%s:", __func__);
 
 	mutex_lock(&usbvision->lock);
 
 	if (usbvision->user) {
-		err("%s: Someone tried to open an already opened USBVision Radio!", __FUNCTION__);
+		err("%s: Someone tried to open an already opened USBVision Radio!", __func__);
 		errCode = -EBUSY;
 	}
 	else {
@@ -1342,7 +1342,7 @@
 	mutex_unlock(&usbvision->lock);
 
 	if (usbvision->remove_pending) {
-		printk(KERN_INFO "%s: Final disconnect\n", __FUNCTION__);
+		printk(KERN_INFO "%s: Final disconnect\n", __func__);
 		usbvision_release(usbvision);
 	}
 
@@ -1507,7 +1507,7 @@
 	struct video_device *vdev;
 
 	if (usb_dev == NULL) {
-		err("%s: usbvision->dev is not set", __FUNCTION__);
+		err("%s: usbvision->dev is not set", __func__);
 		return NULL;
 	}
 
@@ -1759,7 +1759,7 @@
 		PDEBUG(DBG_PROBE, "model out of bounds %d",model);
 		return -ENODEV;
 	}
-	printk(KERN_INFO "%s: %s found\n", __FUNCTION__,
+	printk(KERN_INFO "%s: %s found\n", __func__,
 				usbvision_device_data[model].ModelString);
 
 	if (usbvision_device_data[model].Interface >= 0) {
@@ -1771,20 +1771,20 @@
 	if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
 	    USB_ENDPOINT_XFER_ISOC) {
 		err("%s: interface %d. has non-ISO endpoint!",
-		    __FUNCTION__, ifnum);
+		    __func__, ifnum);
 		err("%s: Endpoint attributes %d",
-		    __FUNCTION__, endpoint->bmAttributes);
+		    __func__, endpoint->bmAttributes);
 		return -ENODEV;
 	}
 	if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ==
 	    USB_DIR_OUT) {
 		err("%s: interface %d. has ISO OUT endpoint!",
-		    __FUNCTION__, ifnum);
+		    __func__, ifnum);
 		return -ENODEV;
 	}
 
 	if ((usbvision = usbvision_alloc(dev)) == NULL) {
-		err("%s: couldn't allocate USBVision struct", __FUNCTION__);
+		err("%s: couldn't allocate USBVision struct", __func__);
 		return -ENOMEM;
 	}
 
@@ -1868,7 +1868,7 @@
 	PDEBUG(DBG_PROBE, "");
 
 	if (usbvision == NULL) {
-		err("%s: usb_get_intfdata() failed", __FUNCTION__);
+		err("%s: usb_get_intfdata() failed", __func__);
 		return;
 	}
 	usb_set_intfdata (intf, NULL);
@@ -1891,7 +1891,7 @@
 
 	if (usbvision->user) {
 		printk(KERN_INFO "%s: In use, disconnect pending\n",
-		       __FUNCTION__);
+		       __func__);
 		wake_up_interruptible(&usbvision->wait_frame);
 		wake_up_interruptible(&usbvision->wait_stream);
 	} else {
diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c
index e3ac5e6..a0f6c60 100644
--- a/drivers/media/video/v4l1-compat.c
+++ b/drivers/media/video/v4l1-compat.c
@@ -39,15 +39,18 @@
 #include <linux/kmod.h>
 #endif
 
-static unsigned int debug  = 0;
+static unsigned int debug;
 module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug,"enable debug messages");
+MODULE_PARM_DESC(debug, "enable debug messages");
 MODULE_AUTHOR("Bill Dirks");
 MODULE_DESCRIPTION("v4l(1) compatibility layer for v4l2 drivers.");
 MODULE_LICENSE("GPL");
 
-#define dprintk(fmt, arg...)	if (debug) \
-	printk(KERN_DEBUG "v4l1-compat: " fmt , ## arg)
+#define dprintk(fmt, arg...) \
+	do { \
+		if (debug) \
+			printk(KERN_DEBUG "v4l1-compat: " fmt , ## arg);\
+	} while (0)
 
 /*
  *	I O C T L   T R A N S L A T I O N
@@ -69,14 +72,12 @@
 	qctrl2.id = cid;
 	err = drv(inode, file, VIDIOC_QUERYCTRL, &qctrl2);
 	if (err < 0)
-		dprintk("VIDIOC_QUERYCTRL: %d\n",err);
-	if (err == 0 &&
-	    !(qctrl2.flags & V4L2_CTRL_FLAG_DISABLED))
-	{
+		dprintk("VIDIOC_QUERYCTRL: %d\n", err);
+	if (err == 0 && !(qctrl2.flags & V4L2_CTRL_FLAG_DISABLED)) {
 		ctrl2.id = qctrl2.id;
 		err = drv(inode, file, VIDIOC_G_CTRL, &ctrl2);
 		if (err < 0) {
-			dprintk("VIDIOC_G_CTRL: %d\n",err);
+			dprintk("VIDIOC_G_CTRL: %d\n", err);
 			return 0;
 		}
 		return ((ctrl2.value - qctrl2.minimum) * 65535
@@ -100,11 +101,10 @@
 	qctrl2.id = cid;
 	err = drv(inode, file, VIDIOC_QUERYCTRL, &qctrl2);
 	if (err < 0)
-		dprintk("VIDIOC_QUERYCTRL: %d\n",err);
+		dprintk("VIDIOC_QUERYCTRL: %d\n", err);
 	if (err == 0 &&
 	    !(qctrl2.flags & V4L2_CTRL_FLAG_DISABLED) &&
-	    !(qctrl2.flags & V4L2_CTRL_FLAG_GRABBED))
-	{
+	    !(qctrl2.flags & V4L2_CTRL_FLAG_GRABBED)) {
 		if (value < 0)
 			value = 0;
 		if (value > 65535)
@@ -119,7 +119,7 @@
 		ctrl2.value += qctrl2.minimum;
 		err = drv(inode, file, VIDIOC_S_CTRL, &ctrl2);
 		if (err < 0)
-			dprintk("VIDIOC_S_CTRL: %d\n",err);
+			dprintk("VIDIOC_S_CTRL: %d\n", err);
 	}
 	return 0;
 }
@@ -157,8 +157,7 @@
 pixelformat_to_palette(unsigned int pixelformat)
 {
 	int	palette = 0;
-	switch (pixelformat)
-	{
+	switch (pixelformat) {
 	case V4L2_PIX_FMT_GREY:
 		palette = VIDEO_PALETTE_GREY;
 		break;
@@ -200,14 +199,13 @@
 
 /* ----------------------------------------------------------------- */
 
-static int poll_one(struct file *file)
+static int poll_one(struct file *file, struct poll_wqueues *pwq)
 {
 	int retval = 1;
 	poll_table *table;
-	struct poll_wqueues pwq;
 
-	poll_initwait(&pwq);
-	table = &pwq.pt;
+	poll_initwait(pwq);
+	table = &pwq->pt;
 	for (;;) {
 		int mask;
 		set_current_state(TASK_INTERRUPTIBLE);
@@ -222,57 +220,993 @@
 		schedule();
 	}
 	set_current_state(TASK_RUNNING);
-	poll_freewait(&pwq);
+	poll_freewait(pwq);
 	return retval;
 }
 
-static int count_inputs(struct inode         *inode,
-			struct file          *file,
-			v4l2_kioctl          drv)
+static int count_inputs(
+			struct inode *inode,
+			struct file *file,
+			v4l2_kioctl drv)
 {
 	struct v4l2_input input2;
 	int i;
 
 	for (i = 0;; i++) {
-		memset(&input2,0,sizeof(input2));
+		memset(&input2, 0, sizeof(input2));
 		input2.index = i;
-		if (0 != drv(inode,file,VIDIOC_ENUMINPUT, &input2))
+		if (0 != drv(inode, file, VIDIOC_ENUMINPUT, &input2))
 			break;
 	}
 	return i;
 }
 
-static int check_size(struct inode         *inode,
-		      struct file          *file,
-		      v4l2_kioctl          drv,
-		      int *maxw, int *maxh)
+static int check_size(
+		struct inode *inode,
+		struct file *file,
+		v4l2_kioctl drv,
+		int *maxw,
+		int *maxh)
 {
 	struct v4l2_fmtdesc desc2;
 	struct v4l2_format  fmt2;
 
-	memset(&desc2,0,sizeof(desc2));
-	memset(&fmt2,0,sizeof(fmt2));
+	memset(&desc2, 0, sizeof(desc2));
+	memset(&fmt2, 0, sizeof(fmt2));
 
 	desc2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	if (0 != drv(inode,file,VIDIOC_ENUM_FMT, &desc2))
+	if (0 != drv(inode, file, VIDIOC_ENUM_FMT, &desc2))
 		goto done;
 
 	fmt2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 	fmt2.fmt.pix.width       = 10000;
 	fmt2.fmt.pix.height      = 10000;
 	fmt2.fmt.pix.pixelformat = desc2.pixelformat;
-	if (0 != drv(inode,file,VIDIOC_TRY_FMT, &fmt2))
+	if (0 != drv(inode, file, VIDIOC_TRY_FMT, &fmt2))
 		goto done;
 
 	*maxw = fmt2.fmt.pix.width;
 	*maxh = fmt2.fmt.pix.height;
 
- done:
+done:
 	return 0;
 }
 
 /* ----------------------------------------------------------------- */
 
+static noinline int v4l1_compat_get_capabilities(
+					struct video_capability *cap,
+					struct inode *inode,
+					struct file *file,
+					v4l2_kioctl drv)
+{
+	int err;
+	struct v4l2_framebuffer fbuf;
+	struct v4l2_capability *cap2;
+
+	cap2 = kzalloc(sizeof(*cap2), GFP_KERNEL);
+	if (!cap2) {
+		err = -ENOMEM;
+		return err;
+	}
+	memset(cap, 0, sizeof(*cap));
+	memset(&fbuf, 0, sizeof(fbuf));
+
+	err = drv(inode, file, VIDIOC_QUERYCAP, cap2);
+	if (err < 0) {
+		dprintk("VIDIOCGCAP / VIDIOC_QUERYCAP: %d\n", err);
+		goto done;
+	}
+	if (cap2->capabilities & V4L2_CAP_VIDEO_OVERLAY) {
+		err = drv(inode, file, VIDIOC_G_FBUF, &fbuf);
+		if (err < 0) {
+			dprintk("VIDIOCGCAP / VIDIOC_G_FBUF: %d\n", err);
+			memset(&fbuf, 0, sizeof(fbuf));
+		}
+		err = 0;
+	}
+
+	memcpy(cap->name, cap2->card,
+	       min(sizeof(cap->name), sizeof(cap2->card)));
+	cap->name[sizeof(cap->name) - 1] = 0;
+	if (cap2->capabilities & V4L2_CAP_VIDEO_CAPTURE)
+		cap->type |= VID_TYPE_CAPTURE;
+	if (cap2->capabilities & V4L2_CAP_TUNER)
+		cap->type |= VID_TYPE_TUNER;
+	if (cap2->capabilities & V4L2_CAP_VBI_CAPTURE)
+		cap->type |= VID_TYPE_TELETEXT;
+	if (cap2->capabilities & V4L2_CAP_VIDEO_OVERLAY)
+		cap->type |= VID_TYPE_OVERLAY;
+	if (fbuf.capability & V4L2_FBUF_CAP_LIST_CLIPPING)
+		cap->type |= VID_TYPE_CLIPPING;
+
+	cap->channels  = count_inputs(inode, file, drv);
+	check_size(inode, file, drv,
+		   &cap->maxwidth, &cap->maxheight);
+	cap->audios    =  0; /* FIXME */
+	cap->minwidth  = 48; /* FIXME */
+	cap->minheight = 32; /* FIXME */
+
+done:
+	kfree(cap2);
+	return err;
+}
+
+static noinline int v4l1_compat_get_frame_buffer(
+					struct video_buffer *buffer,
+					struct inode *inode,
+					struct file *file,
+					v4l2_kioctl drv)
+{
+	int err;
+	struct v4l2_framebuffer fbuf;
+
+	memset(buffer, 0, sizeof(*buffer));
+	memset(&fbuf, 0, sizeof(fbuf));
+
+	err = drv(inode, file, VIDIOC_G_FBUF, &fbuf);
+	if (err < 0) {
+		dprintk("VIDIOCGFBUF / VIDIOC_G_FBUF: %d\n", err);
+		goto done;
+	}
+	buffer->base   = fbuf.base;
+	buffer->height = fbuf.fmt.height;
+	buffer->width  = fbuf.fmt.width;
+
+	switch (fbuf.fmt.pixelformat) {
+	case V4L2_PIX_FMT_RGB332:
+		buffer->depth = 8;
+		break;
+	case V4L2_PIX_FMT_RGB555:
+		buffer->depth = 15;
+		break;
+	case V4L2_PIX_FMT_RGB565:
+		buffer->depth = 16;
+		break;
+	case V4L2_PIX_FMT_BGR24:
+		buffer->depth = 24;
+		break;
+	case V4L2_PIX_FMT_BGR32:
+		buffer->depth = 32;
+		break;
+	default:
+		buffer->depth = 0;
+	}
+	if (fbuf.fmt.bytesperline) {
+		buffer->bytesperline = fbuf.fmt.bytesperline;
+		if (!buffer->depth && buffer->width)
+			buffer->depth   = ((fbuf.fmt.bytesperline<<3)
+					  + (buffer->width-1))
+					  / buffer->width;
+	} else {
+		buffer->bytesperline =
+			(buffer->width * buffer->depth + 7) & 7;
+		buffer->bytesperline >>= 3;
+	}
+done:
+	return err;
+}
+
+static noinline int v4l1_compat_set_frame_buffer(
+					struct video_buffer *buffer,
+					struct inode *inode,
+					struct file *file,
+					v4l2_kioctl drv)
+{
+	int err;
+	struct v4l2_framebuffer fbuf;
+
+	memset(&fbuf, 0, sizeof(fbuf));
+	fbuf.base       = buffer->base;
+	fbuf.fmt.height = buffer->height;
+	fbuf.fmt.width  = buffer->width;
+	switch (buffer->depth) {
+	case 8:
+		fbuf.fmt.pixelformat = V4L2_PIX_FMT_RGB332;
+		break;
+	case 15:
+		fbuf.fmt.pixelformat = V4L2_PIX_FMT_RGB555;
+		break;
+	case 16:
+		fbuf.fmt.pixelformat = V4L2_PIX_FMT_RGB565;
+		break;
+	case 24:
+		fbuf.fmt.pixelformat = V4L2_PIX_FMT_BGR24;
+		break;
+	case 32:
+		fbuf.fmt.pixelformat = V4L2_PIX_FMT_BGR32;
+		break;
+	}
+	fbuf.fmt.bytesperline = buffer->bytesperline;
+	err = drv(inode, file, VIDIOC_S_FBUF, &fbuf);
+	if (err < 0)
+		dprintk("VIDIOCSFBUF / VIDIOC_S_FBUF: %d\n", err);
+	return err;
+}
+
+static noinline int v4l1_compat_get_win_cap_dimensions(
+					struct video_window *win,
+					struct inode *inode,
+					struct file *file,
+					v4l2_kioctl drv)
+{
+	int err;
+	struct v4l2_format *fmt;
+
+	fmt = kzalloc(sizeof(*fmt), GFP_KERNEL);
+	if (!fmt) {
+		err = -ENOMEM;
+		return err;
+	}
+	memset(win, 0, sizeof(*win));
+
+	fmt->type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
+	err = drv(inode, file, VIDIOC_G_FMT, fmt);
+	if (err < 0)
+		dprintk("VIDIOCGWIN / VIDIOC_G_WIN: %d\n", err);
+	if (err == 0) {
+		win->x         = fmt->fmt.win.w.left;
+		win->y         = fmt->fmt.win.w.top;
+		win->width     = fmt->fmt.win.w.width;
+		win->height    = fmt->fmt.win.w.height;
+		win->chromakey = fmt->fmt.win.chromakey;
+		win->clips     = NULL;
+		win->clipcount = 0;
+		goto done;
+	}
+
+	fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	err = drv(inode, file, VIDIOC_G_FMT, fmt);
+	if (err < 0) {
+		dprintk("VIDIOCGWIN / VIDIOC_G_FMT: %d\n", err);
+		goto done;
+	}
+	win->x         = 0;
+	win->y         = 0;
+	win->width     = fmt->fmt.pix.width;
+	win->height    = fmt->fmt.pix.height;
+	win->chromakey = 0;
+	win->clips     = NULL;
+	win->clipcount = 0;
+done:
+	kfree(fmt);
+	return err;
+}
+
+static noinline int v4l1_compat_set_win_cap_dimensions(
+					struct video_window *win,
+					struct inode *inode,
+					struct file *file,
+					v4l2_kioctl drv)
+{
+	int err, err1, err2;
+	struct v4l2_format *fmt;
+
+	fmt = kzalloc(sizeof(*fmt), GFP_KERNEL);
+	if (!fmt) {
+		err = -ENOMEM;
+		return err;
+	}
+	fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	drv(inode, file, VIDIOC_STREAMOFF, &fmt->type);
+	err1 = drv(inode, file, VIDIOC_G_FMT, fmt);
+	if (err1 < 0)
+		dprintk("VIDIOCSWIN / VIDIOC_G_FMT: %d\n", err1);
+	if (err1 == 0) {
+		fmt->fmt.pix.width  = win->width;
+		fmt->fmt.pix.height = win->height;
+		fmt->fmt.pix.field  = V4L2_FIELD_ANY;
+		fmt->fmt.pix.bytesperline = 0;
+		err = drv(inode, file, VIDIOC_S_FMT, fmt);
+		if (err < 0)
+			dprintk("VIDIOCSWIN / VIDIOC_S_FMT #1: %d\n",
+				err);
+		win->width  = fmt->fmt.pix.width;
+		win->height = fmt->fmt.pix.height;
+	}
+
+	memset(fmt, 0, sizeof(*fmt));
+	fmt->type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
+	fmt->fmt.win.w.left    = win->x;
+	fmt->fmt.win.w.top     = win->y;
+	fmt->fmt.win.w.width   = win->width;
+	fmt->fmt.win.w.height  = win->height;
+	fmt->fmt.win.chromakey = win->chromakey;
+	fmt->fmt.win.clips     = (void __user *)win->clips;
+	fmt->fmt.win.clipcount = win->clipcount;
+	err2 = drv(inode, file, VIDIOC_S_FMT, fmt);
+	if (err2 < 0)
+		dprintk("VIDIOCSWIN / VIDIOC_S_FMT #2: %d\n", err2);
+
+	if (err1 != 0 && err2 != 0)
+		err = err1;
+	else
+		err = 0;
+	kfree(fmt);
+	return err;
+}
+
+static noinline int v4l1_compat_turn_preview_on_off(
+					int *on,
+					struct inode *inode,
+					struct file *file,
+					v4l2_kioctl drv)
+{
+	int err;
+	enum v4l2_buf_type captype = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	if (0 == *on) {
+		/* dirty hack time.  But v4l1 has no STREAMOFF
+		 * equivalent in the API, and this one at
+		 * least comes close ... */
+		drv(inode, file, VIDIOC_STREAMOFF, &captype);
+	}
+	err = drv(inode, file, VIDIOC_OVERLAY, on);
+	if (err < 0)
+		dprintk("VIDIOCCAPTURE / VIDIOC_PREVIEW: %d\n", err);
+	return err;
+}
+
+static noinline int v4l1_compat_get_input_info(
+					struct video_channel *chan,
+					struct inode *inode,
+					struct file *file,
+					v4l2_kioctl drv)
+{
+	int err;
+	struct v4l2_input	input2;
+	v4l2_std_id    		sid;
+
+	memset(&input2, 0, sizeof(input2));
+	input2.index = chan->channel;
+	err = drv(inode, file, VIDIOC_ENUMINPUT, &input2);
+	if (err < 0) {
+		dprintk("VIDIOCGCHAN / VIDIOC_ENUMINPUT: "
+			"channel=%d err=%d\n", chan->channel, err);
+		goto done;
+	}
+	chan->channel = input2.index;
+	memcpy(chan->name, input2.name,
+	       min(sizeof(chan->name), sizeof(input2.name)));
+	chan->name[sizeof(chan->name) - 1] = 0;
+	chan->tuners = (input2.type == V4L2_INPUT_TYPE_TUNER) ? 1 : 0;
+	chan->flags = (chan->tuners) ? VIDEO_VC_TUNER : 0;
+	switch (input2.type) {
+	case V4L2_INPUT_TYPE_TUNER:
+		chan->type = VIDEO_TYPE_TV;
+		break;
+	default:
+	case V4L2_INPUT_TYPE_CAMERA:
+		chan->type = VIDEO_TYPE_CAMERA;
+		break;
+	}
+	chan->norm = 0;
+	err = drv(inode, file, VIDIOC_G_STD, &sid);
+	if (err < 0)
+		dprintk("VIDIOCGCHAN / VIDIOC_G_STD: %d\n", err);
+	if (err == 0) {
+		if (sid & V4L2_STD_PAL)
+			chan->norm = VIDEO_MODE_PAL;
+		if (sid & V4L2_STD_NTSC)
+			chan->norm = VIDEO_MODE_NTSC;
+		if (sid & V4L2_STD_SECAM)
+			chan->norm = VIDEO_MODE_SECAM;
+	}
+done:
+	return err;
+}
+
+static noinline int v4l1_compat_set_input(
+					struct video_channel *chan,
+					struct inode *inode,
+					struct file *file,
+					v4l2_kioctl drv)
+{
+	int err;
+	v4l2_std_id sid = 0;
+
+	err = drv(inode, file, VIDIOC_S_INPUT, &chan->channel);
+	if (err < 0)
+		dprintk("VIDIOCSCHAN / VIDIOC_S_INPUT: %d\n", err);
+	switch (chan->norm) {
+	case VIDEO_MODE_PAL:
+		sid = V4L2_STD_PAL;
+		break;
+	case VIDEO_MODE_NTSC:
+		sid = V4L2_STD_NTSC;
+		break;
+	case VIDEO_MODE_SECAM:
+		sid = V4L2_STD_SECAM;
+		break;
+	}
+	if (0 != sid) {
+		err = drv(inode, file, VIDIOC_S_STD, &sid);
+		if (err < 0)
+			dprintk("VIDIOCSCHAN / VIDIOC_S_STD: %d\n", err);
+	}
+	return err;
+}
+
+static noinline int v4l1_compat_get_picture(
+					struct video_picture *pict,
+					struct inode *inode,
+					struct file *file,
+					v4l2_kioctl drv)
+{
+	int err;
+	struct v4l2_format *fmt;
+
+	fmt = kzalloc(sizeof(*fmt), GFP_KERNEL);
+	if (!fmt) {
+		err = -ENOMEM;
+		return err;
+	}
+
+	pict->brightness = get_v4l_control(inode, file,
+					   V4L2_CID_BRIGHTNESS, drv);
+	pict->hue = get_v4l_control(inode, file,
+				    V4L2_CID_HUE, drv);
+	pict->contrast = get_v4l_control(inode, file,
+					 V4L2_CID_CONTRAST, drv);
+	pict->colour = get_v4l_control(inode, file,
+				       V4L2_CID_SATURATION, drv);
+	pict->whiteness = get_v4l_control(inode, file,
+					  V4L2_CID_WHITENESS, drv);
+
+	fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	err = drv(inode, file, VIDIOC_G_FMT, fmt);
+	if (err < 0) {
+		dprintk("VIDIOCGPICT / VIDIOC_G_FMT: %d\n", err);
+		goto done;
+	}
+
+	pict->depth   = ((fmt->fmt.pix.bytesperline << 3)
+			 + (fmt->fmt.pix.width - 1))
+			 / fmt->fmt.pix.width;
+	pict->palette = pixelformat_to_palette(
+		fmt->fmt.pix.pixelformat);
+done:
+	kfree(fmt);
+	return err;
+}
+
+static noinline int v4l1_compat_set_picture(
+					struct video_picture *pict,
+					struct inode *inode,
+					struct file *file,
+					v4l2_kioctl drv)
+{
+	int err;
+	struct v4l2_framebuffer fbuf;
+	int mem_err = 0, ovl_err = 0;
+	struct v4l2_format *fmt;
+
+	fmt = kzalloc(sizeof(*fmt), GFP_KERNEL);
+	if (!fmt) {
+		err = -ENOMEM;
+		return err;
+	}
+	memset(&fbuf, 0, sizeof(fbuf));
+
+	set_v4l_control(inode, file,
+			V4L2_CID_BRIGHTNESS, pict->brightness, drv);
+	set_v4l_control(inode, file,
+			V4L2_CID_HUE, pict->hue, drv);
+	set_v4l_control(inode, file,
+			V4L2_CID_CONTRAST, pict->contrast, drv);
+	set_v4l_control(inode, file,
+			V4L2_CID_SATURATION, pict->colour, drv);
+	set_v4l_control(inode, file,
+			V4L2_CID_WHITENESS, pict->whiteness, drv);
+	/*
+	 * V4L1 uses this ioctl to set both memory capture and overlay
+	 * pixel format, while V4L2 has two different ioctls for this.
+	 * Some cards may not support one or the other, and may support
+	 * different pixel formats for memory vs overlay.
+	 */
+
+	fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	err = drv(inode, file, VIDIOC_G_FMT, fmt);
+	/* If VIDIOC_G_FMT failed, then the driver likely doesn't
+	   support memory capture.  Trying to set the memory capture
+	   parameters would be pointless.  */
+	if (err < 0) {
+		dprintk("VIDIOCSPICT / VIDIOC_G_FMT: %d\n", err);
+		mem_err = -1000;  /* didn't even try */
+	} else if (fmt->fmt.pix.pixelformat !=
+		 palette_to_pixelformat(pict->palette)) {
+		fmt->fmt.pix.pixelformat = palette_to_pixelformat(
+			pict->palette);
+		mem_err = drv(inode, file, VIDIOC_S_FMT, fmt);
+		if (mem_err < 0)
+			dprintk("VIDIOCSPICT / VIDIOC_S_FMT: %d\n",
+				mem_err);
+	}
+
+	err = drv(inode, file, VIDIOC_G_FBUF, &fbuf);
+	/* If VIDIOC_G_FBUF failed, then the driver likely doesn't
+	   support overlay.  Trying to set the overlay parameters
+	   would be quite pointless.  */
+	if (err < 0) {
+		dprintk("VIDIOCSPICT / VIDIOC_G_FBUF: %d\n", err);
+		ovl_err = -1000;  /* didn't even try */
+	} else if (fbuf.fmt.pixelformat !=
+		 palette_to_pixelformat(pict->palette)) {
+		fbuf.fmt.pixelformat = palette_to_pixelformat(
+			pict->palette);
+		ovl_err = drv(inode, file, VIDIOC_S_FBUF, &fbuf);
+		if (ovl_err < 0)
+			dprintk("VIDIOCSPICT / VIDIOC_S_FBUF: %d\n",
+				ovl_err);
+	}
+	if (ovl_err < 0 && mem_err < 0) {
+		/* ioctl failed, couldn't set either parameter */
+		if (mem_err != -1000)
+			err = mem_err;
+		else if (ovl_err == -EPERM)
+			err = 0;
+		else
+			err = ovl_err;
+	} else
+		err = 0;
+	kfree(fmt);
+	return err;
+}
+
+static noinline int v4l1_compat_get_tuner(
+					struct video_tuner *tun,
+					struct inode *inode,
+					struct file *file,
+					v4l2_kioctl drv)
+{
+	int err, i;
+	struct v4l2_tuner	tun2;
+	struct v4l2_standard	std2;
+	v4l2_std_id    		sid;
+
+	memset(&tun2, 0, sizeof(tun2));
+	err = drv(inode, file, VIDIOC_G_TUNER, &tun2);
+	if (err < 0) {
+		dprintk("VIDIOCGTUNER / VIDIOC_G_TUNER: %d\n", err);
+		goto done;
+	}
+	memcpy(tun->name, tun2.name,
+	       min(sizeof(tun->name), sizeof(tun2.name)));
+	tun->name[sizeof(tun->name) - 1] = 0;
+	tun->rangelow = tun2.rangelow;
+	tun->rangehigh = tun2.rangehigh;
+	tun->flags = 0;
+	tun->mode = VIDEO_MODE_AUTO;
+
+	for (i = 0; i < 64; i++) {
+		memset(&std2, 0, sizeof(std2));
+		std2.index = i;
+		if (0 != drv(inode, file, VIDIOC_ENUMSTD, &std2))
+			break;
+		if (std2.id & V4L2_STD_PAL)
+			tun->flags |= VIDEO_TUNER_PAL;
+		if (std2.id & V4L2_STD_NTSC)
+			tun->flags |= VIDEO_TUNER_NTSC;
+		if (std2.id & V4L2_STD_SECAM)
+			tun->flags |= VIDEO_TUNER_SECAM;
+	}
+
+	err = drv(inode, file, VIDIOC_G_STD, &sid);
+	if (err < 0)
+		dprintk("VIDIOCGTUNER / VIDIOC_G_STD: %d\n", err);
+	if (err == 0) {
+		if (sid & V4L2_STD_PAL)
+			tun->mode = VIDEO_MODE_PAL;
+		if (sid & V4L2_STD_NTSC)
+			tun->mode = VIDEO_MODE_NTSC;
+		if (sid & V4L2_STD_SECAM)
+			tun->mode = VIDEO_MODE_SECAM;
+	}
+
+	if (tun2.capability & V4L2_TUNER_CAP_LOW)
+		tun->flags |= VIDEO_TUNER_LOW;
+	if (tun2.rxsubchans & V4L2_TUNER_SUB_STEREO)
+		tun->flags |= VIDEO_TUNER_STEREO_ON;
+	tun->signal = tun2.signal;
+done:
+	return err;
+}
+
+static noinline int v4l1_compat_select_tuner(
+					struct video_tuner *tun,
+					struct inode *inode,
+					struct file *file,
+					v4l2_kioctl drv)
+{
+	int err;
+	struct v4l2_tuner	t;/*84 bytes on x86_64*/
+	memset(&t, 0, sizeof(t));
+
+	t.index = tun->tuner;
+
+	err = drv(inode, file, VIDIOC_S_INPUT, &t);
+	if (err < 0)
+		dprintk("VIDIOCSTUNER / VIDIOC_S_INPUT: %d\n", err);
+	return err;
+}
+
+static noinline int v4l1_compat_get_frequency(
+					unsigned long *freq,
+					struct inode *inode,
+					struct file *file,
+					v4l2_kioctl drv)
+{
+	int err;
+	struct v4l2_frequency   freq2;
+	memset(&freq2, 0, sizeof(freq2));
+
+	freq2.tuner = 0;
+	err = drv(inode, file, VIDIOC_G_FREQUENCY, &freq2);
+	if (err < 0)
+		dprintk("VIDIOCGFREQ / VIDIOC_G_FREQUENCY: %d\n", err);
+	if (0 == err)
+		*freq = freq2.frequency;
+	return err;
+}
+
+static noinline int v4l1_compat_set_frequency(
+					unsigned long *freq,
+					struct inode *inode,
+					struct file *file,
+					v4l2_kioctl drv)
+{
+	int err;
+	struct v4l2_frequency   freq2;
+	memset(&freq2, 0, sizeof(freq2));
+
+	drv(inode, file, VIDIOC_G_FREQUENCY, &freq2);
+	freq2.frequency = *freq;
+	err = drv(inode, file, VIDIOC_S_FREQUENCY, &freq2);
+	if (err < 0)
+		dprintk("VIDIOCSFREQ / VIDIOC_S_FREQUENCY: %d\n", err);
+	return err;
+}
+
+static noinline int v4l1_compat_get_audio(
+					struct video_audio *aud,
+					struct inode *inode,
+					struct file *file,
+					v4l2_kioctl drv)
+{
+	int err, i;
+	struct v4l2_queryctrl	qctrl2;
+	struct v4l2_audio	aud2;
+	struct v4l2_tuner	tun2;
+	memset(&aud2, 0, sizeof(aud2));
+
+	err = drv(inode, file, VIDIOC_G_AUDIO, &aud2);
+	if (err < 0) {
+		dprintk("VIDIOCGAUDIO / VIDIOC_G_AUDIO: %d\n", err);
+		goto done;
+	}
+	memcpy(aud->name, aud2.name,
+	       min(sizeof(aud->name), sizeof(aud2.name)));
+	aud->name[sizeof(aud->name) - 1] = 0;
+	aud->audio = aud2.index;
+	aud->flags = 0;
+	i = get_v4l_control(inode, file, V4L2_CID_AUDIO_VOLUME, drv);
+	if (i >= 0) {
+		aud->volume = i;
+		aud->flags |= VIDEO_AUDIO_VOLUME;
+	}
+	i = get_v4l_control(inode, file, V4L2_CID_AUDIO_BASS, drv);
+	if (i >= 0) {
+		aud->bass = i;
+		aud->flags |= VIDEO_AUDIO_BASS;
+	}
+	i = get_v4l_control(inode, file, V4L2_CID_AUDIO_TREBLE, drv);
+	if (i >= 0) {
+		aud->treble = i;
+		aud->flags |= VIDEO_AUDIO_TREBLE;
+	}
+	i = get_v4l_control(inode, file, V4L2_CID_AUDIO_BALANCE, drv);
+	if (i >= 0) {
+		aud->balance = i;
+		aud->flags |= VIDEO_AUDIO_BALANCE;
+	}
+	i = get_v4l_control(inode, file, V4L2_CID_AUDIO_MUTE, drv);
+	if (i >= 0) {
+		if (i)
+			aud->flags |= VIDEO_AUDIO_MUTE;
+		aud->flags |= VIDEO_AUDIO_MUTABLE;
+	}
+	aud->step = 1;
+	qctrl2.id = V4L2_CID_AUDIO_VOLUME;
+	if (drv(inode, file, VIDIOC_QUERYCTRL, &qctrl2) == 0 &&
+	    !(qctrl2.flags & V4L2_CTRL_FLAG_DISABLED))
+		aud->step = qctrl2.step;
+	aud->mode = 0;
+
+	memset(&tun2, 0, sizeof(tun2));
+	err = drv(inode, file, VIDIOC_G_TUNER, &tun2);
+	if (err < 0) {
+		dprintk("VIDIOCGAUDIO / VIDIOC_G_TUNER: %d\n", err);
+		err = 0;
+		goto done;
+	}
+
+	if (tun2.rxsubchans & V4L2_TUNER_SUB_LANG2)
+		aud->mode = VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+	else if (tun2.rxsubchans & V4L2_TUNER_SUB_STEREO)
+		aud->mode = VIDEO_SOUND_STEREO;
+	else if (tun2.rxsubchans & V4L2_TUNER_SUB_MONO)
+		aud->mode = VIDEO_SOUND_MONO;
+done:
+	return err;
+}
+
+static noinline int v4l1_compat_set_audio(
+					struct video_audio *aud,
+					struct inode *inode,
+					struct file *file,
+					v4l2_kioctl drv)
+{
+	int err;
+	struct v4l2_audio	aud2;
+	struct v4l2_tuner	tun2;
+
+	memset(&aud2, 0, sizeof(aud2));
+	memset(&tun2, 0, sizeof(tun2));
+
+	aud2.index = aud->audio;
+	err = drv(inode, file, VIDIOC_S_AUDIO, &aud2);
+	if (err < 0) {
+		dprintk("VIDIOCSAUDIO / VIDIOC_S_AUDIO: %d\n", err);
+		goto done;
+	}
+
+	set_v4l_control(inode, file, V4L2_CID_AUDIO_VOLUME,
+			aud->volume, drv);
+	set_v4l_control(inode, file, V4L2_CID_AUDIO_BASS,
+			aud->bass, drv);
+	set_v4l_control(inode, file, V4L2_CID_AUDIO_TREBLE,
+			aud->treble, drv);
+	set_v4l_control(inode, file, V4L2_CID_AUDIO_BALANCE,
+			aud->balance, drv);
+	set_v4l_control(inode, file, V4L2_CID_AUDIO_MUTE,
+			!!(aud->flags & VIDEO_AUDIO_MUTE), drv);
+
+	err = drv(inode, file, VIDIOC_G_TUNER, &tun2);
+	if (err < 0)
+		dprintk("VIDIOCSAUDIO / VIDIOC_G_TUNER: %d\n", err);
+	if (err == 0) {
+		switch (aud->mode) {
+		default:
+		case VIDEO_SOUND_MONO:
+		case VIDEO_SOUND_LANG1:
+			tun2.audmode = V4L2_TUNER_MODE_MONO;
+			break;
+		case VIDEO_SOUND_STEREO:
+			tun2.audmode = V4L2_TUNER_MODE_STEREO;
+			break;
+		case VIDEO_SOUND_LANG2:
+			tun2.audmode = V4L2_TUNER_MODE_LANG2;
+			break;
+		}
+		err = drv(inode, file, VIDIOC_S_TUNER, &tun2);
+		if (err < 0)
+			dprintk("VIDIOCSAUDIO / VIDIOC_S_TUNER: %d\n", err);
+	}
+	err = 0;
+done:
+	return err;
+}
+
+static noinline int v4l1_compat_capture_frame(
+					struct video_mmap *mm,
+					struct inode *inode,
+					struct file *file,
+					v4l2_kioctl drv)
+{
+	int err;
+	enum v4l2_buf_type      captype = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	struct v4l2_buffer	buf;
+	struct v4l2_format	*fmt;
+
+	fmt = kzalloc(sizeof(*fmt), GFP_KERNEL);
+	if (!fmt) {
+		err = -ENOMEM;
+		return err;
+	}
+	memset(&buf, 0, sizeof(buf));
+
+	fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	err = drv(inode, file, VIDIOC_G_FMT, fmt);
+	if (err < 0) {
+		dprintk("VIDIOCMCAPTURE / VIDIOC_G_FMT: %d\n", err);
+		goto done;
+	}
+	if (mm->width   != fmt->fmt.pix.width  ||
+	    mm->height  != fmt->fmt.pix.height ||
+	    palette_to_pixelformat(mm->format) !=
+	    fmt->fmt.pix.pixelformat) {
+		/* New capture format...  */
+		fmt->fmt.pix.width = mm->width;
+		fmt->fmt.pix.height = mm->height;
+		fmt->fmt.pix.pixelformat =
+			palette_to_pixelformat(mm->format);
+		fmt->fmt.pix.field = V4L2_FIELD_ANY;
+		fmt->fmt.pix.bytesperline = 0;
+		err = drv(inode, file, VIDIOC_S_FMT, fmt);
+		if (err < 0) {
+			dprintk("VIDIOCMCAPTURE / VIDIOC_S_FMT: %d\n", err);
+			goto done;
+		}
+	}
+	buf.index = mm->frame;
+	buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	err = drv(inode, file, VIDIOC_QUERYBUF, &buf);
+	if (err < 0) {
+		dprintk("VIDIOCMCAPTURE / VIDIOC_QUERYBUF: %d\n", err);
+		goto done;
+	}
+	err = drv(inode, file, VIDIOC_QBUF, &buf);
+	if (err < 0) {
+		dprintk("VIDIOCMCAPTURE / VIDIOC_QBUF: %d\n", err);
+		goto done;
+	}
+	err = drv(inode, file, VIDIOC_STREAMON, &captype);
+	if (err < 0)
+		dprintk("VIDIOCMCAPTURE / VIDIOC_STREAMON: %d\n", err);
+done:
+	kfree(fmt);
+	return err;
+}
+
+static noinline int v4l1_compat_sync(
+				int *i,
+				struct inode *inode,
+				struct file *file,
+				v4l2_kioctl drv)
+{
+	int err;
+	enum v4l2_buf_type captype = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	struct v4l2_buffer buf;
+	struct poll_wqueues *pwq;
+
+	memset(&buf, 0, sizeof(buf));
+	buf.index = *i;
+	buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	err = drv(inode, file, VIDIOC_QUERYBUF, &buf);
+	if (err < 0) {
+		/*  No such buffer */
+		dprintk("VIDIOCSYNC / VIDIOC_QUERYBUF: %d\n", err);
+		goto done;
+	}
+	if (!(buf.flags & V4L2_BUF_FLAG_MAPPED)) {
+		/* Buffer is not mapped  */
+		err = -EINVAL;
+		goto done;
+	}
+
+	/* make sure capture actually runs so we don't block forever */
+	err = drv(inode, file, VIDIOC_STREAMON, &captype);
+	if (err < 0) {
+		dprintk("VIDIOCSYNC / VIDIOC_STREAMON: %d\n", err);
+		goto done;
+	}
+
+	pwq = kmalloc(sizeof(*pwq), GFP_KERNEL);
+	/*  Loop as long as the buffer is queued, but not done  */
+	while ((buf.flags & (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE))
+						== V4L2_BUF_FLAG_QUEUED) {
+		err = poll_one(file, pwq);
+		if (err < 0 ||	/* error or sleep was interrupted  */
+		    err == 0)	/* timeout? Shouldn't occur.  */
+			break;
+		err = drv(inode, file, VIDIOC_QUERYBUF, &buf);
+		if (err < 0)
+			dprintk("VIDIOCSYNC / VIDIOC_QUERYBUF: %d\n", err);
+	}
+	kfree(pwq);
+	if (!(buf.flags & V4L2_BUF_FLAG_DONE)) /* not done */
+		goto done;
+	do {
+		err = drv(inode, file, VIDIOC_DQBUF, &buf);
+		if (err < 0)
+			dprintk("VIDIOCSYNC / VIDIOC_DQBUF: %d\n", err);
+	} while (err == 0 && buf.index != *i);
+done:
+	return err;
+}
+
+static noinline int v4l1_compat_get_vbi_format(
+				struct vbi_format *fmt,
+				struct inode *inode,
+				struct file *file,
+				v4l2_kioctl drv)
+{
+	int err;
+	struct v4l2_format *fmt2;
+
+	fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL);
+	if (!fmt2) {
+		err = -ENOMEM;
+		return err;
+	}
+	fmt2->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+
+	err = drv(inode, file, VIDIOC_G_FMT, fmt2);
+	if (err < 0) {
+		dprintk("VIDIOCGVBIFMT / VIDIOC_G_FMT: %d\n", err);
+		goto done;
+	}
+	if (fmt2->fmt.vbi.sample_format != V4L2_PIX_FMT_GREY) {
+		err = -EINVAL;
+		goto done;
+	}
+	memset(fmt, 0, sizeof(*fmt));
+	fmt->samples_per_line = fmt2->fmt.vbi.samples_per_line;
+	fmt->sampling_rate    = fmt2->fmt.vbi.sampling_rate;
+	fmt->sample_format    = VIDEO_PALETTE_RAW;
+	fmt->start[0]         = fmt2->fmt.vbi.start[0];
+	fmt->count[0]         = fmt2->fmt.vbi.count[0];
+	fmt->start[1]         = fmt2->fmt.vbi.start[1];
+	fmt->count[1]         = fmt2->fmt.vbi.count[1];
+	fmt->flags            = fmt2->fmt.vbi.flags & 0x03;
+done:
+	kfree(fmt2);
+	return err;
+}
+
+static noinline int v4l1_compat_set_vbi_format(
+				struct vbi_format *fmt,
+				struct inode *inode,
+				struct file *file,
+				v4l2_kioctl drv)
+{
+	int err;
+	struct v4l2_format	*fmt2 = NULL;
+
+	if (VIDEO_PALETTE_RAW != fmt->sample_format) {
+		err = -EINVAL;
+		return err;
+	}
+
+	fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL);
+	if (!fmt2) {
+		err = -ENOMEM;
+		return err;
+	}
+	fmt2->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+	fmt2->fmt.vbi.samples_per_line = fmt->samples_per_line;
+	fmt2->fmt.vbi.sampling_rate    = fmt->sampling_rate;
+	fmt2->fmt.vbi.sample_format    = V4L2_PIX_FMT_GREY;
+	fmt2->fmt.vbi.start[0]         = fmt->start[0];
+	fmt2->fmt.vbi.count[0]         = fmt->count[0];
+	fmt2->fmt.vbi.start[1]         = fmt->start[1];
+	fmt2->fmt.vbi.count[1]         = fmt->count[1];
+	fmt2->fmt.vbi.flags            = fmt->flags;
+	err = drv(inode, file, VIDIOC_TRY_FMT, fmt2);
+	if (err < 0) {
+		dprintk("VIDIOCSVBIFMT / VIDIOC_TRY_FMT: %d\n", err);
+		goto done;
+	}
+
+	if (fmt2->fmt.vbi.samples_per_line != fmt->samples_per_line ||
+	    fmt2->fmt.vbi.sampling_rate    != fmt->sampling_rate    ||
+	    fmt2->fmt.vbi.sample_format    != V4L2_PIX_FMT_GREY     ||
+	    fmt2->fmt.vbi.start[0]         != fmt->start[0]         ||
+	    fmt2->fmt.vbi.count[0]         != fmt->count[0]         ||
+	    fmt2->fmt.vbi.start[1]         != fmt->start[1]         ||
+	    fmt2->fmt.vbi.count[1]         != fmt->count[1]         ||
+	    fmt2->fmt.vbi.flags            != fmt->flags) {
+		err = -EINVAL;
+		goto done;
+	}
+	err = drv(inode, file, VIDIOC_S_FMT, fmt2);
+	if (err < 0)
+		dprintk("VIDIOCSVBIFMT / VIDIOC_S_FMT: %d\n", err);
+done:
+	kfree(fmt2);
+	return err;
+}
+
 /*
  *	This function is exported.
  */
@@ -283,817 +1217,76 @@
 			   void			*arg,
 			   v4l2_kioctl          drv)
 {
-	struct v4l2_capability  *cap2 = NULL;
-	struct v4l2_format	*fmt2 = NULL;
-	enum v4l2_buf_type      captype = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-	struct v4l2_framebuffer fbuf2;
-	struct v4l2_input	input2;
-	struct v4l2_tuner	tun2;
-	struct v4l2_standard	std2;
-	struct v4l2_frequency   freq2;
-	struct v4l2_audio	aud2;
-	struct v4l2_queryctrl	qctrl2;
-	struct v4l2_buffer	buf2;
-	v4l2_std_id    		sid;
-	int i, err = 0;
+	int err;
 
 	switch (cmd) {
 	case VIDIOCGCAP:	/* capability */
-	{
-		struct video_capability *cap = arg;
-
-		cap2 = kzalloc(sizeof(*cap2), GFP_KERNEL);
-		if (!cap2) {
-			err = -ENOMEM;
-			break;
-		}
-		memset(cap, 0, sizeof(*cap));
-		memset(&fbuf2, 0, sizeof(fbuf2));
-
-		err = drv(inode, file, VIDIOC_QUERYCAP, cap2);
-		if (err < 0) {
-			dprintk("VIDIOCGCAP / VIDIOC_QUERYCAP: %d\n",err);
-			break;
-		}
-		if (cap2->capabilities & V4L2_CAP_VIDEO_OVERLAY) {
-			err = drv(inode, file, VIDIOC_G_FBUF, &fbuf2);
-			if (err < 0) {
-				dprintk("VIDIOCGCAP / VIDIOC_G_FBUF: %d\n",err);
-				memset(&fbuf2, 0, sizeof(fbuf2));
-			}
-			err = 0;
-		}
-
-		memcpy(cap->name, cap2->card,
-		       min(sizeof(cap->name), sizeof(cap2->card)));
-		cap->name[sizeof(cap->name) - 1] = 0;
-		if (cap2->capabilities & V4L2_CAP_VIDEO_CAPTURE)
-			cap->type |= VID_TYPE_CAPTURE;
-		if (cap2->capabilities & V4L2_CAP_TUNER)
-			cap->type |= VID_TYPE_TUNER;
-		if (cap2->capabilities & V4L2_CAP_VBI_CAPTURE)
-			cap->type |= VID_TYPE_TELETEXT;
-		if (cap2->capabilities & V4L2_CAP_VIDEO_OVERLAY)
-			cap->type |= VID_TYPE_OVERLAY;
-		if (fbuf2.capability & V4L2_FBUF_CAP_LIST_CLIPPING)
-			cap->type |= VID_TYPE_CLIPPING;
-
-		cap->channels  = count_inputs(inode,file,drv);
-		check_size(inode,file,drv,
-			   &cap->maxwidth,&cap->maxheight);
-		cap->audios    =  0; /* FIXME */
-		cap->minwidth  = 48; /* FIXME */
-		cap->minheight = 32; /* FIXME */
+		err = v4l1_compat_get_capabilities(arg, inode, file, drv);
 		break;
-	}
 	case VIDIOCGFBUF: /*  get frame buffer  */
-	{
-		struct video_buffer	*buffer = arg;
-
-		memset(buffer, 0, sizeof(*buffer));
-		memset(&fbuf2, 0, sizeof(fbuf2));
-
-		err = drv(inode, file, VIDIOC_G_FBUF, &fbuf2);
-		if (err < 0) {
-			dprintk("VIDIOCGFBUF / VIDIOC_G_FBUF: %d\n",err);
-			break;
-		}
-		buffer->base   = fbuf2.base;
-		buffer->height = fbuf2.fmt.height;
-		buffer->width  = fbuf2.fmt.width;
-
-		switch (fbuf2.fmt.pixelformat) {
-		case V4L2_PIX_FMT_RGB332:
-			buffer->depth = 8;
-			break;
-		case V4L2_PIX_FMT_RGB555:
-			buffer->depth = 15;
-			break;
-		case V4L2_PIX_FMT_RGB565:
-			buffer->depth = 16;
-			break;
-		case V4L2_PIX_FMT_BGR24:
-			buffer->depth = 24;
-			break;
-		case V4L2_PIX_FMT_BGR32:
-			buffer->depth = 32;
-			break;
-		default:
-			buffer->depth = 0;
-		}
-		if (fbuf2.fmt.bytesperline) {
-			buffer->bytesperline = fbuf2.fmt.bytesperline;
-			if (!buffer->depth && buffer->width)
-				buffer->depth   = ((fbuf2.fmt.bytesperline<<3)
-						  + (buffer->width-1) )
-						  /buffer->width;
-		} else {
-			buffer->bytesperline =
-				(buffer->width * buffer->depth + 7) & 7;
-			buffer->bytesperline >>= 3;
-		}
+		err = v4l1_compat_get_frame_buffer(arg, inode, file, drv);
 		break;
-	}
 	case VIDIOCSFBUF: /*  set frame buffer  */
-	{
-		struct video_buffer	*buffer = arg;
-
-		memset(&fbuf2, 0, sizeof(fbuf2));
-		fbuf2.base       = buffer->base;
-		fbuf2.fmt.height = buffer->height;
-		fbuf2.fmt.width  = buffer->width;
-		switch (buffer->depth) {
-		case 8:
-			fbuf2.fmt.pixelformat = V4L2_PIX_FMT_RGB332;
-			break;
-		case 15:
-			fbuf2.fmt.pixelformat = V4L2_PIX_FMT_RGB555;
-			break;
-		case 16:
-			fbuf2.fmt.pixelformat = V4L2_PIX_FMT_RGB565;
-			break;
-		case 24:
-			fbuf2.fmt.pixelformat = V4L2_PIX_FMT_BGR24;
-			break;
-		case 32:
-			fbuf2.fmt.pixelformat = V4L2_PIX_FMT_BGR32;
-			break;
-		}
-		fbuf2.fmt.bytesperline = buffer->bytesperline;
-		err = drv(inode, file, VIDIOC_S_FBUF, &fbuf2);
-		if (err < 0)
-			dprintk("VIDIOCSFBUF / VIDIOC_S_FBUF: %d\n",err);
+		err = v4l1_compat_set_frame_buffer(arg, inode, file, drv);
 		break;
-	}
 	case VIDIOCGWIN: /*  get window or capture dimensions  */
-	{
-		struct video_window	*win = arg;
-
-		fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL);
-		if (!fmt2) {
-			err = -ENOMEM;
-			break;
-		}
-		memset(win,0,sizeof(*win));
-
-		fmt2->type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
-		err = drv(inode, file, VIDIOC_G_FMT, fmt2);
-		if (err < 0)
-			dprintk("VIDIOCGWIN / VIDIOC_G_WIN: %d\n",err);
-		if (err == 0) {
-			win->x         = fmt2->fmt.win.w.left;
-			win->y         = fmt2->fmt.win.w.top;
-			win->width     = fmt2->fmt.win.w.width;
-			win->height    = fmt2->fmt.win.w.height;
-			win->chromakey = fmt2->fmt.win.chromakey;
-			win->clips     = NULL;
-			win->clipcount = 0;
-			break;
-		}
-
-		fmt2->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		err = drv(inode, file, VIDIOC_G_FMT, fmt2);
-		if (err < 0) {
-			dprintk("VIDIOCGWIN / VIDIOC_G_FMT: %d\n",err);
-			break;
-		}
-		win->x         = 0;
-		win->y         = 0;
-		win->width     = fmt2->fmt.pix.width;
-		win->height    = fmt2->fmt.pix.height;
-		win->chromakey = 0;
-		win->clips     = NULL;
-		win->clipcount = 0;
+		err = v4l1_compat_get_win_cap_dimensions(arg, inode, file, drv);
 		break;
-	}
 	case VIDIOCSWIN: /*  set window and/or capture dimensions  */
-	{
-		struct video_window	*win = arg;
-		int err1,err2;
-
-		fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL);
-		if (!fmt2) {
-			err = -ENOMEM;
-			break;
-		}
-		fmt2->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		drv(inode, file, VIDIOC_STREAMOFF, &fmt2->type);
-		err1 = drv(inode, file, VIDIOC_G_FMT, fmt2);
-		if (err1 < 0)
-			dprintk("VIDIOCSWIN / VIDIOC_G_FMT: %d\n",err);
-		if (err1 == 0) {
-			fmt2->fmt.pix.width  = win->width;
-			fmt2->fmt.pix.height = win->height;
-			fmt2->fmt.pix.field  = V4L2_FIELD_ANY;
-			fmt2->fmt.pix.bytesperline = 0;
-			err = drv(inode, file, VIDIOC_S_FMT, fmt2);
-			if (err < 0)
-				dprintk("VIDIOCSWIN / VIDIOC_S_FMT #1: %d\n",
-					err);
-			win->width  = fmt2->fmt.pix.width;
-			win->height = fmt2->fmt.pix.height;
-		}
-
-		memset(fmt2,0,sizeof(*fmt2));
-		fmt2->type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
-		fmt2->fmt.win.w.left    = win->x;
-		fmt2->fmt.win.w.top     = win->y;
-		fmt2->fmt.win.w.width   = win->width;
-		fmt2->fmt.win.w.height  = win->height;
-		fmt2->fmt.win.chromakey = win->chromakey;
-		fmt2->fmt.win.clips     = (void __user *)win->clips;
-		fmt2->fmt.win.clipcount = win->clipcount;
-		err2 = drv(inode, file, VIDIOC_S_FMT, fmt2);
-		if (err2 < 0)
-			dprintk("VIDIOCSWIN / VIDIOC_S_FMT #2: %d\n",err);
-
-		if (err1 != 0 && err2 != 0)
-			err = err1;
+		err = v4l1_compat_set_win_cap_dimensions(arg, inode, file, drv);
 		break;
-	}
 	case VIDIOCCAPTURE: /*  turn on/off preview  */
-	{
-		int *on = arg;
-
-		if (0 == *on) {
-			/* dirty hack time.  But v4l1 has no STREAMOFF
-			 * equivalent in the API, and this one at
-			 * least comes close ... */
-			drv(inode, file, VIDIOC_STREAMOFF, &captype);
-		}
-		err = drv(inode, file, VIDIOC_OVERLAY, arg);
-		if (err < 0)
-			dprintk("VIDIOCCAPTURE / VIDIOC_PREVIEW: %d\n",err);
+		err = v4l1_compat_turn_preview_on_off(arg, inode, file, drv);
 		break;
-	}
 	case VIDIOCGCHAN: /*  get input information  */
-	{
-		struct video_channel	*chan = arg;
-
-		memset(&input2,0,sizeof(input2));
-		input2.index = chan->channel;
-		err = drv(inode, file, VIDIOC_ENUMINPUT, &input2);
-		if (err < 0) {
-			dprintk("VIDIOCGCHAN / VIDIOC_ENUMINPUT: "
-				"channel=%d err=%d\n",chan->channel,err);
-			break;
-		}
-		chan->channel = input2.index;
-		memcpy(chan->name, input2.name,
-		       min(sizeof(chan->name), sizeof(input2.name)));
-		chan->name[sizeof(chan->name) - 1] = 0;
-		chan->tuners = (input2.type == V4L2_INPUT_TYPE_TUNER) ? 1 : 0;
-		chan->flags = (chan->tuners) ? VIDEO_VC_TUNER : 0;
-		switch (input2.type) {
-		case V4L2_INPUT_TYPE_TUNER:
-			chan->type = VIDEO_TYPE_TV;
-			break;
-		default:
-		case V4L2_INPUT_TYPE_CAMERA:
-			chan->type = VIDEO_TYPE_CAMERA;
-			break;
-		}
-		chan->norm = 0;
-		err = drv(inode, file, VIDIOC_G_STD, &sid);
-		if (err < 0)
-			dprintk("VIDIOCGCHAN / VIDIOC_G_STD: %d\n",err);
-		if (err == 0) {
-			if (sid & V4L2_STD_PAL)
-				chan->norm = VIDEO_MODE_PAL;
-			if (sid & V4L2_STD_NTSC)
-				chan->norm = VIDEO_MODE_NTSC;
-			if (sid & V4L2_STD_SECAM)
-				chan->norm = VIDEO_MODE_SECAM;
-		}
+		err = v4l1_compat_get_input_info(arg, inode, file, drv);
 		break;
-	}
 	case VIDIOCSCHAN: /*  set input  */
-	{
-		struct video_channel *chan = arg;
-
-		sid = 0;
-		err = drv(inode, file, VIDIOC_S_INPUT, &chan->channel);
-		if (err < 0)
-			dprintk("VIDIOCSCHAN / VIDIOC_S_INPUT: %d\n",err);
-		switch (chan->norm) {
-		case VIDEO_MODE_PAL:
-			sid = V4L2_STD_PAL;
-			break;
-		case VIDEO_MODE_NTSC:
-			sid = V4L2_STD_NTSC;
-			break;
-		case VIDEO_MODE_SECAM:
-			sid = V4L2_STD_SECAM;
-			break;
-		}
-		if (0 != sid) {
-			err = drv(inode, file, VIDIOC_S_STD, &sid);
-			if (err < 0)
-				dprintk("VIDIOCSCHAN / VIDIOC_S_STD: %d\n",err);
-		}
+		err = v4l1_compat_set_input(arg, inode, file, drv);
 		break;
-	}
 	case VIDIOCGPICT: /*  get tone controls & partial capture format  */
-	{
-		struct video_picture	*pict = arg;
-
-		fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL);
-		if (!fmt2) {
-			err = -ENOMEM;
-			break;
-		}
-
-		pict->brightness = get_v4l_control(inode, file,
-						   V4L2_CID_BRIGHTNESS,drv);
-		pict->hue = get_v4l_control(inode, file,
-					    V4L2_CID_HUE, drv);
-		pict->contrast = get_v4l_control(inode, file,
-						 V4L2_CID_CONTRAST, drv);
-		pict->colour = get_v4l_control(inode, file,
-					       V4L2_CID_SATURATION, drv);
-		pict->whiteness = get_v4l_control(inode, file,
-						  V4L2_CID_WHITENESS, drv);
-
-		fmt2->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		err = drv(inode, file, VIDIOC_G_FMT, fmt2);
-		if (err < 0) {
-			dprintk("VIDIOCGPICT / VIDIOC_G_FMT: %d\n",err);
-			break;
-		}
-
-		pict->depth   = ((fmt2->fmt.pix.bytesperline<<3)
-				 + (fmt2->fmt.pix.width-1) )
-				 /fmt2->fmt.pix.width;
-		pict->palette = pixelformat_to_palette(
-			fmt2->fmt.pix.pixelformat);
+		err = v4l1_compat_get_picture(arg, inode, file, drv);
 		break;
-	}
 	case VIDIOCSPICT: /*  set tone controls & partial capture format  */
-	{
-		struct video_picture	*pict = arg;
-		int mem_err = 0, ovl_err = 0;
-
-		fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL);
-		if (!fmt2) {
-			err = -ENOMEM;
-			break;
-		}
-		memset(&fbuf2, 0, sizeof(fbuf2));
-
-		set_v4l_control(inode, file,
-				V4L2_CID_BRIGHTNESS, pict->brightness, drv);
-		set_v4l_control(inode, file,
-				V4L2_CID_HUE, pict->hue, drv);
-		set_v4l_control(inode, file,
-				V4L2_CID_CONTRAST, pict->contrast, drv);
-		set_v4l_control(inode, file,
-				V4L2_CID_SATURATION, pict->colour, drv);
-		set_v4l_control(inode, file,
-				V4L2_CID_WHITENESS, pict->whiteness, drv);
-		/*
-		 * V4L1 uses this ioctl to set both memory capture and overlay
-		 * pixel format, while V4L2 has two different ioctls for this.
-		 * Some cards may not support one or the other, and may support
-		 * different pixel formats for memory vs overlay.
-		 */
-
-		fmt2->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		err = drv(inode, file, VIDIOC_G_FMT, fmt2);
-		/* If VIDIOC_G_FMT failed, then the driver likely doesn't
-		   support memory capture.  Trying to set the memory capture
-		   parameters would be pointless.  */
-		if (err < 0) {
-			dprintk("VIDIOCSPICT / VIDIOC_G_FMT: %d\n",err);
-			mem_err = -1000;  /* didn't even try */
-		} else if (fmt2->fmt.pix.pixelformat !=
-			 palette_to_pixelformat(pict->palette)) {
-			fmt2->fmt.pix.pixelformat = palette_to_pixelformat(
-				pict->palette);
-			mem_err = drv(inode, file, VIDIOC_S_FMT, fmt2);
-			if (mem_err < 0)
-				dprintk("VIDIOCSPICT / VIDIOC_S_FMT: %d\n",
-					mem_err);
-		}
-
-		err = drv(inode, file, VIDIOC_G_FBUF, &fbuf2);
-		/* If VIDIOC_G_FBUF failed, then the driver likely doesn't
-		   support overlay.  Trying to set the overlay parameters
-		   would be quite pointless.  */
-		if (err < 0) {
-			dprintk("VIDIOCSPICT / VIDIOC_G_FBUF: %d\n",err);
-			ovl_err = -1000;  /* didn't even try */
-		} else if (fbuf2.fmt.pixelformat !=
-			 palette_to_pixelformat(pict->palette)) {
-			fbuf2.fmt.pixelformat = palette_to_pixelformat(
-				pict->palette);
-			ovl_err = drv(inode, file, VIDIOC_S_FBUF, &fbuf2);
-			if (ovl_err < 0)
-				dprintk("VIDIOCSPICT / VIDIOC_S_FBUF: %d\n",
-					ovl_err);
-		}
-		if (ovl_err < 0 && mem_err < 0)
-			/* ioctl failed, couldn't set either parameter */
-			if (mem_err != -1000) {
-			    err = mem_err;
-			} else if (ovl_err == -EPERM) {
-			    err = 0;
-			} else {
-			    err = ovl_err;
-			}
-		else
-			err = 0;
+		err = v4l1_compat_set_picture(arg, inode, file, drv);
 		break;
-	}
 	case VIDIOCGTUNER: /*  get tuner information  */
-	{
-		struct video_tuner	*tun = arg;
-
-		memset(&tun2,0,sizeof(tun2));
-		err = drv(inode, file, VIDIOC_G_TUNER, &tun2);
-		if (err < 0) {
-			dprintk("VIDIOCGTUNER / VIDIOC_G_TUNER: %d\n",err);
-			break;
-		}
-		memcpy(tun->name, tun2.name,
-		       min(sizeof(tun->name), sizeof(tun2.name)));
-		tun->name[sizeof(tun->name) - 1] = 0;
-		tun->rangelow = tun2.rangelow;
-		tun->rangehigh = tun2.rangehigh;
-		tun->flags = 0;
-		tun->mode = VIDEO_MODE_AUTO;
-
-		for (i = 0; i < 64; i++) {
-			memset(&std2,0,sizeof(std2));
-			std2.index = i;
-			if (0 != drv(inode, file, VIDIOC_ENUMSTD, &std2))
-				break;
-			if (std2.id & V4L2_STD_PAL)
-				tun->flags |= VIDEO_TUNER_PAL;
-			if (std2.id & V4L2_STD_NTSC)
-				tun->flags |= VIDEO_TUNER_NTSC;
-			if (std2.id & V4L2_STD_SECAM)
-				tun->flags |= VIDEO_TUNER_SECAM;
-		}
-
-		err = drv(inode, file, VIDIOC_G_STD, &sid);
-		if (err < 0)
-			dprintk("VIDIOCGTUNER / VIDIOC_G_STD: %d\n",err);
-		if (err == 0) {
-			if (sid & V4L2_STD_PAL)
-				tun->mode = VIDEO_MODE_PAL;
-			if (sid & V4L2_STD_NTSC)
-				tun->mode = VIDEO_MODE_NTSC;
-			if (sid & V4L2_STD_SECAM)
-				tun->mode = VIDEO_MODE_SECAM;
-		}
-
-		if (tun2.capability & V4L2_TUNER_CAP_LOW)
-			tun->flags |= VIDEO_TUNER_LOW;
-		if (tun2.rxsubchans & V4L2_TUNER_SUB_STEREO)
-			tun->flags |= VIDEO_TUNER_STEREO_ON;
-		tun->signal = tun2.signal;
+		err = v4l1_compat_get_tuner(arg, inode, file, drv);
 		break;
-	}
 	case VIDIOCSTUNER: /*  select a tuner input  */
-	{
-		struct video_tuner	*tun = arg;
-		struct v4l2_tuner	t;
-		memset(&t,0,sizeof(t));
-
-		t.index=tun->tuner;
-
-		err = drv(inode, file, VIDIOC_S_INPUT, &t);
-		if (err < 0)
-			dprintk("VIDIOCSTUNER / VIDIOC_S_INPUT: %d\n",err);
-
+		err = v4l1_compat_select_tuner(arg, inode, file, drv);
 		break;
-	}
 	case VIDIOCGFREQ: /*  get frequency  */
-	{
-		unsigned long *freq = arg;
-		memset(&freq2,0,sizeof(freq2));
-
-		freq2.tuner = 0;
-		err = drv(inode, file, VIDIOC_G_FREQUENCY, &freq2);
-		if (err < 0)
-			dprintk("VIDIOCGFREQ / VIDIOC_G_FREQUENCY: %d\n",err);
-		if (0 == err)
-			*freq = freq2.frequency;
+		err = v4l1_compat_get_frequency(arg, inode, file, drv);
 		break;
-	}
 	case VIDIOCSFREQ: /*  set frequency  */
-	{
-		unsigned long *freq = arg;
-		memset(&freq2,0,sizeof(freq2));
-
-		drv(inode, file, VIDIOC_G_FREQUENCY, &freq2);
-		freq2.frequency = *freq;
-		err = drv(inode, file, VIDIOC_S_FREQUENCY, &freq2);
-		if (err < 0)
-			dprintk("VIDIOCSFREQ / VIDIOC_S_FREQUENCY: %d\n",err);
+		err = v4l1_compat_set_frequency(arg, inode, file, drv);
 		break;
-	}
 	case VIDIOCGAUDIO: /*  get audio properties/controls  */
-	{
-		struct video_audio	*aud = arg;
-		memset(&aud2,0,sizeof(aud2));
-
-		err = drv(inode, file, VIDIOC_G_AUDIO, &aud2);
-		if (err < 0) {
-			dprintk("VIDIOCGAUDIO / VIDIOC_G_AUDIO: %d\n",err);
-			break;
-		}
-		memcpy(aud->name, aud2.name,
-		       min(sizeof(aud->name), sizeof(aud2.name)));
-		aud->name[sizeof(aud->name) - 1] = 0;
-		aud->audio = aud2.index;
-		aud->flags = 0;
-		i = get_v4l_control(inode, file, V4L2_CID_AUDIO_VOLUME, drv);
-		if (i >= 0) {
-			aud->volume = i;
-			aud->flags |= VIDEO_AUDIO_VOLUME;
-		}
-		i = get_v4l_control(inode, file, V4L2_CID_AUDIO_BASS, drv);
-		if (i >= 0) {
-			aud->bass = i;
-			aud->flags |= VIDEO_AUDIO_BASS;
-		}
-		i = get_v4l_control(inode, file, V4L2_CID_AUDIO_TREBLE, drv);
-		if (i >= 0) {
-			aud->treble = i;
-			aud->flags |= VIDEO_AUDIO_TREBLE;
-		}
-		i = get_v4l_control(inode, file, V4L2_CID_AUDIO_BALANCE, drv);
-		if (i >= 0) {
-			aud->balance = i;
-			aud->flags |= VIDEO_AUDIO_BALANCE;
-		}
-		i = get_v4l_control(inode, file, V4L2_CID_AUDIO_MUTE, drv);
-		if (i >= 0) {
-			if (i)
-				aud->flags |= VIDEO_AUDIO_MUTE;
-			aud->flags |= VIDEO_AUDIO_MUTABLE;
-		}
-		aud->step = 1;
-		qctrl2.id = V4L2_CID_AUDIO_VOLUME;
-		if (drv(inode, file, VIDIOC_QUERYCTRL, &qctrl2) == 0 &&
-		    !(qctrl2.flags & V4L2_CTRL_FLAG_DISABLED))
-			aud->step = qctrl2.step;
-		aud->mode = 0;
-
-		memset(&tun2,0,sizeof(tun2));
-		err = drv(inode, file, VIDIOC_G_TUNER, &tun2);
-		if (err < 0) {
-			dprintk("VIDIOCGAUDIO / VIDIOC_G_TUNER: %d\n",err);
-			err = 0;
-			break;
-		}
-
-		if (tun2.rxsubchans & V4L2_TUNER_SUB_LANG2)
-			aud->mode = VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-		else if (tun2.rxsubchans & V4L2_TUNER_SUB_STEREO)
-			aud->mode = VIDEO_SOUND_STEREO;
-		else if (tun2.rxsubchans & V4L2_TUNER_SUB_MONO)
-			aud->mode = VIDEO_SOUND_MONO;
+		err = v4l1_compat_get_audio(arg, inode, file, drv);
 		break;
-	}
 	case VIDIOCSAUDIO: /*  set audio controls  */
-	{
-		struct video_audio	*aud = arg;
-
-		memset(&aud2,0,sizeof(aud2));
-		memset(&tun2,0,sizeof(tun2));
-
-		aud2.index = aud->audio;
-		err = drv(inode, file, VIDIOC_S_AUDIO, &aud2);
-		if (err < 0) {
-			dprintk("VIDIOCSAUDIO / VIDIOC_S_AUDIO: %d\n",err);
-			break;
-		}
-
-		set_v4l_control(inode, file, V4L2_CID_AUDIO_VOLUME,
-				aud->volume, drv);
-		set_v4l_control(inode, file, V4L2_CID_AUDIO_BASS,
-				aud->bass, drv);
-		set_v4l_control(inode, file, V4L2_CID_AUDIO_TREBLE,
-				aud->treble, drv);
-		set_v4l_control(inode, file, V4L2_CID_AUDIO_BALANCE,
-				aud->balance, drv);
-		set_v4l_control(inode, file, V4L2_CID_AUDIO_MUTE,
-				!!(aud->flags & VIDEO_AUDIO_MUTE), drv);
-
-		err = drv(inode, file, VIDIOC_G_TUNER, &tun2);
-		if (err < 0)
-			dprintk("VIDIOCSAUDIO / VIDIOC_G_TUNER: %d\n",err);
-		if (err == 0) {
-			switch (aud->mode) {
-			default:
-			case VIDEO_SOUND_MONO:
-			case VIDEO_SOUND_LANG1:
-				tun2.audmode = V4L2_TUNER_MODE_MONO;
-				break;
-			case VIDEO_SOUND_STEREO:
-				tun2.audmode = V4L2_TUNER_MODE_STEREO;
-				break;
-			case VIDEO_SOUND_LANG2:
-				tun2.audmode = V4L2_TUNER_MODE_LANG2;
-				break;
-			}
-			err = drv(inode, file, VIDIOC_S_TUNER, &tun2);
-			if (err < 0)
-				dprintk("VIDIOCSAUDIO / VIDIOC_S_TUNER: %d\n",err);
-		}
-		err = 0;
+		err = v4l1_compat_set_audio(arg, inode, file, drv);
 		break;
-	}
 	case VIDIOCMCAPTURE: /*  capture a frame  */
-	{
-		struct video_mmap	*mm = arg;
-
-		fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL);
-		if (!fmt2) {
-			err = -ENOMEM;
-			break;
-		}
-		memset(&buf2,0,sizeof(buf2));
-
-		fmt2->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		err = drv(inode, file, VIDIOC_G_FMT, fmt2);
-		if (err < 0) {
-			dprintk("VIDIOCMCAPTURE / VIDIOC_G_FMT: %d\n",err);
-			break;
-		}
-		if (mm->width   != fmt2->fmt.pix.width  ||
-		    mm->height  != fmt2->fmt.pix.height ||
-		    palette_to_pixelformat(mm->format) !=
-		    fmt2->fmt.pix.pixelformat)
-		{/* New capture format...  */
-			fmt2->fmt.pix.width = mm->width;
-			fmt2->fmt.pix.height = mm->height;
-			fmt2->fmt.pix.pixelformat =
-				palette_to_pixelformat(mm->format);
-			fmt2->fmt.pix.field = V4L2_FIELD_ANY;
-			fmt2->fmt.pix.bytesperline = 0;
-			err = drv(inode, file, VIDIOC_S_FMT, fmt2);
-			if (err < 0) {
-				dprintk("VIDIOCMCAPTURE / VIDIOC_S_FMT: %d\n",err);
-				break;
-			}
-		}
-		buf2.index = mm->frame;
-		buf2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		err = drv(inode, file, VIDIOC_QUERYBUF, &buf2);
-		if (err < 0) {
-			dprintk("VIDIOCMCAPTURE / VIDIOC_QUERYBUF: %d\n",err);
-			break;
-		}
-		err = drv(inode, file, VIDIOC_QBUF, &buf2);
-		if (err < 0) {
-			dprintk("VIDIOCMCAPTURE / VIDIOC_QBUF: %d\n",err);
-			break;
-		}
-		err = drv(inode, file, VIDIOC_STREAMON, &captype);
-		if (err < 0)
-			dprintk("VIDIOCMCAPTURE / VIDIOC_STREAMON: %d\n",err);
+		err = v4l1_compat_capture_frame(arg, inode, file, drv);
 		break;
-	}
 	case VIDIOCSYNC: /*  wait for a frame  */
-	{
-		int			*i = arg;
-
-		memset(&buf2,0,sizeof(buf2));
-		buf2.index = *i;
-		buf2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		err = drv(inode, file, VIDIOC_QUERYBUF, &buf2);
-		if (err < 0) {
-			/*  No such buffer */
-			dprintk("VIDIOCSYNC / VIDIOC_QUERYBUF: %d\n",err);
-			break;
-		}
-		if (!(buf2.flags & V4L2_BUF_FLAG_MAPPED)) {
-			/* Buffer is not mapped  */
-			err = -EINVAL;
-			break;
-		}
-
-		/* make sure capture actually runs so we don't block forever */
-		err = drv(inode, file, VIDIOC_STREAMON, &captype);
-		if (err < 0) {
-			dprintk("VIDIOCSYNC / VIDIOC_STREAMON: %d\n",err);
-			break;
-		}
-
-		/*  Loop as long as the buffer is queued, but not done  */
-		while ((buf2.flags &
-			(V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE))
-		       == V4L2_BUF_FLAG_QUEUED)
-		{
-			err = poll_one(file);
-			if (err < 0 ||	/* error or sleep was interrupted  */
-			    err == 0)	/* timeout? Shouldn't occur.  */
-				break;
-			err = drv(inode, file, VIDIOC_QUERYBUF, &buf2);
-			if (err < 0)
-				dprintk("VIDIOCSYNC / VIDIOC_QUERYBUF: %d\n",err);
-		}
-		if (!(buf2.flags & V4L2_BUF_FLAG_DONE)) /* not done */
-			break;
-		do {
-			err = drv(inode, file, VIDIOC_DQBUF, &buf2);
-			if (err < 0)
-				dprintk("VIDIOCSYNC / VIDIOC_DQBUF: %d\n",err);
-		} while (err == 0 && buf2.index != *i);
+		err = v4l1_compat_sync(arg, inode, file, drv);
 		break;
-	}
-
 	case VIDIOCGVBIFMT: /* query VBI data capture format */
-	{
-		struct vbi_format      *fmt = arg;
-
-		fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL);
-		if (!fmt2) {
-			err = -ENOMEM;
-			break;
-		}
-		fmt2->type = V4L2_BUF_TYPE_VBI_CAPTURE;
-
-		err = drv(inode, file, VIDIOC_G_FMT, fmt2);
-		if (err < 0) {
-			dprintk("VIDIOCGVBIFMT / VIDIOC_G_FMT: %d\n", err);
-			break;
-		}
-		if (fmt2->fmt.vbi.sample_format != V4L2_PIX_FMT_GREY) {
-			err = -EINVAL;
-			break;
-		}
-		memset(fmt, 0, sizeof(*fmt));
-		fmt->samples_per_line = fmt2->fmt.vbi.samples_per_line;
-		fmt->sampling_rate    = fmt2->fmt.vbi.sampling_rate;
-		fmt->sample_format    = VIDEO_PALETTE_RAW;
-		fmt->start[0]         = fmt2->fmt.vbi.start[0];
-		fmt->count[0]         = fmt2->fmt.vbi.count[0];
-		fmt->start[1]         = fmt2->fmt.vbi.start[1];
-		fmt->count[1]         = fmt2->fmt.vbi.count[1];
-		fmt->flags            = fmt2->fmt.vbi.flags & 0x03;
+		err = v4l1_compat_get_vbi_format(arg, inode, file, drv);
 		break;
-	}
 	case VIDIOCSVBIFMT:
-	{
-		struct vbi_format      *fmt = arg;
-
-		if (VIDEO_PALETTE_RAW != fmt->sample_format) {
-			err = -EINVAL;
-			break;
-		}
-
-		fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL);
-		if (!fmt2) {
-			err = -ENOMEM;
-			break;
-		}
-		fmt2->type = V4L2_BUF_TYPE_VBI_CAPTURE;
-		fmt2->fmt.vbi.samples_per_line = fmt->samples_per_line;
-		fmt2->fmt.vbi.sampling_rate    = fmt->sampling_rate;
-		fmt2->fmt.vbi.sample_format    = V4L2_PIX_FMT_GREY;
-		fmt2->fmt.vbi.start[0]         = fmt->start[0];
-		fmt2->fmt.vbi.count[0]         = fmt->count[0];
-		fmt2->fmt.vbi.start[1]         = fmt->start[1];
-		fmt2->fmt.vbi.count[1]         = fmt->count[1];
-		fmt2->fmt.vbi.flags            = fmt->flags;
-		err = drv(inode, file, VIDIOC_TRY_FMT, fmt2);
-		if (err < 0) {
-			dprintk("VIDIOCSVBIFMT / VIDIOC_TRY_FMT: %d\n", err);
-			break;
-		}
-
-		if (fmt2->fmt.vbi.samples_per_line != fmt->samples_per_line ||
-		    fmt2->fmt.vbi.sampling_rate    != fmt->sampling_rate    ||
-		    fmt2->fmt.vbi.sample_format    != V4L2_PIX_FMT_GREY     ||
-		    fmt2->fmt.vbi.start[0]         != fmt->start[0]         ||
-		    fmt2->fmt.vbi.count[0]         != fmt->count[0]         ||
-		    fmt2->fmt.vbi.start[1]         != fmt->start[1]         ||
-		    fmt2->fmt.vbi.count[1]         != fmt->count[1]         ||
-		    fmt2->fmt.vbi.flags            != fmt->flags) {
-			err = -EINVAL;
-			break;
-		}
-		err = drv(inode, file, VIDIOC_S_FMT, fmt2);
-		if (err < 0)
-			dprintk("VIDIOCSVBIFMT / VIDIOC_S_FMT: %d\n", err);
+		err = v4l1_compat_set_vbi_format(arg, inode, file, drv);
 		break;
-	}
-
 	default:
 		err = -ENOIOCTLCMD;
 		break;
 	}
 
-	kfree(cap2);
-	kfree(fmt2);
 	return err;
 }
-
 EXPORT_SYMBOL(v4l_compat_translate_ioctl);
 
 /*
diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c
index eab79ff..fc51e49 100644
--- a/drivers/media/video/videobuf-core.c
+++ b/drivers/media/video/videobuf-core.c
@@ -64,32 +64,25 @@
 	return vb;
 }
 
+#define WAITON_CONDITION (vb->state != VIDEOBUF_ACTIVE &&\
+				vb->state != VIDEOBUF_QUEUED)
 int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr)
 {
-	int retval = 0;
-	DECLARE_WAITQUEUE(wait, current);
-
 	MAGIC_CHECK(vb->magic, MAGIC_BUFFER);
-	add_wait_queue(&vb->done, &wait);
-	while (vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) {
-		if (non_blocking) {
-			retval = -EAGAIN;
-			break;
-		}
-		set_current_state(intr  ? TASK_INTERRUPTIBLE
-					: TASK_UNINTERRUPTIBLE);
-		if (vb->state == VIDEOBUF_ACTIVE ||
-		    vb->state == VIDEOBUF_QUEUED)
-			schedule();
-		set_current_state(TASK_RUNNING);
-		if (intr && signal_pending(current)) {
-			dprintk(1, "buffer waiton: -EINTR\n");
-			retval = -EINTR;
-			break;
-		}
+
+	if (non_blocking) {
+		if (WAITON_CONDITION)
+			return 0;
+		else
+			return -EAGAIN;
 	}
-	remove_wait_queue(&vb->done, &wait);
-	return retval;
+
+	if (intr)
+		return wait_event_interruptible(vb->done, WAITON_CONDITION);
+	else
+		wait_event(vb->done, WAITON_CONDITION);
+
+	return 0;
 }
 
 int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb,
@@ -98,29 +91,22 @@
 	MAGIC_CHECK(vb->magic, MAGIC_BUFFER);
 	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
-	/* This is required to avoid OOPS on some cases,
-	   since mmap_mapper() method should be called before _iolock.
-	   On some cases, the mmap_mapper() is called only after scheduling.
-	 */
-	if (vb->memory == V4L2_MEMORY_MMAP) {
-		wait_event_timeout(vb->done, q->is_mmapped,
-				   msecs_to_jiffies(100));
-		if (!q->is_mmapped) {
-			printk(KERN_ERR
-			       "Error: mmap_mapper() never called!\n");
-			return -EINVAL;
-		}
-	}
-
 	return CALL(q, iolock, q, vb, fbuf);
 }
 
+void *videobuf_queue_to_vmalloc (struct videobuf_queue *q,
+			   struct videobuf_buffer *buf)
+{
+	return CALL(q, vmalloc, buf);
+}
+EXPORT_SYMBOL_GPL(videobuf_queue_to_vmalloc);
+
 /* --------------------------------------------------------------------- */
 
 
 void videobuf_queue_core_init(struct videobuf_queue *q,
 			 struct videobuf_queue_ops *ops,
-			 void *dev,
+			 struct device *dev,
 			 spinlock_t *irqlock,
 			 enum v4l2_buf_type type,
 			 enum v4l2_field field,
@@ -144,10 +130,14 @@
 	BUG_ON(!q->ops->buf_queue);
 	BUG_ON(!q->ops->buf_release);
 
+	/* Lock is mandatory for queue_cancel to work */
+	BUG_ON(!irqlock);
+
 	/* Having implementations for abstract methods are mandatory */
 	BUG_ON(!q->int_ops);
 
 	mutex_init(&q->vb_lock);
+	init_waitqueue_head(&q->wait);
 	INIT_LIST_HEAD(&q->stream);
 }
 
@@ -195,19 +185,22 @@
 	unsigned long flags = 0;
 	int i;
 
+	q->streaming = 0;
+	q->reading  = 0;
+	wake_up_interruptible_sync(&q->wait);
+
 	/* remove queued buffers from list */
-	if (q->irqlock)
-		spin_lock_irqsave(q->irqlock, flags);
+	spin_lock_irqsave(q->irqlock, flags);
 	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
 		if (NULL == q->bufs[i])
 			continue;
 		if (q->bufs[i]->state == VIDEOBUF_QUEUED) {
 			list_del(&q->bufs[i]->queue);
 			q->bufs[i]->state = VIDEOBUF_ERROR;
+			wake_up_all(&q->bufs[i]->done);
 		}
 	}
-	if (q->irqlock)
-		spin_unlock_irqrestore(q->irqlock, flags);
+	spin_unlock_irqrestore(q->irqlock, flags);
 
 	/* free all buffers + clear queue */
 	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
@@ -563,14 +556,13 @@
 
 	list_add_tail(&buf->stream, &q->stream);
 	if (q->streaming) {
-		if (q->irqlock)
-			spin_lock_irqsave(q->irqlock, flags);
+		spin_lock_irqsave(q->irqlock, flags);
 		q->ops->buf_queue(q, buf);
-		if (q->irqlock)
-			spin_unlock_irqrestore(q->irqlock, flags);
+		spin_unlock_irqrestore(q->irqlock, flags);
 	}
 	dprintk(1, "qbuf: succeded\n");
 	retval = 0;
+	wake_up_interruptible_sync(&q->wait);
 
  done:
 	mutex_unlock(&q->vb_lock);
@@ -581,35 +573,88 @@
 	return retval;
 }
 
+
+/* Locking: Caller holds q->vb_lock */
+static int stream_next_buffer_check_queue(struct videobuf_queue *q, int noblock)
+{
+	int retval;
+
+checks:
+	if (!q->streaming) {
+		dprintk(1, "next_buffer: Not streaming\n");
+		retval = -EINVAL;
+		goto done;
+	}
+
+	if (list_empty(&q->stream)) {
+		if (noblock) {
+			retval = -EAGAIN;
+			dprintk(2, "next_buffer: no buffers to dequeue\n");
+			goto done;
+		} else {
+			dprintk(2, "next_buffer: waiting on buffer\n");
+
+			/* Drop lock to avoid deadlock with qbuf */
+			mutex_unlock(&q->vb_lock);
+
+			/* Checking list_empty and streaming is safe without
+			 * locks because we goto checks to validate while
+			 * holding locks before proceeding */
+			retval = wait_event_interruptible(q->wait,
+				!list_empty(&q->stream) || !q->streaming);
+			mutex_lock(&q->vb_lock);
+
+			if (retval)
+				goto done;
+
+			goto checks;
+		}
+	}
+
+	retval = 0;
+
+done:
+	return retval;
+}
+
+
+/* Locking: Caller holds q->vb_lock */
+static int stream_next_buffer(struct videobuf_queue *q,
+			struct videobuf_buffer **vb, int nonblocking)
+{
+	int retval;
+	struct videobuf_buffer *buf = NULL;
+
+	retval = stream_next_buffer_check_queue(q, nonblocking);
+	if (retval)
+		goto done;
+
+	buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
+	retval = videobuf_waiton(buf, nonblocking, 1);
+	if (retval < 0)
+		goto done;
+
+	*vb = buf;
+done:
+	return retval;
+}
+
 int videobuf_dqbuf(struct videobuf_queue *q,
 	       struct v4l2_buffer *b, int nonblocking)
 {
-	struct videobuf_buffer *buf;
+	struct videobuf_buffer *buf = NULL;
 	int retval;
 
 	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
 	mutex_lock(&q->vb_lock);
-	retval = -EBUSY;
-	if (q->reading) {
-		dprintk(1, "dqbuf: Reading running...\n");
-		goto done;
-	}
-	retval = -EINVAL;
-	if (b->type != q->type) {
-		dprintk(1, "dqbuf: Wrong type.\n");
-		goto done;
-	}
-	if (list_empty(&q->stream)) {
-		dprintk(1, "dqbuf: stream running\n");
-		goto done;
-	}
-	buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
-	retval = videobuf_waiton(buf, nonblocking, 1);
+
+	retval = stream_next_buffer(q, &buf, nonblocking);
 	if (retval < 0) {
-		dprintk(1, "dqbuf: waiton returned %d\n", retval);
+		dprintk(1, "dqbuf: next_buffer error: %i\n", retval);
 		goto done;
 	}
+
 	switch (buf->state) {
 	case VIDEOBUF_ERROR:
 		dprintk(1, "dqbuf: state is error\n");
@@ -650,14 +695,13 @@
 	if (q->streaming)
 		goto done;
 	q->streaming = 1;
-	if (q->irqlock)
-		spin_lock_irqsave(q->irqlock, flags);
+	spin_lock_irqsave(q->irqlock, flags);
 	list_for_each_entry(buf, &q->stream, stream)
 		if (buf->state == VIDEOBUF_PREPARED)
 			q->ops->buf_queue(q, buf);
-	if (q->irqlock)
-		spin_unlock_irqrestore(q->irqlock, flags);
+	spin_unlock_irqrestore(q->irqlock, flags);
 
+	wake_up_interruptible_sync(&q->wait);
  done:
 	mutex_unlock(&q->vb_lock);
 	return retval;
@@ -670,7 +714,6 @@
 		return -EINVAL;
 
 	videobuf_queue_cancel(q);
-	q->streaming = 0;
 
 	return 0;
 }
@@ -712,11 +755,9 @@
 		goto done;
 
 	/* start capture & wait */
-	if (q->irqlock)
-		spin_lock_irqsave(q->irqlock, flags);
+	spin_lock_irqsave(q->irqlock, flags);
 	q->ops->buf_queue(q, q->read_buf);
-	if (q->irqlock)
-		spin_unlock_irqrestore(q->irqlock, flags);
+	spin_unlock_irqrestore(q->irqlock, flags);
 	retval = videobuf_waiton(q->read_buf, 0, 0);
 	if (0 == retval) {
 		CALL(q, sync, q, q->read_buf);
@@ -740,14 +781,13 @@
 {
 	enum v4l2_field field;
 	unsigned long flags = 0;
-	unsigned size, nbufs;
+	unsigned size = 0, nbufs = 1;
 	int retval;
 
 	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
 	mutex_lock(&q->vb_lock);
 
-	nbufs = 1; size = 0;
 	q->ops->buf_setup(q, &nbufs, &size);
 
 	if (NULL == q->read_buf  &&
@@ -778,12 +818,11 @@
 			q->read_buf = NULL;
 			goto done;
 		}
-		if (q->irqlock)
-			spin_lock_irqsave(q->irqlock, flags);
 
+		spin_lock_irqsave(q->irqlock, flags);
 		q->ops->buf_queue(q, q->read_buf);
-		if (q->irqlock)
-			spin_unlock_irqrestore(q->irqlock, flags);
+		spin_unlock_irqrestore(q->irqlock, flags);
+
 		q->read_off = 0;
 	}
 
@@ -849,12 +888,10 @@
 			return err;
 		list_add_tail(&q->bufs[i]->stream, &q->stream);
 	}
-	if (q->irqlock)
-		spin_lock_irqsave(q->irqlock, flags);
+	spin_lock_irqsave(q->irqlock, flags);
 	for (i = 0; i < count; i++)
 		q->ops->buf_queue(q, q->bufs[i]);
-	if (q->irqlock)
-		spin_unlock_irqrestore(q->irqlock, flags);
+	spin_unlock_irqrestore(q->irqlock, flags);
 	q->reading = 1;
 	return 0;
 }
@@ -863,7 +900,6 @@
 {
 	int i;
 
-
 	videobuf_queue_cancel(q);
 	__videobuf_mmap_free(q);
 	INIT_LIST_HEAD(&q->stream);
@@ -874,7 +910,6 @@
 		q->bufs[i] = NULL;
 	}
 	q->read_buf = NULL;
-	q->reading  = 0;
 
 }
 
@@ -919,7 +954,7 @@
 
 	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
-	dprintk(2, "%s\n", __FUNCTION__);
+	dprintk(2, "%s\n", __func__);
 	mutex_lock(&q->vb_lock);
 	retval = -EBUSY;
 	if (q->streaming)
@@ -968,11 +1003,9 @@
 		if (q->read_off == q->read_buf->size) {
 			list_add_tail(&q->read_buf->stream,
 				      &q->stream);
-			if (q->irqlock)
-				spin_lock_irqsave(q->irqlock, flags);
+			spin_lock_irqsave(q->irqlock, flags);
 			q->ops->buf_queue(q, q->read_buf);
-			if (q->irqlock)
-				spin_unlock_irqrestore(q->irqlock, flags);
+			spin_unlock_irqrestore(q->irqlock, flags);
 			q->read_buf = NULL;
 		}
 		if (retval < 0)
diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c
index 53fed4b..03a7b94 100644
--- a/drivers/media/video/videobuf-dma-sg.c
+++ b/drivers/media/video/videobuf-dma-sg.c
@@ -1,5 +1,5 @@
 /*
- * helper functions for PCI DMA video4linux capture buffers
+ * helper functions for SG DMA video4linux capture buffers
  *
  * The functions expect the hardware being able to scatter gatter
  * (i.e. the buffers are not linear in physical memory, but fragmented
@@ -24,7 +24,7 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 
-#include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/vmalloc.h>
 #include <linux/pagemap.h>
 #include <linux/scatterlist.h>
@@ -39,10 +39,10 @@
 #define MAGIC_CHECK(is,should)	if (unlikely((is) != (should))) \
 	{ printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); }
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0644);
 
-MODULE_DESCRIPTION("helper module to manage video4linux pci dma sg buffers");
+MODULE_DESCRIPTION("helper module to manage video4linux dma sg buffers");
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
 MODULE_LICENSE("GPL");
 
@@ -119,10 +119,10 @@
 
 struct videobuf_dmabuf *videobuf_to_dma (struct videobuf_buffer *buf)
 {
-	struct videbuf_pci_sg_memory *mem=buf->priv;
-	BUG_ON (!mem);
+	struct videobuf_dma_sg_memory *mem = buf->priv;
+	BUG_ON(!mem);
 
-	MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
+	MAGIC_CHECK(mem->magic, MAGIC_SG_MEM);
 
 	return &mem->dma;
 }
@@ -141,9 +141,14 @@
 
 	dma->direction = direction;
 	switch (dma->direction) {
-	case PCI_DMA_FROMDEVICE: rw = READ;  break;
-	case PCI_DMA_TODEVICE:   rw = WRITE; break;
-	default:                 BUG();
+	case DMA_FROM_DEVICE:
+		rw = READ;
+		break;
+	case DMA_TO_DEVICE:
+		rw = WRITE;
+		break;
+	default:
+		BUG();
 	}
 
 	first = (data          & PAGE_MASK) >> PAGE_SHIFT;
@@ -157,9 +162,6 @@
 	dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n",
 		data,size,dma->nr_pages);
 
-	dma->varea = (void *) data;
-
-
 	err = get_user_pages(current,current->mm,
 			     data & PAGE_MASK, dma->nr_pages,
 			     rw == READ, 1, /* force */
@@ -216,10 +218,8 @@
 	return 0;
 }
 
-int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
+int videobuf_dma_map(struct videobuf_queue* q, struct videobuf_dmabuf *dma)
 {
-	void                   *dev=q->dev;
-
 	MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
 	BUG_ON(0 == dma->nr_pages);
 
@@ -245,11 +245,11 @@
 		return -ENOMEM;
 	}
 	if (!dma->bus_addr) {
-		dma->sglen = pci_map_sg(dev,dma->sglist,
+		dma->sglen = dma_map_sg(q->dev, dma->sglist,
 					dma->nr_pages, dma->direction);
 		if (0 == dma->sglen) {
 			printk(KERN_WARNING
-			       "%s: videobuf_map_sg failed\n",__FUNCTION__);
+			       "%s: videobuf_map_sg failed\n",__func__);
 			kfree(dma->sglist);
 			dma->sglist = NULL;
 			dma->sglen = 0;
@@ -259,26 +259,22 @@
 	return 0;
 }
 
-int videobuf_dma_sync(struct videobuf_queue *q,struct videobuf_dmabuf *dma)
+int videobuf_dma_sync(struct videobuf_queue *q, struct videobuf_dmabuf *dma)
 {
-	void                   *dev=q->dev;
-
-	MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
+	MAGIC_CHECK(dma->magic, MAGIC_DMABUF);
 	BUG_ON(!dma->sglen);
 
-	pci_dma_sync_sg_for_cpu (dev,dma->sglist,dma->nr_pages,dma->direction);
+	dma_sync_sg_for_cpu(q->dev, dma->sglist, dma->nr_pages, dma->direction);
 	return 0;
 }
 
 int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
 {
-	void                   *dev=q->dev;
-
-	MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
+	MAGIC_CHECK(dma->magic, MAGIC_DMABUF);
 	if (!dma->sglen)
 		return 0;
 
-	pci_unmap_sg (dev,dma->sglist,dma->nr_pages,dma->direction);
+	dma_unmap_sg(q->dev, dma->sglist, dma->nr_pages, dma->direction);
 
 	kfree(dma->sglist);
 	dma->sglist = NULL;
@@ -301,33 +297,32 @@
 
 	vfree(dma->vmalloc);
 	dma->vmalloc = NULL;
-	dma->varea = NULL;
 
 	if (dma->bus_addr) {
 		dma->bus_addr = 0;
 	}
-	dma->direction = PCI_DMA_NONE;
+	dma->direction = DMA_NONE;
 	return 0;
 }
 
 /* --------------------------------------------------------------------- */
 
-int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma)
+int videobuf_sg_dma_map(struct device *dev, struct videobuf_dmabuf *dma)
 {
 	struct videobuf_queue q;
 
-	q.dev=pci;
+	q.dev = dev;
 
-	return (videobuf_dma_map(&q,dma));
+	return videobuf_dma_map(&q, dma);
 }
 
-int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma)
+int videobuf_sg_dma_unmap(struct device *dev, struct videobuf_dmabuf *dma)
 {
 	struct videobuf_queue q;
 
-	q.dev=pci;
+	q.dev = dev;
 
-	return (videobuf_dma_unmap(&q,dma));
+	return videobuf_dma_unmap(&q, dma);
 }
 
 /* --------------------------------------------------------------------- */
@@ -347,7 +342,7 @@
 {
 	struct videobuf_mapping *map = vma->vm_private_data;
 	struct videobuf_queue *q = map->q;
-	struct videbuf_pci_sg_memory *mem;
+	struct videobuf_dma_sg_memory *mem;
 	int i;
 
 	dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map,
@@ -409,18 +404,18 @@
 };
 
 /* ---------------------------------------------------------------------
- * PCI handlers for the generic methods
+ * SG handlers for the generic methods
  */
 
 /* Allocated area consists on 3 parts:
 	struct video_buffer
 	struct <driver>_buffer (cx88_buffer, saa7134_buf, ...)
-	struct videobuf_pci_sg_memory
+	struct videobuf_dma_sg_memory
  */
 
 static void *__videobuf_alloc(size_t size)
 {
-	struct videbuf_pci_sg_memory *mem;
+	struct videobuf_dma_sg_memory *mem;
 	struct videobuf_buffer *vb;
 
 	vb = kzalloc(size+sizeof(*mem),GFP_KERNEL);
@@ -431,22 +426,32 @@
 	videobuf_dma_init(&mem->dma);
 
 	dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
-		__FUNCTION__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb),
+		__func__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb),
 		mem,(long)sizeof(*mem));
 
 	return vb;
 }
 
+static void *__videobuf_to_vmalloc (struct videobuf_buffer *buf)
+{
+	struct videobuf_dma_sg_memory *mem = buf->priv;
+	BUG_ON(!mem);
+
+	MAGIC_CHECK(mem->magic, MAGIC_SG_MEM);
+
+	return mem->dma.vmalloc;
+}
+
 static int __videobuf_iolock (struct videobuf_queue* q,
 			      struct videobuf_buffer *vb,
 			      struct v4l2_framebuffer *fbuf)
 {
 	int err,pages;
 	dma_addr_t bus;
-	struct videbuf_pci_sg_memory *mem=vb->priv;
+	struct videobuf_dma_sg_memory *mem = vb->priv;
 	BUG_ON(!mem);
 
-	MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
+	MAGIC_CHECK(mem->magic, MAGIC_SG_MEM);
 
 	switch (vb->memory) {
 	case V4L2_MEMORY_MMAP:
@@ -455,14 +460,14 @@
 			/* no userspace addr -- kernel bounce buffer */
 			pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;
 			err = videobuf_dma_init_kernel( &mem->dma,
-							PCI_DMA_FROMDEVICE,
+							DMA_FROM_DEVICE,
 							pages );
 			if (0 != err)
 				return err;
 		} else if (vb->memory == V4L2_MEMORY_USERPTR) {
 			/* dma directly to userspace */
 			err = videobuf_dma_init_user( &mem->dma,
-						      PCI_DMA_FROMDEVICE,
+						      DMA_FROM_DEVICE,
 						      vb->baddr,vb->bsize );
 			if (0 != err)
 				return err;
@@ -473,7 +478,7 @@
 			locking inversion, so don't take it here */
 
 			err = videobuf_dma_init_user_locked(&mem->dma,
-						      PCI_DMA_FROMDEVICE,
+						      DMA_FROM_DEVICE,
 						      vb->baddr, vb->bsize);
 			if (0 != err)
 				return err;
@@ -490,7 +495,7 @@
 		 */
 		bus   = (dma_addr_t)(unsigned long)fbuf->base + vb->boff;
 		pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;
-		err = videobuf_dma_init_overlay(&mem->dma,PCI_DMA_FROMDEVICE,
+		err = videobuf_dma_init_overlay(&mem->dma, DMA_FROM_DEVICE,
 						bus, pages);
 		if (0 != err)
 			return err;
@@ -498,7 +503,7 @@
 	default:
 		BUG();
 	}
-	err = videobuf_dma_map(q,&mem->dma);
+	err = videobuf_dma_map(q, &mem->dma);
 	if (0 != err)
 		return err;
 
@@ -508,8 +513,8 @@
 static int __videobuf_sync(struct videobuf_queue *q,
 			   struct videobuf_buffer *buf)
 {
-	struct videbuf_pci_sg_memory *mem=buf->priv;
-	BUG_ON (!mem);
+	struct videobuf_dma_sg_memory *mem = buf->priv;
+	BUG_ON(!mem);
 	MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
 
 	return	videobuf_dma_sync(q,&mem->dma);
@@ -532,7 +537,7 @@
 static int __videobuf_mmap_mapper(struct videobuf_queue *q,
 			 struct vm_area_struct *vma)
 {
-	struct videbuf_pci_sg_memory *mem;
+	struct videobuf_dma_sg_memory *mem;
 	struct videobuf_mapping *map;
 	unsigned int first,last,size,i;
 	int retval;
@@ -547,12 +552,20 @@
 		goto done;
 	}
 
+	/* This function maintains backwards compatibility with V4L1 and will
+	 * map more than one buffer if the vma length is equal to the combined
+	 * size of multiple buffers than it will map them together.  See
+	 * VIDIOCGMBUF in the v4l spec
+	 *
+	 * TODO: Allow drivers to specify if they support this mode
+	 */
+
 	/* look for first buffer to map */
 	for (first = 0; first < VIDEO_MAX_FRAME; first++) {
 		if (NULL == q->bufs[first])
 			continue;
 		mem=q->bufs[first]->priv;
-		BUG_ON (!mem);
+		BUG_ON(!mem);
 		MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
 
 		if (V4L2_MEMORY_MMAP != q->bufs[first]->memory)
@@ -591,10 +604,16 @@
 	map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL);
 	if (NULL == map)
 		goto done;
-	for (size = 0, i = first; i <= last; size += q->bufs[i++]->bsize) {
+
+	size = 0;
+	for (i = first; i <= last; i++) {
+		if (NULL == q->bufs[i])
+			continue;
 		q->bufs[i]->map   = map;
 		q->bufs[i]->baddr = vma->vm_start + size;
+		size += q->bufs[i]->bsize;
 	}
+
 	map->count    = 1;
 	map->start    = vma->vm_start;
 	map->end      = vma->vm_end;
@@ -615,8 +634,8 @@
 				char __user *data, size_t count,
 				int nonblocking )
 {
-	struct videbuf_pci_sg_memory *mem=q->read_buf->priv;
-	BUG_ON (!mem);
+	struct videobuf_dma_sg_memory *mem = q->read_buf->priv;
+	BUG_ON(!mem);
 	MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
 
 	/* copy to userspace */
@@ -634,8 +653,8 @@
 				int vbihack, int nonblocking )
 {
 	unsigned int  *fc;
-	struct videbuf_pci_sg_memory *mem=q->read_buf->priv;
-	BUG_ON (!mem);
+	struct videobuf_dma_sg_memory *mem = q->read_buf->priv;
+	BUG_ON(!mem);
 	MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
 
 	if (vbihack) {
@@ -658,7 +677,7 @@
 	return count;
 }
 
-static struct videobuf_qtype_ops pci_ops = {
+static struct videobuf_qtype_ops sg_ops = {
 	.magic        = MAGIC_QTYPE_OPS,
 
 	.alloc        = __videobuf_alloc,
@@ -668,23 +687,24 @@
 	.mmap_mapper  = __videobuf_mmap_mapper,
 	.video_copy_to_user = __videobuf_copy_to_user,
 	.copy_stream  = __videobuf_copy_stream,
+	.vmalloc      = __videobuf_to_vmalloc,
 };
 
-void *videobuf_pci_alloc (size_t size)
+void *videobuf_sg_alloc(size_t size)
 {
 	struct videobuf_queue q;
 
 	/* Required to make generic handler to call __videobuf_alloc */
-	q.int_ops=&pci_ops;
+	q.int_ops = &sg_ops;
 
-	q.msize=size;
+	q.msize = size;
 
-	return videobuf_alloc (&q);
+	return videobuf_alloc(&q);
 }
 
-void videobuf_queue_pci_init(struct videobuf_queue* q,
+void videobuf_queue_sg_init(struct videobuf_queue* q,
 			 struct videobuf_queue_ops *ops,
-			 void *dev,
+			 struct device *dev,
 			 spinlock_t *irqlock,
 			 enum v4l2_buf_type type,
 			 enum v4l2_field field,
@@ -692,7 +712,7 @@
 			 void *priv)
 {
 	videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
-				 priv, &pci_ops);
+				 priv, &sg_ops);
 }
 
 /* --------------------------------------------------------------------- */
@@ -709,11 +729,11 @@
 EXPORT_SYMBOL_GPL(videobuf_dma_unmap);
 EXPORT_SYMBOL_GPL(videobuf_dma_free);
 
-EXPORT_SYMBOL_GPL(videobuf_pci_dma_map);
-EXPORT_SYMBOL_GPL(videobuf_pci_dma_unmap);
-EXPORT_SYMBOL_GPL(videobuf_pci_alloc);
+EXPORT_SYMBOL_GPL(videobuf_sg_dma_map);
+EXPORT_SYMBOL_GPL(videobuf_sg_dma_unmap);
+EXPORT_SYMBOL_GPL(videobuf_sg_alloc);
 
-EXPORT_SYMBOL_GPL(videobuf_queue_pci_init);
+EXPORT_SYMBOL_GPL(videobuf_queue_sg_init);
 
 /*
  * Local variables:
diff --git a/drivers/media/video/videobuf-dvb.c b/drivers/media/video/videobuf-dvb.c
index b73aba6..6e4d73e 100644
--- a/drivers/media/video/videobuf-dvb.c
+++ b/drivers/media/video/videobuf-dvb.c
@@ -20,9 +20,10 @@
 #include <linux/fs.h>
 #include <linux/kthread.h>
 #include <linux/file.h>
+
 #include <linux/freezer.h>
 
-#include <media/videobuf-dma-sg.h>
+#include <media/videobuf-core.h>
 #include <media/videobuf-dvb.h>
 
 /* ------------------------------------------------------------------ */
@@ -30,7 +31,7 @@
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
 
-static unsigned int debug = 0;
+static unsigned int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug,"enable debug messages");
 
@@ -45,7 +46,7 @@
 	struct videobuf_buffer *buf;
 	unsigned long flags;
 	int err;
-	struct videobuf_dmabuf *dma;
+	void *outp;
 
 	dprintk("dvb thread started\n");
 	set_freezable();
@@ -66,9 +67,10 @@
 		try_to_freeze();
 
 		/* feed buffer data to demux */
-		dma=videobuf_to_dma(buf);
+		outp = videobuf_queue_to_vmalloc (&dvb->dvbq, buf);
+
 		if (buf->state == VIDEOBUF_DONE)
-			dvb_dmx_swfilter(&dvb->demux, dma->vmalloc,
+			dvb_dmx_swfilter(&dvb->demux, outp,
 					 buf->size);
 
 		/* requeue buffer */
@@ -138,14 +140,16 @@
 int videobuf_dvb_register(struct videobuf_dvb *dvb,
 			  struct module *module,
 			  void *adapter_priv,
-			  struct device *device)
+			  struct device *device,
+			  short *adapter_nr)
 {
 	int result;
 
 	mutex_init(&dvb->lock);
 
 	/* register adapter */
-	result = dvb_register_adapter(&dvb->adapter, dvb->name, module, device);
+	result = dvb_register_adapter(&dvb->adapter, dvb->name, module, device,
+				      adapter_nr);
 	if (result < 0) {
 		printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n",
 		       dvb->name, result);
diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c
index 5266ecc9..c91e1d8 100644
--- a/drivers/media/video/videobuf-vmalloc.c
+++ b/drivers/media/video/videobuf-vmalloc.c
@@ -33,7 +33,7 @@
 #define MAGIC_CHECK(is,should)	if (unlikely((is) != (should))) \
 	{ printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); }
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0644);
 
 MODULE_DESCRIPTION("helper module to manage video4linux vmalloc buffers");
@@ -57,20 +57,26 @@
 	map->count++;
 }
 
-static void
-videobuf_vm_close(struct vm_area_struct *vma)
+static void videobuf_vm_close(struct vm_area_struct *vma)
 {
 	struct videobuf_mapping *map = vma->vm_private_data;
 	struct videobuf_queue *q = map->q;
 	int i;
 
-	dprintk(2,"vm_close %p [count=%u,vma=%08lx-%08lx]\n",map,
-		map->count,vma->vm_start,vma->vm_end);
+	dprintk(2,"vm_close %p [count=%u,vma=%08lx-%08lx]\n", map,
+		map->count, vma->vm_start, vma->vm_end);
 
 	map->count--;
 	if (0 == map->count) {
-		dprintk(1,"munmap %p q=%p\n",map,q);
+		struct videobuf_vmalloc_memory *mem;
+
+		dprintk(1, "munmap %p q=%p\n", map, q);
 		mutex_lock(&q->vb_lock);
+
+		/* We need first to cancel streams, before unmapping */
+		if (q->streaming)
+			videobuf_queue_cancel(q);
+
 		for (i = 0; i < VIDEO_MAX_FRAME; i++) {
 			if (NULL == q->bufs[i])
 				continue;
@@ -78,14 +84,35 @@
 			if (q->bufs[i]->map != map)
 				continue;
 
-			q->ops->buf_release(q,q->bufs[i]);
+			mem = q->bufs[i]->priv;
+			if (mem) {
+				/* This callback is called only if kernel has
+				   allocated memory and this memory is mmapped.
+				   In this case, memory should be freed,
+				   in order to do memory unmap.
+				 */
+
+				MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
+
+				/* vfree is not atomic - can't be
+				   called with IRQ's disabled
+				 */
+				dprintk(1, "%s: buf[%d] freeing (%p)\n",
+					__func__, i, mem->vmalloc);
+
+				vfree(mem->vmalloc);
+				mem->vmalloc = NULL;
+			}
 
 			q->bufs[i]->map   = NULL;
 			q->bufs[i]->baddr = 0;
 		}
-		mutex_unlock(&q->vb_lock);
+
 		kfree(map);
+
+		mutex_unlock(&q->vb_lock);
 	}
+
 	return;
 }
 
@@ -102,7 +129,7 @@
 /* Allocated area consists on 3 parts:
 	struct video_buffer
 	struct <driver>_buffer (cx88_buffer, saa7134_buf, ...)
-	struct videobuf_pci_sg_memory
+	struct videobuf_dma_sg_memory
  */
 
 static void *__videobuf_alloc(size_t size)
@@ -116,7 +143,7 @@
 	mem->magic=MAGIC_VMAL_MEM;
 
 	dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
-		__FUNCTION__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb),
+		__func__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb),
 		mem,(long)sizeof(*mem));
 
 	return vb;
@@ -126,45 +153,74 @@
 			      struct videobuf_buffer *vb,
 			      struct v4l2_framebuffer *fbuf)
 {
+	struct videobuf_vmalloc_memory *mem = vb->priv;
 	int pages;
-	struct videobuf_vmalloc_memory *mem=vb->priv;
 
 	BUG_ON(!mem);
 
-	MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
+	MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
 
-	pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;
+	switch (vb->memory) {
+	case V4L2_MEMORY_MMAP:
+		dprintk(1, "%s memory method MMAP\n", __func__);
 
-	/* Currently, doesn't support V4L2_MEMORY_OVERLAY */
-	if ((vb->memory != V4L2_MEMORY_MMAP) &&
-				(vb->memory != V4L2_MEMORY_USERPTR) ) {
-		printk(KERN_ERR "Method currently unsupported.\n");
-		return -EINVAL;
-	}
-
-	/* FIXME: should be tested with kernel mmap mem */
-	mem->vmalloc=vmalloc_user (PAGE_ALIGN(vb->size));
-	if (NULL == mem->vmalloc) {
-		printk(KERN_ERR "vmalloc (%d pages) failed\n",pages);
-		return -ENOMEM;
-	}
-
-	dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n",
-				(unsigned long)mem->vmalloc,
-				pages << PAGE_SHIFT);
-
-	/* It seems that some kernel versions need to do remap *after*
-	   the mmap() call
-	 */
-	if (mem->vma) {
-		int retval=remap_vmalloc_range(mem->vma, mem->vmalloc,0);
-		kfree(mem->vma);
-		mem->vma=NULL;
-		if (retval<0) {
-			dprintk(1,"mmap app bug: remap_vmalloc_range area %p error %d\n",
-				mem->vmalloc,retval);
-			return retval;
+		/* All handling should be done by __videobuf_mmap_mapper() */
+		if (!mem->vmalloc) {
+			printk(KERN_ERR "memory is not alloced/mmapped.\n");
+			return -EINVAL;
 		}
+		break;
+	case V4L2_MEMORY_USERPTR:
+		pages = PAGE_ALIGN(vb->size);
+
+		dprintk(1, "%s memory method USERPTR\n", __func__);
+
+#if 1
+		if (vb->baddr) {
+			printk(KERN_ERR "USERPTR is currently not supported\n");
+			return -EINVAL;
+		}
+#endif
+
+		/* The only USERPTR currently supported is the one needed for
+		   read() method.
+		 */
+
+		mem->vmalloc = vmalloc_user(pages);
+		if (!mem->vmalloc) {
+			printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
+			return -ENOMEM;
+		}
+		dprintk(1, "vmalloc is at addr %p (%d pages)\n",
+			mem->vmalloc, pages);
+
+#if 0
+		int rc;
+		/* Kernel userptr is used also by read() method. In this case,
+		   there's no need to remap, since data will be copied to user
+		 */
+		if (!vb->baddr)
+			return 0;
+
+		/* FIXME: to properly support USERPTR, remap should occur.
+		   The code bellow won't work, since mem->vma = NULL
+		 */
+		/* Try to remap memory */
+		rc = remap_vmalloc_range(mem->vma, (void *)vb->baddr, 0);
+		if (rc < 0) {
+			printk(KERN_ERR "mmap: remap failed with error %d. ", rc);
+			return -ENOMEM;
+		}
+#endif
+
+		break;
+	case V4L2_MEMORY_OVERLAY:
+	default:
+		dprintk(1, "%s memory method OVERLAY/unknown\n", __func__);
+
+		/* Currently, doesn't support V4L2_MEMORY_OVERLAY */
+		printk(KERN_ERR "Memory method currently unsupported.\n");
+		return -EINVAL;
 	}
 
 	return 0;
@@ -180,6 +236,7 @@
 {
 	unsigned int i;
 
+	dprintk(1, "%s\n", __func__);
 	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
 		if (q->bufs[i]) {
 			if (q->bufs[i]->map)
@@ -196,10 +253,11 @@
 	struct videobuf_vmalloc_memory *mem;
 	struct videobuf_mapping *map;
 	unsigned int first;
-	int retval;
+	int retval, pages;
 	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
 
-	if (! (vma->vm_flags & VM_WRITE) || ! (vma->vm_flags & VM_SHARED))
+	dprintk(1, "%s\n", __func__);
+	if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED))
 		return -EINVAL;
 
 	/* look for first buffer to map */
@@ -219,46 +277,55 @@
 	}
 
 	/* create mapping + update buffer list */
-	map = q->bufs[first]->map = kzalloc(sizeof(struct videobuf_mapping),GFP_KERNEL);
+	map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
 	if (NULL == map)
 		return -ENOMEM;
 
+	q->bufs[first]->map = map;
 	map->start = vma->vm_start;
 	map->end   = vma->vm_end;
 	map->q     = q;
 
 	q->bufs[first]->baddr = vma->vm_start;
 
+	mem = q->bufs[first]->priv;
+	BUG_ON(!mem);
+	MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
+
+	pages = PAGE_ALIGN(vma->vm_end - vma->vm_start);
+	mem->vmalloc = vmalloc_user(pages);
+	if (!mem->vmalloc) {
+		printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
+		goto error;
+	}
+	dprintk(1, "vmalloc is at addr %p (%d pages)\n",
+		mem->vmalloc, pages);
+
+	/* Try to remap memory */
+	retval = remap_vmalloc_range(vma, mem->vmalloc, 0);
+	if (retval < 0) {
+		printk(KERN_ERR "mmap: remap failed with error %d. ", retval);
+		vfree(mem->vmalloc);
+		goto error;
+	}
+
 	vma->vm_ops          = &videobuf_vm_ops;
 	vma->vm_flags       |= VM_DONTEXPAND | VM_RESERVED;
 	vma->vm_private_data = map;
 
-	mem=q->bufs[first]->priv;
-	BUG_ON (!mem);
-	MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
-
-	/* Try to remap memory */
-	retval=remap_vmalloc_range(vma, mem->vmalloc,0);
-	if (retval<0) {
-		dprintk(1,"mmap: postponing remap_vmalloc_range\n");
-
-		mem->vma=kmalloc(sizeof(*vma),GFP_KERNEL);
-		if (!mem->vma) {
-			kfree(map);
-			q->bufs[first]->map=NULL;
-			return -ENOMEM;
-		}
-		memcpy(mem->vma,vma,sizeof(*vma));
-	}
-
 	dprintk(1,"mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
-		map,q,vma->vm_start,vma->vm_end,
+		map, q, vma->vm_start, vma->vm_end,
 		(long int) q->bufs[first]->bsize,
-		vma->vm_pgoff,first);
+		vma->vm_pgoff, first);
 
 	videobuf_vm_open(vma);
 
-	return (0);
+	return 0;
+
+error:
+	mem = NULL;
+	kfree(map);
+	return -ENOMEM;
 }
 
 static int __videobuf_copy_to_user ( struct videobuf_queue *q,
@@ -320,6 +387,7 @@
 	.mmap_mapper  = __videobuf_mmap_mapper,
 	.video_copy_to_user = __videobuf_copy_to_user,
 	.copy_stream  = __videobuf_copy_stream,
+	.vmalloc      = videobuf_to_vmalloc,
 };
 
 void videobuf_queue_vmalloc_init(struct videobuf_queue* q,
@@ -349,13 +417,24 @@
 
 void videobuf_vmalloc_free (struct videobuf_buffer *buf)
 {
-	struct videobuf_vmalloc_memory *mem=buf->priv;
-	BUG_ON (!mem);
+	struct videobuf_vmalloc_memory *mem = buf->priv;
 
-	MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
+	/* mmapped memory can't be freed here, otherwise mmapped region
+	   would be released, while still needed. In this case, the memory
+	   release should happen inside videobuf_vm_close().
+	   So, it should free memory only if the memory were allocated for
+	   read() operation.
+	 */
+	if ((buf->memory != V4L2_MEMORY_USERPTR) || (buf->baddr == 0))
+		return;
+
+	if (!mem)
+		return;
+
+	MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
 
 	vfree(mem->vmalloc);
-	mem->vmalloc=NULL;
+	mem->vmalloc = NULL;
 
 	return;
 }
diff --git a/drivers/media/video/videocodec.c b/drivers/media/video/videocodec.c
index 87951ec..cf24956 100644
--- a/drivers/media/video/videocodec.c
+++ b/drivers/media/video/videocodec.c
@@ -39,12 +39,13 @@
 
 #ifdef CONFIG_PROC_FS
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <asm/uaccess.h>
 #endif
 
 #include "videocodec.h"
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-4)");
 
@@ -320,56 +321,22 @@
 }
 
 #ifdef CONFIG_PROC_FS
-/* ============ */
-/* procfs stuff */
-/* ============ */
-
-static char *videocodec_buf = NULL;
-static int videocodec_bufsize = 0;
-
-static int
-videocodec_build_table (void)
+static int proc_videocodecs_show(struct seq_file *m, void *v)
 {
 	struct codec_list *h = codeclist_top;
 	struct attached_list *a;
-	int i = 0, size;
 
-	// sum up amount of slaves plus their attached masters
-	while (h) {
-		i += h->attached + 1;
-		h = h->next;
-	}
-#define LINESIZE 100
-	size = LINESIZE * (i + 1);
-
-	dprintk(3, "videocodec_build table: %d entries, %d bytes\n", i,
-		size);
-
-	kfree(videocodec_buf);
-	videocodec_buf = kmalloc(size, GFP_KERNEL);
-
-	if (!videocodec_buf)
-		return 0;
-
-	i = 0;
-	i += scnprintf(videocodec_buf + i, size - 1,
-		      "<S>lave or attached <M>aster name  type flags    magic    ");
-	i += scnprintf(videocodec_buf + i, size -i - 1, "(connected as)\n");
+	seq_printf(m, "<S>lave or attached <M>aster name  type flags    magic    ");
+	seq_printf(m, "(connected as)\n");
 
 	h = codeclist_top;
 	while (h) {
-		if (i > (size - LINESIZE))
-			break;	// security check
-		i += scnprintf(videocodec_buf + i, size -i -1,
-			      "S %32s %04x %08lx %08lx (TEMPLATE)\n",
+		seq_printf(m, "S %32s %04x %08lx %08lx (TEMPLATE)\n",
 			      h->codec->name, h->codec->type,
 			      h->codec->flags, h->codec->magic);
 		a = h->list;
 		while (a) {
-			if (i > (size - LINESIZE))
-				break;	// security check
-			i += scnprintf(videocodec_buf + i, size -i -1,
-				      "M %32s %04x %08lx %08lx (%s)\n",
+			seq_printf(m, "M %32s %04x %08lx %08lx (%s)\n",
 				      a->codec->master_data->name,
 				      a->codec->master_data->type,
 				      a->codec->master_data->flags,
@@ -380,54 +347,21 @@
 		h = h->next;
 	}
 
-	return i;
+	return 0;
 }
 
-//The definition:
-//typedef int (read_proc_t)(char *page, char **start, off_t off,
-//                          int count, int *eof, void *data);
-
-static int
-videocodec_info (char  *buffer,
-		 char **buffer_location,
-		 off_t  offset,
-		 int    buffer_length,
-		 int   *eof,
-		 void  *data)
+static int proc_videocodecs_open(struct inode *inode, struct file *file)
 {
-	int size;
-
-	dprintk(3, "videocodec_info: offset: %ld, len %d / size %d\n",
-		offset, buffer_length, videocodec_bufsize);
-
-	if (offset == 0) {
-		videocodec_bufsize = videocodec_build_table();
-	}
-	if ((offset < 0) || (offset >= videocodec_bufsize)) {
-		dprintk(4,
-			"videocodec_info: call delivers no result, return 0\n");
-		*eof = 1;
-		return 0;
-	}
-
-	if (buffer_length < (videocodec_bufsize - offset)) {
-		dprintk(4, "videocodec_info: %ld needed, %d got\n",
-			videocodec_bufsize - offset, buffer_length);
-		size = buffer_length;
-	} else {
-		dprintk(4, "videocodec_info: last reading of %ld bytes\n",
-			videocodec_bufsize - offset);
-		size = videocodec_bufsize - offset;
-		*eof = 1;
-	}
-
-	memcpy(buffer, videocodec_buf + offset, size);
-	/* doesn't work...                           */
-	/* copy_to_user(buffer, videocodec_buf+offset, size); */
-	/* *buffer_location = videocodec_buf+offset; */
-
-	return size;
+	return single_open(file, proc_videocodecs_show, NULL);
 }
+
+static const struct file_operations videocodecs_proc_fops = {
+	.owner		= THIS_MODULE,
+	.open		= proc_videocodecs_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
 #endif
 
 /* ===================== */
@@ -444,16 +378,8 @@
 	       VIDEOCODEC_VERSION);
 
 #ifdef CONFIG_PROC_FS
-	videocodec_buf = NULL;
-	videocodec_bufsize = 0;
-
-	videocodec_proc_entry = create_proc_entry("videocodecs", 0, NULL);
-	if (videocodec_proc_entry) {
-		videocodec_proc_entry->read_proc = videocodec_info;
-		videocodec_proc_entry->write_proc = NULL;
-		videocodec_proc_entry->data = NULL;
-		videocodec_proc_entry->owner = THIS_MODULE;
-	} else {
+	videocodec_proc_entry = proc_create("videocodecs", 0, NULL, &videocodecs_proc_fops);
+	if (!videocodec_proc_entry) {
 		dprintk(1, KERN_ERR "videocodec: can't init procfs.\n");
 	}
 #endif
@@ -465,7 +391,6 @@
 {
 #ifdef CONFIG_PROC_FS
 	remove_proc_entry("videocodecs", NULL);
-	kfree(videocodec_buf);
 #endif
 }
 
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index 0d9b637..31e8af0 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -18,14 +18,14 @@
 
 #define dbgarg(cmd, fmt, arg...) \
 		if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {		\
-			printk (KERN_DEBUG "%s: ",  vfd->name);		\
+			printk(KERN_DEBUG "%s: ",  vfd->name);		\
 			v4l_printk_ioctl(cmd);				\
-			printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg); \
+			printk(" " fmt,  ## arg);			\
 		}
 
 #define dbgarg2(fmt, arg...) \
 		if (vfd->debug & V4L2_DEBUG_IOCTL_ARG)			\
-			printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg);
+			printk(KERN_DEBUG "%s: " fmt, vfd->name, ## arg);
 
 #include <linux/module.h>
 #include <linux/types.h>
@@ -378,7 +378,35 @@
    external ioctl messages as well as internal V4L ioctl */
 void v4l_printk_ioctl(unsigned int cmd)
 {
-	char *dir;
+	char *dir, *type;
+
+	switch (_IOC_TYPE(cmd)) {
+	case 'd':
+		if (_IOC_NR(cmd) >= V4L2_INT_IOCTLS) {
+			type = "v4l2_int";
+			break;
+		}
+		printk("%s", v4l2_int_ioctls[_IOC_NR(cmd)]);
+		return;
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+	case 'v':
+		if (_IOC_NR(cmd) >= V4L1_IOCTLS) {
+			type = "v4l1";
+			break;
+		}
+		printk("%s", v4l1_ioctls[_IOC_NR(cmd)]);
+		return;
+#endif
+	case 'V':
+		if (_IOC_NR(cmd) >= V4L2_IOCTLS) {
+			type = "v4l2";
+			break;
+		}
+		printk("%s", v4l2_ioctls[_IOC_NR(cmd)]);
+		return;
+	default:
+		type = "unknown";
+	}
 
 	switch (_IOC_DIR(cmd)) {
 	case _IOC_NONE:              dir = "--"; break;
@@ -387,29 +415,8 @@
 	case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
 	default:                     dir = "*ERR*"; break;
 	}
-	switch (_IOC_TYPE(cmd)) {
-	case 'd':
-		printk("v4l2_int ioctl %s, dir=%s (0x%08x)\n",
-		       (_IOC_NR(cmd) < V4L2_INT_IOCTLS) ?
-		       v4l2_int_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd);
-		break;
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-	case 'v':
-		printk("v4l1 ioctl %s, dir=%s (0x%08x)\n",
-		       (_IOC_NR(cmd) < V4L1_IOCTLS) ?
-		       v4l1_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd);
-		break;
-#endif
-	case 'V':
-		printk("v4l2 ioctl %s, dir=%s (0x%08x)\n",
-		       (_IOC_NR(cmd) < V4L2_IOCTLS) ?
-		       v4l2_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd);
-		break;
-
-	default:
-		printk("unknown ioctl '%c', dir=%s, #%d (0x%08x)\n",
-		       _IOC_TYPE(cmd), dir, _IOC_NR(cmd), cmd);
-	}
+	printk("%s ioctl '%c', dir=%s, #%d (0x%08x)",
+		type, _IOC_TYPE(cmd), dir, _IOC_NR(cmd), cmd);
 }
 EXPORT_SYMBOL(v4l_printk_ioctl);
 
@@ -774,6 +781,7 @@
 	if ( (vfd->debug & V4L2_DEBUG_IOCTL) &&
 				!(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) {
 		v4l_print_ioctl(vfd->name, cmd);
+		printk("\n");
 	}
 
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
@@ -1853,12 +1861,20 @@
 			dbgarg (cmd, "chip_ident=%u, revision=0x%x\n", p->ident, p->revision);
 		break;
 	}
+	default:
+	{
+		if (!vfd->vidioc_default)
+			break;
+		ret = vfd->vidioc_default(file, fh, cmd, arg);
+		break;
+	}
 	} /* switch */
 
 	if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {
 		if (ret<0) {
-			printk ("%s: err:\n", vfd->name);
+			printk("%s: err: on ", vfd->name);
 			v4l_print_ioctl(vfd->name, cmd);
+			printk("\n");
 		}
 	}
 
@@ -2019,7 +2035,7 @@
 			break;
 		default:
 			printk(KERN_ERR "%s called with unknown type: %d\n",
-			       __FUNCTION__, type);
+			       __func__, type);
 			return -1;
 	}
 
@@ -2057,7 +2073,7 @@
 	ret = device_register(&vfd->class_dev);
 	if (ret < 0) {
 		printk(KERN_ERR "%s: device_register failed\n",
-		       __FUNCTION__);
+		       __func__);
 		goto fail_minor;
 	}
 
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index 5bb7529..d545c98 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -333,7 +333,7 @@
  *
  * Use non-zero value to enable conversion.
  */
-static int vino_pixel_conversion = 0;
+static int vino_pixel_conversion;
 
 module_param_named(pixelconv, vino_pixel_conversion, int, 0);
 
@@ -4370,8 +4370,8 @@
 
 /* Initialization and cleanup */
 
-// __initdata
-static int vino_init_stage = 0;
+/* __initdata */
+static int vino_init_stage;
 
 static const struct file_operations vino_fops = {
 	.owner		= THIS_MODULE,
@@ -4385,8 +4385,8 @@
 
 static struct video_device v4l_device_template = {
 	.name		= "NOT SET",
-	//.type		= VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE |
-	//	VID_TYPE_CLIPPING | VID_TYPE_SCALES, VID_TYPE_OVERLAY
+	/*.type		= VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE | */
+	/*	VID_TYPE_CLIPPING | VID_TYPE_SCALES, VID_TYPE_OVERLAY */
 	.fops		= &vino_fops,
 	.minor		= -1,
 };
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 1db067c..b1e9592 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -146,8 +146,6 @@
 
 struct vivi_dmaqueue {
 	struct list_head       active;
-	struct list_head       queued;
-	struct timer_list      timeout;
 
 	/* thread for generating video stream*/
 	struct task_struct         *kthread;
@@ -162,8 +160,8 @@
 struct vivi_dev {
 	struct list_head           vivi_devlist;
 
-	struct mutex               lock;
 	spinlock_t                 slock;
+	struct mutex		   mutex;
 
 	int                        users;
 
@@ -322,24 +320,26 @@
 end:
 	return;
 }
+
 static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
 {
 	int h , pos = 0;
 	int hmax  = buf->vb.height;
 	int wmax  = buf->vb.width;
 	struct timeval ts;
-	char *tmpbuf = kmalloc(wmax * 2, GFP_KERNEL);
+	char *tmpbuf = kmalloc(wmax * 2, GFP_ATOMIC);
 	void *vbuf = videobuf_to_vmalloc(&buf->vb);
 
 	if (!tmpbuf)
 		return;
 
+	if (!vbuf)
+		return;
+
 	for (h = 0; h < hmax; h++) {
 		gen_line(tmpbuf, 0, wmax, hmax, h, dev->mv_count,
 			 dev->timestr);
-		/* FIXME: replacing to __copy_to_user */
-		if (copy_to_user(vbuf + pos, tmpbuf, wmax * 2) != 0)
-			dprintk(dev, 2, "vivifill copy_to_user failed.\n");
+		memcpy(vbuf + pos, tmpbuf, wmax * 2);
 		pos += wmax*2;
 	}
 
@@ -372,107 +372,71 @@
 			dev->timestr, (unsigned long)tmpbuf, pos);
 
 	/* Advice that buffer was filled */
-	buf->vb.state = VIDEOBUF_DONE;
 	buf->vb.field_count++;
 	do_gettimeofday(&ts);
 	buf->vb.ts = ts;
-
-	list_del(&buf->vb.queue);
-	wake_up(&buf->vb.done);
+	buf->vb.state = VIDEOBUF_DONE;
 }
 
-static int restart_video_queue(struct vivi_dmaqueue *dma_q);
-
-static void vivi_thread_tick(struct vivi_dmaqueue  *dma_q)
+static void vivi_thread_tick(struct vivi_fh *fh)
 {
-	struct vivi_buffer    *buf;
-	struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
+	struct vivi_buffer *buf;
+	struct vivi_dev *dev = fh->dev;
+	struct vivi_dmaqueue *dma_q = &dev->vidq;
 
-	int bc;
+	unsigned long flags = 0;
 
-	spin_lock(&dev->slock);
-	/* Announces videobuf that all went ok */
-	for (bc = 0;; bc++) {
-		if (list_empty(&dma_q->active)) {
-			dprintk(dev, 1, "No active queue to serve\n");
-			break;
-		}
+	dprintk(dev, 1, "Thread tick\n");
 
-		buf = list_entry(dma_q->active.next,
-				 struct vivi_buffer, vb.queue);
-
-		/* Nobody is waiting something to be done, just return */
-		if (!waitqueue_active(&buf->vb.done)) {
-			mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
-			spin_unlock(&dev->slock);
-			return;
-		}
-
-		do_gettimeofday(&buf->vb.ts);
-		dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i);
-
-		/* Fill buffer */
-		vivi_fillbuff(dev, buf);
-
-		if (list_empty(&dma_q->active)) {
-			del_timer(&dma_q->timeout);
-		} else {
-			mod_timer(&dma_q->timeout, jiffies + BUFFER_TIMEOUT);
-		}
+	spin_lock_irqsave(&dev->slock, flags);
+	if (list_empty(&dma_q->active)) {
+		dprintk(dev, 1, "No active queue to serve\n");
+		goto unlock;
 	}
-	if (bc != 1)
-		dprintk(dev, 1, "%s: %d buffers handled (should be 1)\n",
-			__FUNCTION__, bc);
-	spin_unlock(&dev->slock);
+
+	buf = list_entry(dma_q->active.next,
+			 struct vivi_buffer, vb.queue);
+
+	/* Nobody is waiting on this buffer, return */
+	if (!waitqueue_active(&buf->vb.done))
+		goto unlock;
+
+	list_del(&buf->vb.queue);
+
+	do_gettimeofday(&buf->vb.ts);
+
+	/* Fill buffer */
+	vivi_fillbuff(dev, buf);
+	dprintk(dev, 1, "filled buffer %p\n", buf);
+
+	wake_up(&buf->vb.done);
+	dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i);
+unlock:
+	spin_unlock_irqrestore(&dev->slock, flags);
+	return;
 }
 
 #define frames_to_ms(frames)					\
 	((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR)
 
-static void vivi_sleep(struct vivi_dmaqueue  *dma_q)
+static void vivi_sleep(struct vivi_fh *fh)
 {
-	struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
-	int timeout, running_time;
+	struct vivi_dev *dev = fh->dev;
+	struct vivi_dmaqueue *dma_q = &dev->vidq;
+	int timeout;
 	DECLARE_WAITQUEUE(wait, current);
 
-	dprintk(dev, 1, "%s dma_q=0x%08lx\n", __FUNCTION__,
+	dprintk(dev, 1, "%s dma_q=0x%08lx\n", __func__,
 		(unsigned long)dma_q);
 
 	add_wait_queue(&dma_q->wq, &wait);
 	if (kthread_should_stop())
 		goto stop_task;
 
-	running_time = jiffies - dma_q->ini_jiffies;
-	dma_q->frame++;
-
 	/* Calculate time to wake up */
-	timeout = msecs_to_jiffies(frames_to_ms(dma_q->frame)) - running_time;
+	timeout = msecs_to_jiffies(frames_to_ms(1));
 
-	if (timeout > msecs_to_jiffies(frames_to_ms(2)) || timeout <= 0) {
-		int old = dma_q->frame;
-		int nframes;
-
-		dma_q->frame = (jiffies_to_msecs(running_time) /
-			       frames_to_ms(1)) + 1;
-
-		timeout = msecs_to_jiffies(frames_to_ms(dma_q->frame))
-			  - running_time;
-
-		if (unlikely (timeout <= 0))
-			timeout = 1;
-
-		nframes = (dma_q->frame > old)?
-				  dma_q->frame - old : old - dma_q->frame;
-
-		dprintk(dev, 1, "%ld: %s %d frames. "
-			"Current frame is %d. Will sleep for %d jiffies\n",
-			jiffies,
-			(dma_q->frame > old)? "Underrun, losed" : "Overrun of",
-			nframes, dma_q->frame, timeout);
-	} else
-		dprintk(dev, 1, "will sleep for %d jiffies\n", timeout);
-
-	vivi_thread_tick(dma_q);
+	vivi_thread_tick(fh);
 
 	schedule_timeout_interruptible(timeout);
 
@@ -483,16 +447,15 @@
 
 static int vivi_thread(void *data)
 {
-	struct vivi_dmaqueue  *dma_q = data;
-	struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
+	struct vivi_fh  *fh = data;
+	struct vivi_dev *dev = fh->dev;
 
 	dprintk(dev, 1, "thread started\n");
 
-	mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
 	set_freezable();
 
 	for (;;) {
-		vivi_sleep(dma_q);
+		vivi_sleep(fh);
 
 		if (kthread_should_stop())
 			break;
@@ -501,16 +464,17 @@
 	return 0;
 }
 
-static int vivi_start_thread(struct vivi_dmaqueue  *dma_q)
+static int vivi_start_thread(struct vivi_fh *fh)
 {
-	struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
+	struct vivi_dev *dev = fh->dev;
+	struct vivi_dmaqueue *dma_q = &dev->vidq;
 
 	dma_q->frame = 0;
 	dma_q->ini_jiffies = jiffies;
 
-	dprintk(dev, 1, "%s\n", __FUNCTION__);
+	dprintk(dev, 1, "%s\n", __func__);
 
-	dma_q->kthread = kthread_run(vivi_thread, dma_q, "vivi");
+	dma_q->kthread = kthread_run(vivi_thread, fh, "vivi");
 
 	if (IS_ERR(dma_q->kthread)) {
 		printk(KERN_ERR "vivi: kernel_thread() failed\n");
@@ -519,7 +483,7 @@
 	/* Wakes thread */
 	wake_up_interruptible(&dma_q->wq);
 
-	dprintk(dev, 1, "returning from %s\n", __FUNCTION__);
+	dprintk(dev, 1, "returning from %s\n", __func__);
 	return 0;
 }
 
@@ -527,7 +491,7 @@
 {
 	struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
 
-	dprintk(dev, 1, "%s\n", __FUNCTION__);
+	dprintk(dev, 1, "%s\n", __func__);
 	/* shutdown control thread */
 	if (dma_q->kthread) {
 		kthread_stop(dma_q->kthread);
@@ -535,91 +499,6 @@
 	}
 }
 
-static int restart_video_queue(struct vivi_dmaqueue *dma_q)
-{
-	struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
-	struct vivi_buffer *buf, *prev;
-
-	dprintk(dev, 1, "%s dma_q=0x%08lx\n", __FUNCTION__,
-		(unsigned long)dma_q);
-
-	if (!list_empty(&dma_q->active)) {
-		buf = list_entry(dma_q->active.next,
-				 struct vivi_buffer, vb.queue);
-		dprintk(dev, 2, "restart_queue [%p/%d]: restart dma\n",
-			buf, buf->vb.i);
-
-		dprintk(dev, 1, "Restarting video dma\n");
-		vivi_stop_thread(dma_q);
-
-		/* cancel all outstanding capture / vbi requests */
-		list_for_each_entry_safe(buf, prev, &dma_q->active, vb.queue) {
-			list_del(&buf->vb.queue);
-			buf->vb.state = VIDEOBUF_ERROR;
-			wake_up(&buf->vb.done);
-		}
-		mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
-
-		return 0;
-	}
-
-	prev = NULL;
-	for (;;) {
-		if (list_empty(&dma_q->queued))
-			return 0;
-		buf = list_entry(dma_q->queued.next,
-				 struct vivi_buffer, vb.queue);
-		if (NULL == prev) {
-			list_del(&buf->vb.queue);
-			list_add_tail(&buf->vb.queue, &dma_q->active);
-
-			dprintk(dev, 1, "Restarting video dma\n");
-			vivi_stop_thread(dma_q);
-			vivi_start_thread(dma_q);
-
-			buf->vb.state = VIDEOBUF_ACTIVE;
-			mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
-			dprintk(dev, 2,
-				"[%p/%d] restart_queue - first active\n",
-				buf, buf->vb.i);
-
-		} else if (prev->vb.width  == buf->vb.width  &&
-			   prev->vb.height == buf->vb.height &&
-			   prev->fmt       == buf->fmt) {
-			list_del(&buf->vb.queue);
-			list_add_tail(&buf->vb.queue, &dma_q->active);
-			buf->vb.state = VIDEOBUF_ACTIVE;
-			dprintk(dev, 2,
-				"[%p/%d] restart_queue - move to active\n",
-				buf, buf->vb.i);
-		} else {
-			return 0;
-		}
-		prev = buf;
-	}
-}
-
-static void vivi_vid_timeout(unsigned long data)
-{
-	struct vivi_dev      *dev  = (struct vivi_dev *)data;
-	struct vivi_dmaqueue *vidq = &dev->vidq;
-	struct vivi_buffer   *buf;
-
-	spin_lock(&dev->slock);
-
-	while (!list_empty(&vidq->active)) {
-		buf = list_entry(vidq->active.next,
-				 struct vivi_buffer, vb.queue);
-		list_del(&buf->vb.queue);
-		buf->vb.state = VIDEOBUF_ERROR;
-		wake_up(&buf->vb.done);
-		printk(KERN_INFO "vivi/0: [%p/%d] timeout\n", buf, buf->vb.i);
-	}
-	restart_video_queue(vidq);
-
-	spin_unlock(&dev->slock);
-}
-
 /* ------------------------------------------------------------------
 	Videobuf operations
    ------------------------------------------------------------------*/
@@ -637,7 +516,7 @@
 	while (*size * *count > vid_limit * 1024 * 1024)
 		(*count)--;
 
-	dprintk(dev, 1, "%s, count=%d, size=%d\n", __FUNCTION__,
+	dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__,
 		*count, *size);
 
 	return 0;
@@ -648,13 +527,13 @@
 	struct vivi_fh  *fh = vq->priv_data;
 	struct vivi_dev *dev  = fh->dev;
 
-	dprintk(dev, 1, "%s\n", __FUNCTION__);
+	dprintk(dev, 1, "%s, state: %i\n", __func__, buf->vb.state);
 
 	if (in_interrupt())
 		BUG();
 
-	videobuf_waiton(&buf->vb, 0, 0);
 	videobuf_vmalloc_free(&buf->vb);
+	dprintk(dev, 1, "free_buffer: freed\n");
 	buf->vb.state = VIDEOBUF_NEEDS_INIT;
 }
 
@@ -667,28 +546,25 @@
 	struct vivi_fh     *fh  = vq->priv_data;
 	struct vivi_dev    *dev = fh->dev;
 	struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
-	int rc, init_buffer = 0;
+	int rc;
 
-	dprintk(dev, 1, "%s, field=%d\n", __FUNCTION__, field);
+	dprintk(dev, 1, "%s, field=%d\n", __func__, field);
 
 	BUG_ON(NULL == fh->fmt);
+
 	if (fh->width  < 48 || fh->width  > norm_maxw() ||
 	    fh->height < 32 || fh->height > norm_maxh())
 		return -EINVAL;
+
 	buf->vb.size = fh->width*fh->height*2;
 	if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
 		return -EINVAL;
 
-	if (buf->fmt       != fh->fmt    ||
-	    buf->vb.width  != fh->width  ||
-	    buf->vb.height != fh->height ||
-	buf->vb.field  != field) {
-		buf->fmt       = fh->fmt;
-		buf->vb.width  = fh->width;
-		buf->vb.height = fh->height;
-		buf->vb.field  = field;
-		init_buffer = 1;
-	}
+	/* These properties only change when queue is idle, see s_fmt */
+	buf->fmt       = fh->fmt;
+	buf->vb.width  = fh->width;
+	buf->vb.height = fh->height;
+	buf->vb.field  = field;
 
 	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
 		rc = videobuf_iolock(vq, &buf->vb, NULL);
@@ -711,45 +587,12 @@
 	struct vivi_buffer    *buf  = container_of(vb, struct vivi_buffer, vb);
 	struct vivi_fh        *fh   = vq->priv_data;
 	struct vivi_dev       *dev  = fh->dev;
-	struct vivi_dmaqueue  *vidq = &dev->vidq;
-	struct vivi_buffer    *prev;
+	struct vivi_dmaqueue *vidq = &dev->vidq;
 
-	if (!list_empty(&vidq->queued)) {
-		dprintk(dev, 1, "adding vb queue=0x%08lx\n",
-			(unsigned long)&buf->vb.queue);
-		list_add_tail(&buf->vb.queue, &vidq->queued);
-		buf->vb.state = VIDEOBUF_QUEUED;
-		dprintk(dev, 2, "[%p/%d] buffer_queue - append to queued\n",
-			buf, buf->vb.i);
-	} else if (list_empty(&vidq->active)) {
-		list_add_tail(&buf->vb.queue, &vidq->active);
+	dprintk(dev, 1, "%s\n", __func__);
 
-		buf->vb.state = VIDEOBUF_ACTIVE;
-		mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
-		dprintk(dev, 2, "[%p/%d] buffer_queue - first active\n",
-			buf, buf->vb.i);
-
-		vivi_start_thread(vidq);
-	} else {
-		prev = list_entry(vidq->active.prev,
-				  struct vivi_buffer, vb.queue);
-		if (prev->vb.width  == buf->vb.width  &&
-		    prev->vb.height == buf->vb.height &&
-		    prev->fmt       == buf->fmt) {
-			list_add_tail(&buf->vb.queue, &vidq->active);
-			buf->vb.state = VIDEOBUF_ACTIVE;
-			dprintk(dev, 2,
-				"[%p/%d] buffer_queue - append to active\n",
-				buf, buf->vb.i);
-
-		} else {
-			list_add_tail(&buf->vb.queue, &vidq->queued);
-			buf->vb.state = VIDEOBUF_QUEUED;
-			dprintk(dev, 2,
-				"[%p/%d] buffer_queue - first queued\n",
-				buf, buf->vb.i);
-		}
-	}
+	buf->vb.state = VIDEOBUF_QUEUED;
+	list_add_tail(&buf->vb.queue, &vidq->active);
 }
 
 static void buffer_release(struct videobuf_queue *vq,
@@ -758,11 +601,8 @@
 	struct vivi_buffer   *buf  = container_of(vb, struct vivi_buffer, vb);
 	struct vivi_fh       *fh   = vq->priv_data;
 	struct vivi_dev      *dev  = (struct vivi_dev *)fh->dev;
-	struct vivi_dmaqueue *vidq = &dev->vidq;
 
-	dprintk(dev, 1, "%s\n", __FUNCTION__);
-
-	vivi_stop_thread(vidq);
+	dprintk(dev, 1, "%s\n", __func__);
 
 	free_buffer(vq, buf);
 }
@@ -869,17 +709,31 @@
 					struct v4l2_format *f)
 {
 	struct vivi_fh  *fh = priv;
+	struct videobuf_queue *q = &fh->vb_vidq;
+
 	int ret = vidioc_try_fmt_cap(file, fh, f);
 	if (ret < 0)
 		return (ret);
 
+	mutex_lock(&q->vb_lock);
+
+	if (videobuf_queue_is_busy(&fh->vb_vidq)) {
+		dprintk(fh->dev, 1, "%s queue busy\n", __func__);
+		ret = -EBUSY;
+		goto out;
+	}
+
 	fh->fmt           = &format;
 	fh->width         = f->fmt.pix.width;
 	fh->height        = f->fmt.pix.height;
 	fh->vb_vidq.field = f->fmt.pix.field;
 	fh->type          = f->type;
 
-	return (0);
+	ret = 0;
+out:
+	mutex_unlock(&q->vb_lock);
+
+	return (ret);
 }
 
 static int vidioc_reqbufs(struct file *file, void *priv,
@@ -1036,6 +890,7 @@
 	struct vivi_dev *dev;
 	struct vivi_fh *fh;
 	int i;
+	int retval = 0;
 
 	printk(KERN_DEBUG "vivi: open called (minor=%d)\n", minor);
 
@@ -1045,9 +900,15 @@
 	return -ENODEV;
 
 found:
-	/* If more than one user, mutex should be added */
+	mutex_lock(&dev->mutex);
 	dev->users++;
 
+	if (dev->users > 1) {
+		dev->users--;
+		retval = -EBUSY;
+		goto unlock;
+	}
+
 	dprintk(dev, 1, "open minor=%d type=%s users=%d\n", minor,
 		v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
 
@@ -1055,8 +916,13 @@
 	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
 	if (NULL == fh) {
 		dev->users--;
-		return -ENOMEM;
+		retval = -ENOMEM;
+		goto unlock;
 	}
+unlock:
+	mutex_unlock(&dev->mutex);
+	if (retval)
+		return retval;
 
 	file->private_data = fh;
 	fh->dev      = dev;
@@ -1084,6 +950,8 @@
 			NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED,
 			sizeof(struct vivi_buffer), fh);
 
+	vivi_start_thread(fh);
+
 	return 0;
 }
 
@@ -1106,7 +974,7 @@
 	struct vivi_dev       *dev = fh->dev;
 	struct videobuf_queue *q = &fh->vb_vidq;
 
-	dprintk(dev, 1, "%s\n", __FUNCTION__);
+	dprintk(dev, 1, "%s\n", __func__);
 
 	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
 		return POLLERR;
@@ -1128,7 +996,9 @@
 
 	kfree(fh);
 
+	mutex_lock(&dev->mutex);
 	dev->users--;
+	mutex_unlock(&dev->mutex);
 
 	dprintk(dev, 1, "close called (minor=%d, users=%d)\n",
 		minor, dev->users);
@@ -1182,6 +1052,7 @@
 	.read           = vivi_read,
 	.poll		= vivi_poll,
 	.ioctl          = video_ioctl2, /* V4L2 ioctl handler */
+	.compat_ioctl   = v4l_compat_ioctl32,
 	.mmap           = vivi_mmap,
 	.llseek         = no_llseek,
 };
@@ -1236,16 +1107,11 @@
 
 		/* init video dma queues */
 		INIT_LIST_HEAD(&dev->vidq.active);
-		INIT_LIST_HEAD(&dev->vidq.queued);
 		init_waitqueue_head(&dev->vidq.wq);
 
 		/* initialize locks */
-		mutex_init(&dev->lock);
 		spin_lock_init(&dev->slock);
-
-		dev->vidq.timeout.function = vivi_vid_timeout;
-		dev->vidq.timeout.data     = (unsigned long)dev;
-		init_timer(&dev->vidq.timeout);
+		mutex_init(&dev->mutex);
 
 		vfd = video_device_alloc();
 		if (NULL == vfd)
diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c
index a913385..35293029 100644
--- a/drivers/media/video/vpx3220.c
+++ b/drivers/media/video/vpx3220.c
@@ -40,7 +40,7 @@
 #define I2C_VPX3220        0x86
 #define VPX3220_DEBUG	KERN_DEBUG "vpx3220: "
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c
index 08aaae0..33f7026 100644
--- a/drivers/media/video/w9966.c
+++ b/drivers/media/video/w9966.c
@@ -61,10 +61,10 @@
 #include <media/v4l2-common.h>
 #include <linux/parport.h>
 
-//#define DEBUG				// Undef me for production
+/*#define DEBUG*/				/* Undef me for production */
 
 #ifdef DEBUG
-#define DPRINTF(x, a...) printk(KERN_DEBUG "W9966: %s(): "x, __FUNCTION__ , ##a)
+#define DPRINTF(x, a...) printk(KERN_DEBUG "W9966: %s(): "x, __func__ , ##a)
 #else
 #define DPRINTF(x...)
 #endif
@@ -134,7 +134,7 @@
 \tEg: >pardev=parport3,aggressive,parport2,parport1< would assign\n\
 \tcam 1 to parport3 and search every parport for cam 2 etc...");
 
-static int parmode = 0;
+static int parmode;
 module_param(parmode, int, 0);
 MODULE_PARM_DESC(parmode, "parmode: transfer mode (0=auto, 1=ecp, 2=epp");
 
@@ -188,7 +188,9 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl          = w9966_v4l_ioctl,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
+#endif
 	.read           = w9966_v4l_read,
 	.llseek         = no_llseek,
 };
diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c
index 2ae1430..8405224 100644
--- a/drivers/media/video/w9968cf.c
+++ b/drivers/media/video/w9968cf.c
@@ -3461,7 +3461,9 @@
 	.release = w9968cf_release,
 	.read =    w9968cf_read,
 	.ioctl =   w9968cf_ioctl,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl = v4l_compat_ioctl32,
+#endif
 	.mmap =    w9968cf_mmap,
 	.llseek =  no_llseek,
 };
@@ -3481,7 +3483,7 @@
 	enum w9968cf_model_id mod_id;
 	struct list_head* ptr;
 	u8 sc = 0; /* number of simultaneous cameras */
-	static unsigned short dev_nr = 0; /* we are handling device number n */
+	static unsigned short dev_nr; /* 0 - we are handling device number n */
 
 	if (le16_to_cpu(udev->descriptor.idVendor)  == winbond_id_table[0].idVendor &&
 	    le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[0].idProduct)
diff --git a/drivers/media/video/w9968cf.h b/drivers/media/video/w9968cf.h
index ec7696e..3c95316 100644
--- a/drivers/media/video/w9968cf.h
+++ b/drivers/media/video/w9968cf.h
@@ -298,7 +298,7 @@
 			dev_warn(&cam->dev, fmt "\n", ## args);               \
 		else if ((level) >= 5)                                        \
 			dev_info(&cam->dev, "[%s:%d] " fmt "\n",              \
-				 __FUNCTION__, __LINE__ , ## args);           \
+				 __func__, __LINE__ , ## args);           \
 	}                                                                     \
 }
 /* For generic kernel (not device specific) messages */
@@ -309,7 +309,7 @@
 		if ((level) >= 1 && (level) <= 4)                             \
 			pr_info("w9968cf: " fmt "\n", ## args);               \
 		else if ((level) >= 5)                                        \
-			pr_debug("w9968cf: [%s:%d] " fmt "\n", __FUNCTION__,  \
+			pr_debug("w9968cf: [%s:%d] " fmt "\n", __func__,  \
 				 __LINE__ , ## args);                         \
 	}                                                                     \
 }
@@ -321,7 +321,7 @@
 
 #undef PDBG
 #define PDBG(fmt, args...)                                                    \
-dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args);
+dev_info(&cam->dev, "[%s:%d] " fmt "\n", __func__, __LINE__ , ## args);
 
 #undef PDBGG
 #define PDBGG(fmt, args...) do {;} while(0); /* nothing: it's a placeholder */
diff --git a/drivers/media/video/zc0301/zc0301.h b/drivers/media/video/zc0301/zc0301.h
index a2de50e..7bbab54 100644
--- a/drivers/media/video/zc0301/zc0301.h
+++ b/drivers/media/video/zc0301/zc0301.h
@@ -160,7 +160,7 @@
 			dev_info(&cam->usbdev->dev, fmt "\n", ## args);       \
 		else if ((level) >= 3)                                        \
 			dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n",   \
-				 __FILE__, __FUNCTION__, __LINE__ , ## args); \
+				 __FILE__, __func__, __LINE__ , ## args); \
 	}                                                                     \
 } while (0)
 #	define KDBG(level, fmt, args...)                                      \
@@ -170,7 +170,7 @@
 			pr_info("zc0301: " fmt "\n", ## args);                \
 		else if ((level) == 3)                                        \
 			pr_debug("sn9c102: [%s:%s:%d] " fmt "\n", __FILE__,   \
-				 __FUNCTION__, __LINE__ , ## args);           \
+				 __func__, __LINE__ , ## args);           \
 	}                                                                     \
 } while (0)
 #	define V4LDBG(level, name, cmd)                                       \
@@ -186,7 +186,7 @@
 
 #undef PDBG
 #define PDBG(fmt, args...)                                                    \
-dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__,   \
+dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __func__,   \
 	 __LINE__ , ## args)
 
 #undef PDBGG
diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c
index 2c5665c..363dd2b 100644
--- a/drivers/media/video/zc0301/zc0301_core.c
+++ b/drivers/media/video/zc0301/zc0301_core.c
@@ -1925,7 +1925,9 @@
 	.open =    zc0301_open,
 	.release = zc0301_release,
 	.ioctl =   zc0301_ioctl,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl = v4l_compat_ioctl32,
+#endif
 	.read =    zc0301_read,
 	.poll =    zc0301_poll,
 	.mmap =    zc0301_mmap,
@@ -1939,7 +1941,7 @@
 {
 	struct usb_device *udev = interface_to_usbdev(intf);
 	struct zc0301_device* cam;
-	static unsigned int dev_nr = 0;
+	static unsigned int dev_nr;
 	unsigned int i;
 	int err = 0;
 
diff --git a/drivers/media/video/zoran.h b/drivers/media/video/zoran.h
index 498a43c..81cc3b0 100644
--- a/drivers/media/video/zoran.h
+++ b/drivers/media/video/zoran.h
@@ -243,10 +243,8 @@
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
 	int palette;
 #endif
-#ifdef CONFIG_VIDEO_V4L2
 	__u32 fourcc;
 	int colorspace;
-#endif
 	int depth;
 	__u32 flags;
 	__u32 vfespfr;
@@ -271,20 +269,6 @@
 	const struct zoran_format *format;	/* capture format */
 };
 
-/* whoops, this one is undeclared if !v4l2 */
-#ifndef CONFIG_VIDEO_V4L2
-struct v4l2_jpegcompression {
-	int quality;
-	int APPn;
-	int APP_len;
-	char APP_data[60];
-	int COM_len;
-	char COM_data[60];
-	__u32 jpeg_markers;
-	__u8 reserved[116];
-};
-#endif
-
 /* jpg-capture/-playback settings */
 struct zoran_jpg_settings {
 	int decimation;		/* this bit is used to set everything to default */
diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c
index 690281b..006d488 100644
--- a/drivers/media/video/zoran_card.c
+++ b/drivers/media/video/zoran_card.c
@@ -83,7 +83,7 @@
    or set in in a VIDIOCSFBUF ioctl
  */
 
-static unsigned long vidmem = 0;	/* Video memory base address */
+static unsigned long vidmem;	/* default = 0 - Video memory base address */
 module_param(vidmem, ulong, 0444);
 MODULE_PARM_DESC(vidmem, "Default video memory base address");
 
@@ -91,7 +91,7 @@
    Default input and video norm at startup of the driver.
 */
 
-static unsigned int default_input = 0;	/* 0=Composite, 1=S-Video */
+static unsigned int default_input;	/* default 0 = Composite, 1 = S-Video */
 module_param(default_input, uint, 0444);
 MODULE_PARM_DESC(default_input,
 		 "Default input (0=Composite, 1=S-Video, 2=Internal)");
@@ -101,7 +101,7 @@
 MODULE_PARM_DESC(default_mux,
 		 "Default 6 Eyes mux setting (Input selection)");
 
-static int default_norm = 0;	/* 0=PAL, 1=NTSC 2=SECAM */
+static int default_norm;	/* default 0 = PAL, 1 = NTSC 2 = SECAM */
 module_param(default_norm, int, 0444);
 MODULE_PARM_DESC(default_norm, "Default norm (0=PAL, 1=NTSC, 2=SECAM)");
 
diff --git a/drivers/media/video/zoran_card.h b/drivers/media/video/zoran_card.h
index 8444ca0..1b5c417 100644
--- a/drivers/media/video/zoran_card.h
+++ b/drivers/media/video/zoran_card.h
@@ -50,4 +50,6 @@
 extern void zoran_open_init_params(struct zoran *zr);
 extern void zoran_vdev_release(struct video_device *vdev);
 
+void zr36016_write(struct videocodec *codec, u16 reg, u32 val);
+
 #endif				/* __ZORAN_CARD_H__ */
diff --git a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c
index f97c206..7b60533 100644
--- a/drivers/media/video/zoran_device.c
+++ b/drivers/media/video/zoran_device.c
@@ -60,7 +60,8 @@
 
 extern const struct zoran_format zoran_formats[];
 
-static int lml33dpath = 0;	/* 1 will use digital path in capture
+static int lml33dpath;		/* default = 0
+				 * 1 will use digital path in capture
 				 * mode instead of analog. It can be
 				 * used for picture adjustments using
 				 * tool like xawtv while watching image
@@ -927,11 +928,6 @@
 	return isr;
 }
 
-/* hack */
-extern void zr36016_write (struct videocodec *codec,
-			   u16                reg,
-			   u32                val);
-
 void
 jpeg_start (struct zoran *zr)
 {
@@ -987,7 +983,7 @@
 zr36057_enable_jpg (struct zoran          *zr,
 		    enum zoran_codec_mode  mode)
 {
-	static int zero = 0;
+	static int zero;
 	static int one = 1;
 	struct vfe_settings cap;
 	int field_size =
@@ -1726,7 +1722,7 @@
 		return -EIO;
 
 	if (zr->card.type == LML33 &&
-	    (cmd == DECODER_SET_NORM || DECODER_SET_INPUT)) {
+	    (cmd == DECODER_SET_NORM || cmd == DECODER_SET_INPUT)) {
 		int res;
 
 		// Bt819 needs to reset its FIFO buffer using #FRST pin and
diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c
index fea4946..0134bec 100644
--- a/drivers/media/video/zoran_driver.c
+++ b/drivers/media/video/zoran_driver.c
@@ -85,7 +85,6 @@
 #include "zoran_device.h"
 #include "zoran_card.h"
 
-#ifdef CONFIG_VIDEO_V4L2
 	/* we declare some card type definitions here, they mean
 	 * the same as the v4l1 ZORAN_VID_TYPE above, except it's v4l2 */
 #define ZORAN_V4L2_VID_FLAGS ( \
@@ -94,19 +93,15 @@
 				V4L2_CAP_VIDEO_OUTPUT |\
 				V4L2_CAP_VIDEO_OVERLAY \
 			      )
-#endif
 
 #include <asm/byteorder.h>
 
-#if defined(CONFIG_VIDEO_V4L2) && defined(CONFIG_VIDEO_V4L1_COMPAT)
+#if defined(CONFIG_VIDEO_V4L1_COMPAT)
 #define ZFMT(pal, fcc, cs) \
 	.palette = (pal), .fourcc = (fcc), .colorspace = (cs)
-#elif defined(CONFIG_VIDEO_V4L2)
-#define ZFMT(pal, fcc, cs) \
-	.fourcc = (fcc), .colorspace = (cs)
 #else
 #define ZFMT(pal, fcc, cs) \
-	.palette = (pal)
+	.fourcc = (fcc), .colorspace = (cs)
 #endif
 
 const struct zoran_format zoran_formats[] = {
@@ -205,11 +200,10 @@
 extern int jpg_bufsize;
 extern int pass_through;
 
-static int lock_norm = 0;	/* 1=Don't change TV standard (norm) */
+static int lock_norm;	/* 0 = default 1 = Don't change TV standard (norm) */
 module_param(lock_norm, int, 0644);
 MODULE_PARM_DESC(lock_norm, "Prevent norm changes (1 = ignore, >1 = fail)");
 
-#ifdef CONFIG_VIDEO_V4L2
 	/* small helper function for calculating buffersizes for v4l2
 	 * we calculate the nearest higher power-of-two, which
 	 * will be the recommended buffersize */
@@ -232,7 +226,6 @@
 		return 8192;
 	return result;
 }
-#endif
 
 /* forward references */
 static void v4l_fbuffer_free(struct file *file);
@@ -1709,7 +1702,6 @@
 	return wait_grab_pending(zr);
 }
 
-#ifdef CONFIG_VIDEO_V4L2
 	/* get the status of a buffer in the clients buffer queue */
 static int
 zoran_v4l2_buffer_status (struct file        *file,
@@ -1815,7 +1807,6 @@
 
 	return 0;
 }
-#endif
 
 static int
 zoran_set_norm (struct zoran *zr,
@@ -2624,8 +2615,6 @@
 	}
 		break;
 
-#ifdef CONFIG_VIDEO_V4L2
-
 		/* The new video4linux2 capture interface - much nicer than video4linux1, since
 		 * it allows for integrating the JPEG capturing calls inside standard v4l2
 		 */
@@ -4197,7 +4186,6 @@
 		return 0;
 	}
 		break;
-#endif
 
 	default:
 		dprintk(1, KERN_DEBUG "%s: UNKNOWN ioctl cmd: 0x%x\n",
@@ -4247,7 +4235,7 @@
 		dprintk(3,
 			KERN_DEBUG
 			"%s: %s() raw - active=%c, sync_tail=%lu/%c, pend_tail=%lu, pend_head=%lu\n",
-			ZR_DEVNAME(zr), __FUNCTION__,
+			ZR_DEVNAME(zr), __func__,
 			"FAL"[fh->v4l_buffers.active], zr->v4l_sync_tail,
 			"UPMD"[zr->v4l_buffers.buffer[frame].state],
 			zr->v4l_pend_tail, zr->v4l_pend_head);
@@ -4269,7 +4257,7 @@
 		dprintk(3,
 			KERN_DEBUG
 			"%s: %s() jpg - active=%c, que_tail=%lu/%c, que_head=%lu, dma=%lu/%lu\n",
-			ZR_DEVNAME(zr), __FUNCTION__,
+			ZR_DEVNAME(zr), __func__,
 			"FAL"[fh->jpg_buffers.active], zr->jpg_que_tail,
 			"UPMD"[zr->jpg_buffers.buffer[frame].state],
 			zr->jpg_que_head, zr->jpg_dma_tail, zr->jpg_dma_head);
@@ -4644,7 +4632,9 @@
 	.open = zoran_open,
 	.release = zoran_close,
 	.ioctl = zoran_ioctl,
+#ifdef CONFIG_COMPAT
 	.compat_ioctl	= v4l_compat_ioctl32,
+#endif
 	.llseek = no_llseek,
 	.read = zoran_read,
 	.write = zoran_write,
@@ -4655,9 +4645,7 @@
 struct video_device zoran_template __devinitdata = {
 	.name = ZORAN_NAME,
 	.type = ZORAN_VID_TYPE,
-#ifdef CONFIG_VIDEO_V4L2
 	.type2 = ZORAN_V4L2_VID_FLAGS,
-#endif
 	.fops = &zoran_fops,
 	.release = &zoran_vdev_release,
 	.minor = -1
diff --git a/drivers/media/video/zr36016.c b/drivers/media/video/zr36016.c
index dd08455..00d132b 100644
--- a/drivers/media/video/zr36016.c
+++ b/drivers/media/video/zr36016.c
@@ -55,11 +55,10 @@
 #define MAX_CODECS 20
 
 /* amount of chips attached via this driver */
-static int zr36016_codecs = 0;
+static int zr36016_codecs;
 
 /* debugging is available via module parameter */
-
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-4)");
 
diff --git a/drivers/media/video/zr36050.c b/drivers/media/video/zr36050.c
index faae4ec..cf8b271 100644
--- a/drivers/media/video/zr36050.c
+++ b/drivers/media/video/zr36050.c
@@ -52,11 +52,10 @@
 #define MAX_CODECS 20
 
 /* amount of chips attached via this driver */
-static int zr36050_codecs = 0;
+static int zr36050_codecs;
 
 /* debugging is available via module parameter */
-
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-4)");
 
diff --git a/drivers/media/video/zr36060.c b/drivers/media/video/zr36060.c
index 7849b65..8e74054 100644
--- a/drivers/media/video/zr36060.c
+++ b/drivers/media/video/zr36060.c
@@ -52,14 +52,14 @@
 #define MAX_CODECS 20
 
 /* amount of chips attached via this driver */
-static int zr36060_codecs = 0;
+static int zr36060_codecs;
 
-static int low_bitrate = 0;
+static int low_bitrate;
 module_param(low_bitrate, bool, 0);
 MODULE_PARM_DESC(low_bitrate, "Buz compatibility option, halves bitrate");
 
 /* debugging is available via module parameter */
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-4)");
 
diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c
index 04949c8..a0e49dc 100644
--- a/drivers/media/video/zr364xx.c
+++ b/drivers/media/video/zr364xx.c
@@ -62,8 +62,8 @@
 
 
 /* Module parameters */
-static int debug = 0;
-static int mode = 0;
+static int debug;
+static int mode;
 
 
 /* Module parameters interface */
diff --git a/drivers/mfd/htc-pasic3.c b/drivers/mfd/htc-pasic3.c
index af66f4f..4edc120 100644
--- a/drivers/mfd/htc-pasic3.c
+++ b/drivers/mfd/htc-pasic3.c
@@ -19,8 +19,6 @@
 #include <linux/interrupt.h>
 #include <linux/mfd/htc-pasic3.h>
 
-#include <asm/arch/pxa-regs.h>
-
 struct pasic3_data {
 	void __iomem *mapping;
 	unsigned int bus_shift;
@@ -30,7 +28,6 @@
 
 #define REG_ADDR  5
 #define REG_DATA  6
-#define NUM_REGS  7
 
 #define READ_MODE 0x80
 
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 2399a37..015e163 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -827,7 +827,7 @@
 
 config BFIN_MAC
 	tristate "Blackfin 527/536/537 on-chip mac support"
-	depends on NET_ETHERNET && (BF527 || BF537 || BF536) && (!BF537_PORT_H)
+	depends on NET_ETHERNET && (BF527 || BF537 || BF536)
 	select CRC32
 	select MII
 	select PHYLIB
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 4dc5b4b..d3207c0 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -123,7 +123,6 @@
 	u32		minseq;		/* MP: min of most recent seqnos */
 	struct sk_buff_head mrq;	/* MP: receive reconstruction queue */
 #endif /* CONFIG_PPP_MULTILINK */
-	struct net_device_stats stats;	/* statistics */
 #ifdef CONFIG_PPP_FILTER
 	struct sock_filter *pass_filter;	/* filter for packets to pass */
 	struct sock_filter *active_filter;/* filter for pkts to reset idle */
@@ -914,18 +913,10 @@
 
  outf:
 	kfree_skb(skb);
-	++ppp->stats.tx_dropped;
+	++ppp->dev->stats.tx_dropped;
 	return 0;
 }
 
-static struct net_device_stats *
-ppp_net_stats(struct net_device *dev)
-{
-	struct ppp *ppp = (struct ppp *) dev->priv;
-
-	return &ppp->stats;
-}
-
 static int
 ppp_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
@@ -1095,8 +1086,8 @@
 #endif /* CONFIG_PPP_FILTER */
 	}
 
-	++ppp->stats.tx_packets;
-	ppp->stats.tx_bytes += skb->len - 2;
+	++ppp->dev->stats.tx_packets;
+	ppp->dev->stats.tx_bytes += skb->len - 2;
 
 	switch (proto) {
 	case PPP_IP:
@@ -1171,7 +1162,7 @@
  drop:
 	if (skb)
 		kfree_skb(skb);
-	++ppp->stats.tx_errors;
+	++ppp->dev->stats.tx_errors;
 }
 
 /*
@@ -1409,7 +1400,7 @@
 	spin_unlock_bh(&pch->downl);
 	if (ppp->debug & 1)
 		printk(KERN_ERR "PPP: no memory (fragment)\n");
-	++ppp->stats.tx_errors;
+	++ppp->dev->stats.tx_errors;
 	++ppp->nxseq;
 	return 1;	/* abandon the frame */
 }
@@ -1538,7 +1529,7 @@
 
 	if (skb->len > 0)
 		/* note: a 0-length skb is used as an error indication */
-		++ppp->stats.rx_length_errors;
+		++ppp->dev->stats.rx_length_errors;
 
 	kfree_skb(skb);
 	ppp_receive_error(ppp);
@@ -1547,7 +1538,7 @@
 static void
 ppp_receive_error(struct ppp *ppp)
 {
-	++ppp->stats.rx_errors;
+	++ppp->dev->stats.rx_errors;
 	if (ppp->vj)
 		slhc_toss(ppp->vj);
 }
@@ -1627,8 +1618,8 @@
 		break;
 	}
 
-	++ppp->stats.rx_packets;
-	ppp->stats.rx_bytes += skb->len - 2;
+	++ppp->dev->stats.rx_packets;
+	ppp->dev->stats.rx_bytes += skb->len - 2;
 
 	npi = proto_to_npindex(proto);
 	if (npi < 0) {
@@ -1806,7 +1797,7 @@
 	 */
 	if (seq_before(seq, ppp->nextseq)) {
 		kfree_skb(skb);
-		++ppp->stats.rx_dropped;
+		++ppp->dev->stats.rx_dropped;
 		ppp_receive_error(ppp);
 		return;
 	}
@@ -1928,7 +1919,7 @@
 		/* Got a complete packet yet? */
 		if (lost == 0 && (p->BEbits & E) && (head->BEbits & B)) {
 			if (len > ppp->mrru + 2) {
-				++ppp->stats.rx_length_errors;
+				++ppp->dev->stats.rx_length_errors;
 				printk(KERN_DEBUG "PPP: reconstructed packet"
 				       " is too long (%d)\n", len);
 			} else if (p == head) {
@@ -1937,7 +1928,7 @@
 				skb = skb_get(p);
 				break;
 			} else if ((skb = dev_alloc_skb(len)) == NULL) {
-				++ppp->stats.rx_missed_errors;
+				++ppp->dev->stats.rx_missed_errors;
 				printk(KERN_DEBUG "PPP: no memory for "
 				       "reconstructed packet");
 			} else {
@@ -1966,7 +1957,7 @@
 			if (ppp->debug & 1)
 				printk(KERN_DEBUG "  missed pkts %u..%u\n",
 				       ppp->nextseq, head->sequence-1);
-			++ppp->stats.rx_dropped;
+			++ppp->dev->stats.rx_dropped;
 			ppp_receive_error(ppp);
 		}
 
@@ -2377,12 +2368,12 @@
 	struct slcompress *vj = ppp->vj;
 
 	memset(st, 0, sizeof(*st));
-	st->p.ppp_ipackets = ppp->stats.rx_packets;
-	st->p.ppp_ierrors = ppp->stats.rx_errors;
-	st->p.ppp_ibytes = ppp->stats.rx_bytes;
-	st->p.ppp_opackets = ppp->stats.tx_packets;
-	st->p.ppp_oerrors = ppp->stats.tx_errors;
-	st->p.ppp_obytes = ppp->stats.tx_bytes;
+	st->p.ppp_ipackets = ppp->dev->stats.rx_packets;
+	st->p.ppp_ierrors = ppp->dev->stats.rx_errors;
+	st->p.ppp_ibytes = ppp->dev->stats.rx_bytes;
+	st->p.ppp_opackets = ppp->dev->stats.tx_packets;
+	st->p.ppp_oerrors = ppp->dev->stats.tx_errors;
+	st->p.ppp_obytes = ppp->dev->stats.tx_bytes;
 	if (!vj)
 		return;
 	st->vj.vjs_packets = vj->sls_o_compressed + vj->sls_o_uncompressed;
@@ -2436,7 +2427,6 @@
 	dev->priv = ppp;
 
 	dev->hard_start_xmit = ppp_start_xmit;
-	dev->get_stats = ppp_net_stats;
 	dev->do_ioctl = ppp_net_ioctl;
 
 	ret = -EEXIST;
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index d91856b..0ce07a3 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -668,16 +668,23 @@
 		break;
 
 	case TUNSETLINK:
+	{
+		int ret;
+
 		/* Only allow setting the type when the interface is down */
+		rtnl_lock();
 		if (tun->dev->flags & IFF_UP) {
 			DBG(KERN_INFO "%s: Linktype set failed because interface is up\n",
 				tun->dev->name);
-			return -EBUSY;
+			ret = -EBUSY;
 		} else {
 			tun->dev->type = (int) arg;
 			DBG(KERN_INFO "%s: linktype set to %d\n", tun->dev->name, tun->dev->type);
+			ret = 0;
 		}
-		break;
+		rtnl_unlock();
+		return ret;
+	}
 
 #ifdef TUN_DEBUG
 	case TUNSETDEBUG:
@@ -734,7 +741,12 @@
 	case SIOCADDMULTI:
 		/** Add the specified group to the character device's multicast filter
 		 * list. */
+		rtnl_lock();
+		netif_tx_lock_bh(tun->dev);
 		add_multi(tun->chr_filter, ifr.ifr_hwaddr.sa_data);
+		netif_tx_unlock_bh(tun->dev);
+		rtnl_unlock();
+
 		DBG(KERN_DEBUG "%s: add multi: %s\n",
 		    tun->dev->name, print_mac(mac, ifr.ifr_hwaddr.sa_data));
 		return 0;
@@ -742,7 +754,12 @@
 	case SIOCDELMULTI:
 		/** Remove the specified group from the character device's multicast
 		 * filter list. */
+		rtnl_lock();
+		netif_tx_lock_bh(tun->dev);
 		del_multi(tun->chr_filter, ifr.ifr_hwaddr.sa_data);
+		netif_tx_unlock_bh(tun->dev);
+		rtnl_unlock();
+
 		DBG(KERN_DEBUG "%s: del multi: %s\n",
 		    tun->dev->name, print_mac(mac, ifr.ifr_hwaddr.sa_data));
 		return 0;
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 7009219..c2642bc 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -56,8 +56,7 @@
 
 obj-$(CONFIG_ADM8211)	+= adm8211.o
 
-obj-$(CONFIG_IWL3945)	+= iwlwifi/
-obj-$(CONFIG_IWL4965)	+= iwlwifi/
+obj-$(CONFIG_IWLCORE)	+= iwlwifi/
 obj-$(CONFIG_RT2X00)	+= rt2x00/
 
 obj-$(CONFIG_P54_COMMON)	+= p54/
diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c
index 87e7822..5fb1ae6 100644
--- a/drivers/net/wireless/ath5k/hw.c
+++ b/drivers/net/wireless/ath5k/hw.c
@@ -304,14 +304,20 @@
 		ah->ah_radio = AR5K_RF2413;
 		ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A;
 	} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC2) {
-
 		ah->ah_radio = AR5K_RF5413;
+		ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A;
+	} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5133) {
 
-		if (ah->ah_mac_srev <= AR5K_SREV_VER_AR5424 &&
-			ah->ah_mac_srev >= AR5K_SREV_VER_AR2424)
+		/* AR5424 */
+		if (srev >= AR5K_SREV_VER_AR5424) {
+			ah->ah_radio = AR5K_RF5413;
 			ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5424;
-		else
+		/* AR2424 */
+		} else {
+			ah->ah_radio = AR5K_RF2413; /* For testing */
 			ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A;
+		}
+
 	/*
 	 * Register returns 0x4 for radio revision
 	 * so ath5k_hw_radio_revision doesn't parse the value
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
index 21c886a..6dcbb3c 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -980,6 +980,42 @@
 	destroy_ring(dma, tx_ring_mcast);
 }
 
+static int b43_dma_set_mask(struct b43_wldev *dev, u64 mask)
+{
+	u64 orig_mask = mask;
+	bool fallback = 0;
+	int err;
+
+	/* Try to set the DMA mask. If it fails, try falling back to a
+	 * lower mask, as we can always also support a lower one. */
+	while (1) {
+		err = ssb_dma_set_mask(dev->dev, mask);
+		if (!err)
+			break;
+		if (mask == DMA_64BIT_MASK) {
+			mask = DMA_32BIT_MASK;
+			fallback = 1;
+			continue;
+		}
+		if (mask == DMA_32BIT_MASK) {
+			mask = DMA_30BIT_MASK;
+			fallback = 1;
+			continue;
+		}
+		b43err(dev->wl, "The machine/kernel does not support "
+		       "the required %u-bit DMA mask\n",
+		       (unsigned int)dma_mask_to_engine_type(orig_mask));
+		return -EOPNOTSUPP;
+	}
+	if (fallback) {
+		b43info(dev->wl, "DMA mask fallback from %u-bit to %u-bit\n",
+			(unsigned int)dma_mask_to_engine_type(orig_mask),
+			(unsigned int)dma_mask_to_engine_type(mask));
+	}
+
+	return 0;
+}
+
 int b43_dma_init(struct b43_wldev *dev)
 {
 	struct b43_dma *dma = &dev->dma;
@@ -989,14 +1025,9 @@
 
 	dmamask = supported_dma_mask(dev);
 	type = dma_mask_to_engine_type(dmamask);
-	err = ssb_dma_set_mask(dev->dev, dmamask);
-	if (err) {
-		b43err(dev->wl, "The machine/kernel does not support "
-		       "the required DMA mask (0x%08X%08X)\n",
-		       (unsigned int)((dmamask & 0xFFFFFFFF00000000ULL) >> 32),
-		       (unsigned int)(dmamask & 0x00000000FFFFFFFFULL));
-		return -EOPNOTSUPP;
-	}
+	err = b43_dma_set_mask(dev, dmamask);
+	if (err)
+		return err;
 
 	err = -ENOMEM;
 	/* setup TX DMA channels. */
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 943cc85..4bf8a99 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -84,6 +84,10 @@
 module_param_named(qos, b43_modparam_qos, int, 0444);
 MODULE_PARM_DESC(qos, "Enable QOS support (default on)");
 
+static int modparam_btcoex = 1;
+module_param_named(btcoex, modparam_btcoex, int, 0444);
+MODULE_PARM_DESC(btcoex, "Enable Bluetooth coexistance (default on)");
+
 
 static const struct ssb_device_id b43_ssb_tbl[] = {
 	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5),
@@ -3706,8 +3710,10 @@
 static void b43_bluetooth_coext_enable(struct b43_wldev *dev)
 {
 	struct ssb_sprom *sprom = &dev->dev->bus->sprom;
-	u32 hf;
+	u64 hf;
 
+	if (!modparam_btcoex)
+		return;
 	if (!(sprom->boardflags_lo & B43_BFL_BTCOEXIST))
 		return;
 	if (dev->phy.type != B43_PHYTYPE_B && !dev->phy.gmode)
@@ -3719,11 +3725,13 @@
 	else
 		hf |= B43_HF_BTCOEX;
 	b43_hf_write(dev, hf);
-	//TODO
 }
 
 static void b43_bluetooth_coext_disable(struct b43_wldev *dev)
-{				//TODO
+{
+	if (!modparam_btcoex)
+		return;
+	//TODO
 }
 
 static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev)
@@ -3852,7 +3860,8 @@
 	struct ssb_sprom *sprom = &bus->sprom;
 	struct b43_phy *phy = &dev->phy;
 	int err;
-	u32 hf, tmp;
+	u64 hf;
+	u32 tmp;
 
 	B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT);
 
@@ -4414,8 +4423,16 @@
 	return err;
 }
 
+#define IS_PDEV(pdev, _vendor, _device, _subvendor, _subdevice)		( \
+	(pdev->vendor == PCI_VENDOR_ID_##_vendor) &&			\
+	(pdev->device == _device) &&					\
+	(pdev->subsystem_vendor == PCI_VENDOR_ID_##_subvendor) &&	\
+	(pdev->subsystem_device == _subdevice)				)
+
 static void b43_sprom_fixup(struct ssb_bus *bus)
 {
+	struct pci_dev *pdev;
+
 	/* boardflags workarounds */
 	if (bus->boardinfo.vendor == SSB_BOARDVENDOR_DELL &&
 	    bus->chip_id == 0x4301 && bus->boardinfo.rev == 0x74)
@@ -4423,6 +4440,13 @@
 	if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
 	    bus->boardinfo.type == 0x4E && bus->boardinfo.rev > 0x40)
 		bus->sprom.boardflags_lo |= B43_BFL_PACTRL;
+	if (bus->bustype == SSB_BUSTYPE_PCI) {
+		pdev = bus->host_pci;
+		if (IS_PDEV(pdev, BROADCOM, 0x4318, ASUSTEK, 0x100F) ||
+		    IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0015) ||
+		    IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0013))
+			bus->sprom.boardflags_lo &= ~B43_BFL_BTCOEXIST;
+	}
 }
 
 static void b43_wireless_exit(struct ssb_device *dev, struct b43_wl *wl)
diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c
index 575c543..de024dc 100644
--- a/drivers/net/wireless/b43/phy.c
+++ b/drivers/net/wireless/b43/phy.c
@@ -2043,7 +2043,7 @@
 void b43_set_rx_antenna(struct b43_wldev *dev, int antenna)
 {
 	struct b43_phy *phy = &dev->phy;
-	u32 hf;
+	u64 hf;
 	u16 tmp;
 	int autodiv = 0;
 
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 1a5678f..a1a0b3c 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -6907,7 +6907,6 @@
 
 	if (priv->vif != vif) {
 		IWL_DEBUG_MAC80211("leave - priv->vif != vif\n");
-		mutex_unlock(&priv->mutex);
 		return 0;
 	}
 
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index d7e2358..d0bbcaa 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -6473,7 +6473,6 @@
 
 	if (priv->vif != vif) {
 		IWL_DEBUG_MAC80211("leave - priv->vif != vif\n");
-		mutex_unlock(&priv->mutex);
 		return 0;
 	}
 
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index e5b3c28..5b375b2 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -1186,7 +1186,7 @@
 	rvalue |= mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
 	devindex = r.u;
 	/* Now get the key, return it */
-	if ((index < 0) || (index > 3))
+	if (index == -1 || index > 3)
 		/* no index provided, use the current one */
 		index = devindex;
 	rvalue |= mgt_get_request(priv, DOT11_OID_DEFKEYX, index, NULL, &r);
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 977751f..d0b1fb1 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -2402,7 +2402,6 @@
 	priv->param_power_output = modparam_power_output;
 	priv->param_roamtrigger  = modparam_roamtrigger;
 	priv->param_roamdelta    = modparam_roamdelta;
-	priv->param_workaround_interval = modparam_workaround_interval;
 
 	priv->param_country[0] = toupper(priv->param_country[0]);
 	priv->param_country[1] = toupper(priv->param_country[1]);
@@ -2425,8 +2424,10 @@
 	else if (priv->param_roamdelta > 2)
 		priv->param_roamdelta = 2;
 
-	if (priv->param_workaround_interval < 0)
+	if (modparam_workaround_interval < 0)
 		priv->param_workaround_interval = 500;
+	else
+		priv->param_workaround_interval = modparam_workaround_interval;
 
 	rndis_set_config_parameter_str(dev, "Country", priv->param_country);
 	rndis_set_config_parameter_str(dev, "FrameBursting",
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index ed8c069..8d88526 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -200,7 +200,6 @@
 config PCMCIA_SA1100
 	tristate "SA1100 support"
 	depends on ARM && ARCH_SA1100 && PCMCIA
-	depends on ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL || MACH_ARMCORE
 	help
 	  Say Y here to include support for SA11x0-based PCMCIA or CF
 	  sockets, found on HP iPAQs, Yopy, and other StrongARM(R)/
@@ -221,6 +220,7 @@
 config PCMCIA_PXA2XX
 	tristate "PXA2xx support"
 	depends on ARM && ARCH_PXA && PCMCIA
+	depends on ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL || MACH_ARMCORE
 	help
 	  Say Y here to include support for the PXA2xx PCMCIA controller
 
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index 46bb47f..5f55534 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -151,7 +151,8 @@
 {
 	struct bfin_serial_port *uart;
 	
-	if (CONFIG_KGDB_UART_PORT<0 || CONFIG_KGDB_UART_PORT>=NR_PORTS)
+	if (CONFIG_KGDB_UART_PORT < 0
+		|| CONFIG_KGDB_UART_PORT >= BFIN_UART_NR_PORTS)
 		uart = &bfin_serial_ports[0];
 	else
 		uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
@@ -173,7 +174,8 @@
 	struct bfin_serial_port *uart;
 	unsigned char chr;
 
-	if (CONFIG_KGDB_UART_PORT<0 || CONFIG_KGDB_UART_PORT>=NR_PORTS)
+	if (CONFIG_KGDB_UART_PORT < 0
+		|| CONFIG_KGDB_UART_PORT >= BFIN_UART_NR_PORTS)
 		uart = &bfin_serial_ports[0];
 	else
 		uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
@@ -192,7 +194,7 @@
 }
 #endif
 
-#if ANOMALY_05000230 && defined(CONFIG_SERIAL_BFIN_PIO)
+#if ANOMALY_05000363 && defined(CONFIG_SERIAL_BFIN_PIO)
 # define UART_GET_ANOMALY_THRESHOLD(uart)    ((uart)->anomaly_threshold)
 # define UART_SET_ANOMALY_THRESHOLD(uart, v) ((uart)->anomaly_threshold = (v))
 #else
@@ -237,7 +239,7 @@
 	}
 #endif
 
-	if (ANOMALY_05000230) {
+	if (ANOMALY_05000363) {
 		/* The BF533 (and BF561) family of processors have a nice anomaly
 		 * where they continuously generate characters for a "single" break.
 		 * We have to basically ignore this flood until the "next" valid
@@ -249,9 +251,6 @@
 		 * timeout was picked as it must absolutely be larger than 1
 		 * character time +/- some percent.  So 1.5 sounds good.  All other
 		 * Blackfin families operate properly.  Woo.
-		 * Note: While Anomaly 05000230 does not directly address this,
-		 *       the changes that went in for it also fixed this issue.
-		 *       That anomaly was fixed in 0.5+ silicon.  I like bunnies.
 		 */
 		if (anomaly_start.tv_sec) {
 			struct timeval curr;
@@ -285,7 +284,7 @@
 	}
 
 	if (status & BI) {
-		if (ANOMALY_05000230)
+		if (ANOMALY_05000363)
 			if (bfin_revid() < 5)
 				do_gettimeofday(&anomaly_start);
 		uart->port.icount.brk++;
@@ -507,8 +506,7 @@
 		uart->rx_dma_buf.tail = uart->rx_dma_buf.head;
 	}
 
-	uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES;
-	add_timer(&(uart->rx_dma_timer));
+	mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES);
 }
 
 static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
@@ -551,9 +549,7 @@
 	clear_dma_irqstat(uart->rx_dma_channel);
 	spin_unlock(&uart->port.lock);
 
-	del_timer(&(uart->rx_dma_timer));
-	uart->rx_dma_timer.expires = jiffies;
-	add_timer(&(uart->rx_dma_timer));
+	mod_timer(&(uart->rx_dma_timer), jiffies);
 
 	return IRQ_HANDLED;
 }
@@ -749,7 +745,7 @@
 	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
 	unsigned long flags;
 	unsigned int baud, quot;
-	unsigned short val, ier, lsr, lcr = 0;
+	unsigned short val, ier, lcr = 0;
 
 	switch (termios->c_cflag & CSIZE) {
 	case CS8:
@@ -806,10 +802,6 @@
 
 	UART_SET_ANOMALY_THRESHOLD(uart, USEC_PER_SEC / baud * 15);
 
-	do {
-		lsr = UART_GET_LSR(uart);
-	} while (!(lsr & TEMT));
-
 	/* Disable UART */
 	ier = UART_GET_IER(uart);
 #ifdef CONFIG_BF54x
@@ -900,6 +892,31 @@
 	return 0;
 }
 
+/*
+ * Enable the IrDA function if tty->ldisc.num is N_IRDA.
+ * In other cases, disable IrDA function.
+ */
+static void bfin_set_ldisc(struct tty_struct *tty)
+{
+	int line = tty->index;
+	unsigned short val;
+
+	if (line >= tty->driver->num)
+		return;
+
+	switch (tty->ldisc.num) {
+	case N_IRDA:
+		val = UART_GET_GCTL(&bfin_serial_ports[line]);
+		val |= (IREN | RPOLC);
+		UART_PUT_GCTL(&bfin_serial_ports[line], val);
+		break;
+	default:
+		val = UART_GET_GCTL(&bfin_serial_ports[line]);
+		val &= ~(IREN | RPOLC);
+		UART_PUT_GCTL(&bfin_serial_ports[line], val);
+	}
+}
+
 static struct uart_ops bfin_serial_pops = {
 	.tx_empty	= bfin_serial_tx_empty,
 	.set_mctrl	= bfin_serial_set_mctrl,
@@ -1172,7 +1189,7 @@
 	.dev_name		= BFIN_SERIAL_NAME,
 	.major			= BFIN_SERIAL_MAJOR,
 	.minor			= BFIN_SERIAL_MINOR,
-	.nr			= NR_PORTS,
+	.nr			= BFIN_UART_NR_PORTS,
 	.cons			= BFIN_SERIAL_CONSOLE,
 };
 
@@ -1261,6 +1278,7 @@
 
 	ret = uart_register_driver(&bfin_serial_reg);
 	if (ret == 0) {
+		bfin_serial_reg.tty_driver->set_ldisc = bfin_set_ldisc;
 		ret = platform_driver_register(&bfin_serial_driver);
 		if (ret) {
 			pr_debug("uart register failed\n");
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index cb2e405..3271379 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -1015,6 +1015,7 @@
 	.verify_port	=	sunzilog_verify_port,
 };
 
+static int uart_chip_count;
 static struct uart_sunzilog_port *sunzilog_port_table;
 static struct zilog_layout __iomem **sunzilog_chip_regs;
 
@@ -1350,16 +1351,22 @@
 
 static int __devinit zs_probe(struct of_device *op, const struct of_device_id *match)
 {
-	static int inst;
+	static int kbm_inst, uart_inst;
+	int inst;
 	struct uart_sunzilog_port *up;
 	struct zilog_layout __iomem *rp;
-	int keyboard_mouse;
+	int keyboard_mouse = 0;
 	int err;
 
-	keyboard_mouse = 0;
 	if (of_find_property(op->node, "keyboard", NULL))
 		keyboard_mouse = 1;
 
+	/* uarts must come before keyboards/mice */
+	if (keyboard_mouse)
+		inst = uart_chip_count + kbm_inst;
+	else
+		inst = uart_inst;
+
 	sunzilog_chip_regs[inst] = of_ioremap(&op->resource[0], 0,
 					      sizeof(struct zilog_layout),
 					      "zs");
@@ -1427,6 +1434,7 @@
 				   rp, sizeof(struct zilog_layout));
 			return err;
 		}
+		uart_inst++;
 	} else {
 		printk(KERN_INFO "%s: Keyboard at MMIO 0x%llx (irq = %d) "
 		       "is a %s\n",
@@ -1438,12 +1446,11 @@
 		       op->dev.bus_id,
 		       (unsigned long long) up[1].port.mapbase,
 		       op->irqs[0], sunzilog_type(&up[1].port));
+		kbm_inst++;
 	}
 
 	dev_set_drvdata(&op->dev, &up[0]);
 
-	inst++;
-
 	return 0;
 }
 
@@ -1491,28 +1498,25 @@
 static int __init sunzilog_init(void)
 {
 	struct device_node *dp;
-	int err, uart_count;
-	int num_keybms;
+	int err;
+	int num_keybms = 0;
 	int num_sunzilog = 0;
 
-	num_keybms = 0;
 	for_each_node_by_name(dp, "zs") {
 		num_sunzilog++;
 		if (of_find_property(dp, "keyboard", NULL))
 			num_keybms++;
 	}
 
-	uart_count = 0;
 	if (num_sunzilog) {
-		int uart_count;
-
 		err = sunzilog_alloc_tables(num_sunzilog);
 		if (err)
 			goto out;
 
-		uart_count = (num_sunzilog * 2) - (2 * num_keybms);
+		uart_chip_count = num_sunzilog - num_keybms;
 
-		err = sunserial_register_minors(&sunzilog_reg, uart_count);
+		err = sunserial_register_minors(&sunzilog_reg,
+						uart_chip_count * 2);
 		if (err)
 			goto out_free_tables;
 	}
diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c
index 904b1a8d..57c4ccf 100644
--- a/drivers/ssb/pci.c
+++ b/drivers/ssb/pci.c
@@ -484,6 +484,11 @@
 			goto unsupported;
 	}
 
+	if (out->boardflags_lo == 0xFFFF)
+		out->boardflags_lo = 0;  /* per specs */
+	if (out->boardflags_hi == 0xFFFF)
+		out->boardflags_hi = 0;  /* per specs */
+
 	return 0;
 unsupported:
 	ssb_printk(KERN_WARNING PFX "Unsupported SPROM revision %d "
diff --git a/fs/Kconfig b/fs/Kconfig
index 48ca1e1..2e43d46 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -411,7 +411,7 @@
 	  to be made available to the user in the /proc/fs/jfs/ directory.
 
 config FS_POSIX_ACL
-# Posix ACL utility routines (for now, only ext2/ext3/jfs/reiserfs)
+# Posix ACL utility routines (for now, only ext2/ext3/jfs/reiserfs/nfs4)
 #
 # NOTE: you can implement Posix ACLs without these helpers (XFS does).
 # 	Never use this symbol for ifdefs.
@@ -1670,75 +1670,80 @@
 	select LOCKD
 	select SUNRPC
 	select EXPORTFS
-	select NFSD_V2_ACL if NFSD_V3_ACL
 	select NFS_ACL_SUPPORT if NFSD_V2_ACL
-	select NFSD_TCP if NFSD_V4
-	select CRYPTO_MD5 if NFSD_V4
-	select CRYPTO if NFSD_V4
-	select FS_POSIX_ACL if NFSD_V4
-	select PROC_FS if NFSD_V4
-	select PROC_FS if SUNRPC_GSS
 	help
-	  If you want your Linux box to act as an NFS *server*, so that other
-	  computers on your local network which support NFS can access certain
-	  directories on your box transparently, you have two options: you can
-	  use the self-contained user space program nfsd, in which case you
-	  should say N here, or you can say Y and use the kernel based NFS
-	  server. The advantage of the kernel based solution is that it is
-	  faster.
+	  Choose Y here if you want to allow other computers to access
+	  files residing on this system using Sun's Network File System
+	  protocol.  To compile the NFS server support as a module,
+	  choose M here: the module will be called nfsd.
 
-	  In either case, you will need support software; the respective
-	  locations are given in the file <file:Documentation/Changes> in the
-	  NFS section.
+	  You may choose to use a user-space NFS server instead, in which
+	  case you can choose N here.
 
-	  If you say Y here, you will get support for version 2 of the NFS
-	  protocol (NFSv2). If you also want NFSv3, say Y to the next question
-	  as well.
+	  To export local file systems using NFS, you also need to install
+	  user space programs which can be found in the Linux nfs-utils
+	  package, available from http://linux-nfs.org/.  More detail about
+	  the Linux NFS server implementation is available via the
+	  exports(5) man page.
 
-	  Please read the NFS-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
+	  Below you can choose which versions of the NFS protocol are
+	  available to clients mounting the NFS server on this system.
+	  Support for NFS version 2 (RFC 1094) is always available when
+	  CONFIG_NFSD is selected.
 
-	  To compile the NFS server support as a module, choose M here: the
-	  module will be called nfsd.  If unsure, say N.
+	  If unsure, say N.
 
 config NFSD_V2_ACL
 	bool
 	depends on NFSD
 
 config NFSD_V3
-	bool "Provide NFSv3 server support"
+	bool "NFS server support for NFS version 3"
 	depends on NFSD
 	help
-	  If you would like to include the NFSv3 server as well as the NFSv2
-	  server, say Y here.  If unsure, say Y.
+	  This option enables support in your system's NFS server for
+	  version 3 of the NFS protocol (RFC 1813).
+
+	  If unsure, say Y.
 
 config NFSD_V3_ACL
-	bool "Provide server support for the NFSv3 ACL protocol extension"
+	bool "NFS server support for the NFSv3 ACL protocol extension"
 	depends on NFSD_V3
+	select NFSD_V2_ACL
 	help
-	  Implement the NFSv3 ACL protocol extension for manipulating POSIX
-	  Access Control Lists on exported file systems. NFS clients should
-	  be compiled with the NFSv3 ACL protocol extension; see the
-	  CONFIG_NFS_V3_ACL option.  If unsure, say N.
+	  Solaris NFS servers support an auxiliary NFSv3 ACL protocol that
+	  never became an official part of the NFS version 3 protocol.
+	  This protocol extension allows applications on NFS clients to
+	  manipulate POSIX Access Control Lists on files residing on NFS
+	  servers.  NFS servers enforce POSIX ACLs on local files whether
+	  this protocol is available or not.
 
-config NFSD_V4
-	bool "Provide NFSv4 server support (EXPERIMENTAL)"
-	depends on NFSD && NFSD_V3 && EXPERIMENTAL
-	select RPCSEC_GSS_KRB5
-	help
-	  If you would like to include the NFSv4 server as well as the NFSv2
-	  and NFSv3 servers, say Y here.  This feature is experimental, and
-	  should only be used if you are interested in helping to test NFSv4.
+	  This option enables support in your system's NFS server for the
+	  NFSv3 ACL protocol extension allowing NFS clients to manipulate
+	  POSIX ACLs on files exported by your system's NFS server.  NFS
+	  clients which support the Solaris NFSv3 ACL protocol can then
+	  access and modify ACLs on your NFS server.
+
+	  To store ACLs on your NFS server, you also need to enable ACL-
+	  related CONFIG options for your local file systems of choice.
+
 	  If unsure, say N.
 
-config NFSD_TCP
-	bool "Provide NFS server over TCP support"
-	depends on NFSD
-	default y
+config NFSD_V4
+	bool "NFS server support for NFS version 4 (EXPERIMENTAL)"
+	depends on NFSD && PROC_FS && EXPERIMENTAL
+	select NFSD_V3
+	select FS_POSIX_ACL
+	select RPCSEC_GSS_KRB5
 	help
-	  If you want your NFS server to support TCP connections, say Y here.
-	  TCP connections usually perform better than the default UDP when
-	  the network is lossy or congested.  If unsure, say Y.
+	  This option enables support in your system's NFS server for
+	  version 4 of the NFS protocol (RFC 3530).
+
+	  To export files using NFSv4, you need to install additional user
+	  space programs which can be found in the Linux nfs-utils package,
+	  available from http://linux-nfs.org/.
+
+	  If unsure, say N.
 
 config ROOT_NFS
 	bool "Root file system on NFS"
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index f23750d..a17664c 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -19,12 +19,11 @@
 
 
 #define NLMDBG_FACILITY		NLMDBG_HOSTCACHE
-#define NLM_HOST_MAX		64
 #define NLM_HOST_NRHASH		32
 #define NLM_ADDRHASH(addr)	(ntohl(addr) & (NLM_HOST_NRHASH-1))
 #define NLM_HOST_REBIND		(60 * HZ)
-#define NLM_HOST_EXPIRE		((nrhosts > NLM_HOST_MAX)? 300 * HZ : 120 * HZ)
-#define NLM_HOST_COLLECT	((nrhosts > NLM_HOST_MAX)? 120 * HZ :  60 * HZ)
+#define NLM_HOST_EXPIRE		(300 * HZ)
+#define NLM_HOST_COLLECT	(120 * HZ)
 
 static struct hlist_head	nlm_hosts[NLM_HOST_NRHASH];
 static unsigned long		next_gc;
@@ -143,9 +142,7 @@
 	INIT_LIST_HEAD(&host->h_granted);
 	INIT_LIST_HEAD(&host->h_reclaim);
 
-	if (++nrhosts > NLM_HOST_MAX)
-		next_gc = 0;
-
+	nrhosts++;
 out:
 	mutex_unlock(&nlm_host_mutex);
 	return host;
@@ -462,7 +459,7 @@
  * Manage NSM handles
  */
 static LIST_HEAD(nsm_handles);
-static DEFINE_MUTEX(nsm_mutex);
+static DEFINE_SPINLOCK(nsm_lock);
 
 static struct nsm_handle *
 __nsm_find(const struct sockaddr_in *sin,
@@ -470,7 +467,7 @@
 		int create)
 {
 	struct nsm_handle *nsm = NULL;
-	struct list_head *pos;
+	struct nsm_handle *pos;
 
 	if (!sin)
 		return NULL;
@@ -484,38 +481,43 @@
 		return NULL;
 	}
 
-	mutex_lock(&nsm_mutex);
-	list_for_each(pos, &nsm_handles) {
-		nsm = list_entry(pos, struct nsm_handle, sm_link);
+retry:
+	spin_lock(&nsm_lock);
+	list_for_each_entry(pos, &nsm_handles, sm_link) {
 
 		if (hostname && nsm_use_hostnames) {
-			if (strlen(nsm->sm_name) != hostname_len
-			 || memcmp(nsm->sm_name, hostname, hostname_len))
+			if (strlen(pos->sm_name) != hostname_len
+			 || memcmp(pos->sm_name, hostname, hostname_len))
 				continue;
-		} else if (!nlm_cmp_addr(&nsm->sm_addr, sin))
+		} else if (!nlm_cmp_addr(&pos->sm_addr, sin))
 			continue;
-		atomic_inc(&nsm->sm_count);
-		goto out;
+		atomic_inc(&pos->sm_count);
+		kfree(nsm);
+		nsm = pos;
+		goto found;
 	}
+	if (nsm) {
+		list_add(&nsm->sm_link, &nsm_handles);
+		goto found;
+	}
+	spin_unlock(&nsm_lock);
 
-	if (!create) {
-		nsm = NULL;
-		goto out;
-	}
+	if (!create)
+		return NULL;
 
 	nsm = kzalloc(sizeof(*nsm) + hostname_len + 1, GFP_KERNEL);
-	if (nsm != NULL) {
-		nsm->sm_addr = *sin;
-		nsm->sm_name = (char *) (nsm + 1);
-		memcpy(nsm->sm_name, hostname, hostname_len);
-		nsm->sm_name[hostname_len] = '\0';
-		atomic_set(&nsm->sm_count, 1);
+	if (nsm == NULL)
+		return NULL;
 
-		list_add(&nsm->sm_link, &nsm_handles);
-	}
+	nsm->sm_addr = *sin;
+	nsm->sm_name = (char *) (nsm + 1);
+	memcpy(nsm->sm_name, hostname, hostname_len);
+	nsm->sm_name[hostname_len] = '\0';
+	atomic_set(&nsm->sm_count, 1);
+	goto retry;
 
-out:
-	mutex_unlock(&nsm_mutex);
+found:
+	spin_unlock(&nsm_lock);
 	return nsm;
 }
 
@@ -534,12 +536,9 @@
 {
 	if (!nsm)
 		return;
-	if (atomic_dec_and_test(&nsm->sm_count)) {
-		mutex_lock(&nsm_mutex);
-		if (atomic_read(&nsm->sm_count) == 0) {
-			list_del(&nsm->sm_link);
-			kfree(nsm);
-		}
-		mutex_unlock(&nsm_mutex);
+	if (atomic_dec_and_lock(&nsm->sm_count, &nsm_lock)) {
+		list_del(&nsm->sm_link);
+		spin_unlock(&nsm_lock);
+		kfree(nsm);
 	}
 }
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 38c2f0b..2169af4 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -25,6 +25,7 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/mutex.h>
+#include <linux/kthread.h>
 #include <linux/freezer.h>
 
 #include <linux/sunrpc/types.h>
@@ -48,14 +49,11 @@
 
 static DEFINE_MUTEX(nlmsvc_mutex);
 static unsigned int		nlmsvc_users;
-static pid_t			nlmsvc_pid;
+static struct task_struct	*nlmsvc_task;
 static struct svc_serv		*nlmsvc_serv;
 int				nlmsvc_grace_period;
 unsigned long			nlmsvc_timeout;
 
-static DECLARE_COMPLETION(lockd_start_done);
-static DECLARE_WAIT_QUEUE_HEAD(lockd_exit);
-
 /*
  * These can be set at insmod time (useful for NFS as root filesystem),
  * and also changed through the sysctl interface.  -- Jamie Lokier, Aug 2003
@@ -113,35 +111,30 @@
 /*
  * This is the lockd kernel thread
  */
-static void
-lockd(struct svc_rqst *rqstp)
+static int
+lockd(void *vrqstp)
 {
-	int		err = 0;
+	int		err = 0, preverr = 0;
+	struct svc_rqst *rqstp = vrqstp;
 	unsigned long grace_period_expire;
 
-	/* Lock module and set up kernel thread */
-	/* lockd_up is waiting for us to startup, so will
-	 * be holding a reference to this module, so it
-	 * is safe to just claim another reference
-	 */
-	__module_get(THIS_MODULE);
-	lock_kernel();
-
-	/*
-	 * Let our maker know we're running.
-	 */
-	nlmsvc_pid = current->pid;
-	nlmsvc_serv = rqstp->rq_server;
-	complete(&lockd_start_done);
-
-	daemonize("lockd");
+	/* try_to_freeze() is called from svc_recv() */
 	set_freezable();
 
-	/* Process request with signals blocked, but allow SIGKILL.  */
+	/* Allow SIGKILL to tell lockd to drop all of its locks */
 	allow_signal(SIGKILL);
 
 	dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n");
 
+	/*
+	 * FIXME: it would be nice if lockd didn't spend its entire life
+	 * running under the BKL. At the very least, it would be good to
+	 * have someone clarify what it's intended to protect here. I've
+	 * seen some handwavy posts about posix locking needing to be
+	 * done under the BKL, but it's far from clear.
+	 */
+	lock_kernel();
+
 	if (!nlm_timeout)
 		nlm_timeout = LOCKD_DFLT_TIMEO;
 	nlmsvc_timeout = nlm_timeout * HZ;
@@ -150,10 +143,9 @@
 
 	/*
 	 * The main request loop. We don't terminate until the last
-	 * NFS mount or NFS daemon has gone away, and we've been sent a
-	 * signal, or else another process has taken over our job.
+	 * NFS mount or NFS daemon has gone away.
 	 */
-	while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid) {
+	while (!kthread_should_stop()) {
 		long timeout = MAX_SCHEDULE_TIMEOUT;
 		RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
 
@@ -163,6 +155,7 @@
 				nlmsvc_invalidate_all();
 				grace_period_expire = set_grace_period();
 			}
+			continue;
 		}
 
 		/*
@@ -181,14 +174,20 @@
 		 * recvfrom routine.
 		 */
 		err = svc_recv(rqstp, timeout);
-		if (err == -EAGAIN || err == -EINTR)
+		if (err == -EAGAIN || err == -EINTR) {
+			preverr = err;
 			continue;
-		if (err < 0) {
-			printk(KERN_WARNING
-			       "lockd: terminating on error %d\n",
-			       -err);
-			break;
 		}
+		if (err < 0) {
+			if (err != preverr) {
+				printk(KERN_WARNING "%s: unexpected error "
+					"from svc_recv (%d)\n", __func__, err);
+				preverr = err;
+			}
+			schedule_timeout_interruptible(HZ);
+			continue;
+		}
+		preverr = err;
 
 		dprintk("lockd: request from %s\n",
 				svc_print_addr(rqstp, buf, sizeof(buf)));
@@ -197,28 +196,19 @@
 	}
 
 	flush_signals(current);
+	if (nlmsvc_ops)
+		nlmsvc_invalidate_all();
+	nlm_shutdown_hosts();
 
-	/*
-	 * Check whether there's a new lockd process before
-	 * shutting down the hosts and clearing the slot.
-	 */
-	if (!nlmsvc_pid || current->pid == nlmsvc_pid) {
-		if (nlmsvc_ops)
-			nlmsvc_invalidate_all();
-		nlm_shutdown_hosts();
-		nlmsvc_pid = 0;
-		nlmsvc_serv = NULL;
-	} else
-		printk(KERN_DEBUG
-			"lockd: new process, skipping host shutdown\n");
-	wake_up(&lockd_exit);
+	unlock_kernel();
+
+	nlmsvc_task = NULL;
+	nlmsvc_serv = NULL;
 
 	/* Exit the RPC thread */
 	svc_exit_thread(rqstp);
 
-	/* Release module */
-	unlock_kernel();
-	module_put_and_exit(0);
+	return 0;
 }
 
 /*
@@ -263,14 +253,15 @@
 int
 lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */
 {
-	struct svc_serv *	serv;
-	int			error = 0;
+	struct svc_serv *serv;
+	struct svc_rqst *rqstp;
+	int		error = 0;
 
 	mutex_lock(&nlmsvc_mutex);
 	/*
 	 * Check whether we're already up and running.
 	 */
-	if (nlmsvc_pid) {
+	if (nlmsvc_serv) {
 		if (proto)
 			error = make_socks(nlmsvc_serv, proto);
 		goto out;
@@ -297,13 +288,28 @@
 	/*
 	 * Create the kernel thread and wait for it to start.
 	 */
-	error = svc_create_thread(lockd, serv);
-	if (error) {
+	rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]);
+	if (IS_ERR(rqstp)) {
+		error = PTR_ERR(rqstp);
 		printk(KERN_WARNING
-			"lockd_up: create thread failed, error=%d\n", error);
+			"lockd_up: svc_rqst allocation failed, error=%d\n",
+			error);
 		goto destroy_and_out;
 	}
-	wait_for_completion(&lockd_start_done);
+
+	svc_sock_update_bufs(serv);
+	nlmsvc_serv = rqstp->rq_server;
+
+	nlmsvc_task = kthread_run(lockd, rqstp, serv->sv_name);
+	if (IS_ERR(nlmsvc_task)) {
+		error = PTR_ERR(nlmsvc_task);
+		nlmsvc_task = NULL;
+		nlmsvc_serv = NULL;
+		printk(KERN_WARNING
+			"lockd_up: kthread_run failed, error=%d\n", error);
+		svc_exit_thread(rqstp);
+		goto destroy_and_out;
+	}
 
 	/*
 	 * Note: svc_serv structures have an initial use count of 1,
@@ -325,37 +331,21 @@
 void
 lockd_down(void)
 {
-	static int warned;
-
 	mutex_lock(&nlmsvc_mutex);
 	if (nlmsvc_users) {
 		if (--nlmsvc_users)
 			goto out;
-	} else
-		printk(KERN_WARNING "lockd_down: no users! pid=%d\n", nlmsvc_pid);
-
-	if (!nlmsvc_pid) {
-		if (warned++ == 0)
-			printk(KERN_WARNING "lockd_down: no lockd running.\n"); 
-		goto out;
+	} else {
+		printk(KERN_ERR "lockd_down: no users! task=%p\n",
+			nlmsvc_task);
+		BUG();
 	}
-	warned = 0;
 
-	kill_proc(nlmsvc_pid, SIGKILL, 1);
-	/*
-	 * Wait for the lockd process to exit, but since we're holding
-	 * the lockd semaphore, we can't wait around forever ...
-	 */
-	clear_thread_flag(TIF_SIGPENDING);
-	interruptible_sleep_on_timeout(&lockd_exit, HZ);
-	if (nlmsvc_pid) {
-		printk(KERN_WARNING 
-			"lockd_down: lockd failed to exit, clearing pid\n");
-		nlmsvc_pid = 0;
+	if (!nlmsvc_task) {
+		printk(KERN_ERR "lockd_down: no lockd running.\n");
+		BUG();
 	}
-	spin_lock_irq(&current->sighand->siglock);
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	kthread_stop(nlmsvc_task);
 out:
 	mutex_unlock(&nlmsvc_mutex);
 }
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index fe9bdb4..1f122c1 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -29,6 +29,7 @@
 #include <linux/sunrpc/svc.h>
 #include <linux/lockd/nlm.h>
 #include <linux/lockd/lockd.h>
+#include <linux/kthread.h>
 
 #define NLMDBG_FACILITY		NLMDBG_SVCLOCK
 
@@ -226,8 +227,7 @@
 }
 
 /*
- * Delete a block. If the lock was cancelled or the grant callback
- * failed, unlock is set to 1.
+ * Delete a block.
  * It is the caller's responsibility to check whether the file
  * can be closed hereafter.
  */
@@ -887,7 +887,7 @@
 	unsigned long	timeout = MAX_SCHEDULE_TIMEOUT;
 	struct nlm_block *block;
 
-	while (!list_empty(&nlm_blocked)) {
+	while (!list_empty(&nlm_blocked) && !kthread_should_stop()) {
 		block = list_entry(nlm_blocked.next, struct nlm_block, b_list);
 
 		if (block->b_when == NLM_NEVER)
diff --git a/fs/lockd/svcshare.c b/fs/lockd/svcshare.c
index 068886d..b0ae070 100644
--- a/fs/lockd/svcshare.c
+++ b/fs/lockd/svcshare.c
@@ -71,7 +71,8 @@
 	struct nlm_share	*share, **shpp;
 	struct xdr_netobj	*oh = &argp->lock.oh;
 
-	for (shpp = &file->f_shares; (share = *shpp) != 0; shpp = &share->s_next) {
+	for (shpp = &file->f_shares; (share = *shpp) != NULL;
+					shpp = &share->s_next) {
 		if (share->s_host == host && nlm_cmp_owner(share, oh)) {
 			*shpp = share->s_next;
 			kfree(share);
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index 66648dd..5606ae3 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -15,6 +15,7 @@
 #include <linux/nfs_fs.h>
 #include <linux/mutex.h>
 #include <linux/freezer.h>
+#include <linux/kthread.h>
 
 #include <net/inet_sock.h>
 
@@ -27,9 +28,7 @@
 struct nfs_callback_data {
 	unsigned int users;
 	struct svc_serv *serv;
-	pid_t pid;
-	struct completion started;
-	struct completion stopped;
+	struct task_struct *task;
 };
 
 static struct nfs_callback_data nfs_callback_info;
@@ -57,48 +56,44 @@
 /*
  * This is the callback kernel thread.
  */
-static void nfs_callback_svc(struct svc_rqst *rqstp)
+static int
+nfs_callback_svc(void *vrqstp)
 {
-	int err;
+	int err, preverr = 0;
+	struct svc_rqst *rqstp = vrqstp;
 
-	__module_get(THIS_MODULE);
-	lock_kernel();
-
-	nfs_callback_info.pid = current->pid;
-	daemonize("nfsv4-svc");
-	/* Process request with signals blocked, but allow SIGKILL.  */
-	allow_signal(SIGKILL);
 	set_freezable();
 
-	complete(&nfs_callback_info.started);
-
-	for(;;) {
-		if (signalled()) {
-			if (nfs_callback_info.users == 0)
-				break;
-			flush_signals(current);
-		}
+	/*
+	 * FIXME: do we really need to run this under the BKL? If so, please
+	 * add a comment about what it's intended to protect.
+	 */
+	lock_kernel();
+	while (!kthread_should_stop()) {
 		/*
 		 * Listen for a request on the socket
 		 */
 		err = svc_recv(rqstp, MAX_SCHEDULE_TIMEOUT);
-		if (err == -EAGAIN || err == -EINTR)
+		if (err == -EAGAIN || err == -EINTR) {
+			preverr = err;
 			continue;
-		if (err < 0) {
-			printk(KERN_WARNING
-					"%s: terminating on error %d\n",
-					__FUNCTION__, -err);
-			break;
 		}
+		if (err < 0) {
+			if (err != preverr) {
+				printk(KERN_WARNING "%s: unexpected error "
+					"from svc_recv (%d)\n", __func__, err);
+				preverr = err;
+			}
+			schedule_timeout_uninterruptible(HZ);
+			continue;
+		}
+		preverr = err;
 		svc_process(rqstp);
 	}
-
-	flush_signals(current);
-	svc_exit_thread(rqstp);
-	nfs_callback_info.pid = 0;
-	complete(&nfs_callback_info.stopped);
 	unlock_kernel();
-	module_put_and_exit(0);
+	nfs_callback_info.task = NULL;
+	svc_exit_thread(rqstp);
+	return 0;
 }
 
 /*
@@ -107,14 +102,13 @@
 int nfs_callback_up(void)
 {
 	struct svc_serv *serv = NULL;
+	struct svc_rqst *rqstp;
 	int ret = 0;
 
 	lock_kernel();
 	mutex_lock(&nfs_callback_mutex);
-	if (nfs_callback_info.users++ || nfs_callback_info.pid != 0)
+	if (nfs_callback_info.users++ || nfs_callback_info.task != NULL)
 		goto out;
-	init_completion(&nfs_callback_info.started);
-	init_completion(&nfs_callback_info.stopped);
 	serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL);
 	ret = -ENOMEM;
 	if (!serv)
@@ -127,15 +121,28 @@
 	nfs_callback_tcpport = ret;
 	dprintk("Callback port = 0x%x\n", nfs_callback_tcpport);
 
-	ret = svc_create_thread(nfs_callback_svc, serv);
-	if (ret < 0)
+	rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]);
+	if (IS_ERR(rqstp)) {
+		ret = PTR_ERR(rqstp);
 		goto out_err;
+	}
+
+	svc_sock_update_bufs(serv);
 	nfs_callback_info.serv = serv;
-	wait_for_completion(&nfs_callback_info.started);
+
+	nfs_callback_info.task = kthread_run(nfs_callback_svc, rqstp,
+					     "nfsv4-svc");
+	if (IS_ERR(nfs_callback_info.task)) {
+		ret = PTR_ERR(nfs_callback_info.task);
+		nfs_callback_info.serv = NULL;
+		nfs_callback_info.task = NULL;
+		svc_exit_thread(rqstp);
+		goto out_err;
+	}
 out:
 	/*
 	 * svc_create creates the svc_serv with sv_nrthreads == 1, and then
-	 * svc_create_thread increments that. So we need to call svc_destroy
+	 * svc_prepare_thread increments that. So we need to call svc_destroy
 	 * on both success and failure so that the refcount is 1 when the
 	 * thread exits.
 	 */
@@ -152,19 +159,15 @@
 }
 
 /*
- * Kill the server process if it is not already up.
+ * Kill the server process if it is not already down.
  */
 void nfs_callback_down(void)
 {
 	lock_kernel();
 	mutex_lock(&nfs_callback_mutex);
 	nfs_callback_info.users--;
-	do {
-		if (nfs_callback_info.users != 0 || nfs_callback_info.pid == 0)
-			break;
-		if (kill_proc(nfs_callback_info.pid, SIGKILL, 1) < 0)
-			break;
-	} while (wait_for_completion_timeout(&nfs_callback_info.stopped, 5*HZ) == 0);
+	if (nfs_callback_info.users == 0 && nfs_callback_info.task != NULL)
+		kthread_stop(nfs_callback_info.task);
 	mutex_unlock(&nfs_callback_mutex);
 	unlock_kernel();
 }
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c
index 83e865a..412738d 100644
--- a/fs/nfs/symlink.c
+++ b/fs/nfs/symlink.c
@@ -10,7 +10,6 @@
  *  nfs symlink handling code
  */
 
-#define NFS_NEED_XDR_TYPES
 #include <linux/time.h>
 #include <linux/errno.h>
 #include <linux/sunrpc/clnt.h>
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c
index d13403e..294992e 100644
--- a/fs/nfsd/auth.c
+++ b/fs/nfsd/auth.c
@@ -10,6 +10,7 @@
 #include <linux/sunrpc/svcauth.h>
 #include <linux/nfsd/nfsd.h>
 #include <linux/nfsd/export.h>
+#include "auth.h"
 
 int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp)
 {
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 8a6f7c9..33bfcf0 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -35,6 +35,7 @@
 #include <linux/lockd/bind.h>
 #include <linux/sunrpc/msg_prot.h>
 #include <linux/sunrpc/gss_api.h>
+#include <net/ipv6.h>
 
 #define NFSDDBG_FACILITY	NFSDDBG_EXPORT
 
@@ -1548,6 +1549,7 @@
 {
 	struct auth_domain	*dom;
 	int			i, err;
+	struct in6_addr addr6;
 
 	/* First, consistency check. */
 	err = -EINVAL;
@@ -1566,9 +1568,10 @@
 		goto out_unlock;
 
 	/* Insert client into hashtable. */
-	for (i = 0; i < ncp->cl_naddr; i++)
-		auth_unix_add_addr(ncp->cl_addrlist[i], dom);
-
+	for (i = 0; i < ncp->cl_naddr; i++) {
+		ipv6_addr_set_v4mapped(ncp->cl_addrlist[i].s_addr, &addr6);
+		auth_unix_add_addr(&addr6, dom);
+	}
 	auth_unix_forget_old(dom);
 	auth_domain_put(dom);
 
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index aae2b29..562abf3 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -344,6 +344,21 @@
 	&nfs_cb_version4,
 };
 
+static struct rpc_program cb_program;
+
+static struct rpc_stat cb_stats = {
+		.program	= &cb_program
+};
+
+#define NFS4_CALLBACK 0x40000000
+static struct rpc_program cb_program = {
+		.name 		= "nfs4_cb",
+		.number		= NFS4_CALLBACK,
+		.nrvers		= ARRAY_SIZE(nfs_cb_version),
+		.version	= nfs_cb_version,
+		.stats		= &cb_stats,
+};
+
 /* Reference counting, callback cleanup, etc., all look racy as heck.
  * And why is cb_set an atomic? */
 
@@ -358,13 +373,12 @@
 		.to_maxval	= (NFSD_LEASE_TIME/2) * HZ,
 		.to_exponential	= 1,
 	};
-	struct rpc_program *	program = &cb->cb_program;
 	struct rpc_create_args args = {
 		.protocol	= IPPROTO_TCP,
 		.address	= (struct sockaddr *)&addr,
 		.addrsize	= sizeof(addr),
 		.timeout	= &timeparms,
-		.program	= program,
+		.program	= &cb_program,
 		.version	= nfs_cb_version[1]->number,
 		.authflavor	= RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */
 		.flags		= (RPC_CLNT_CREATE_NOPING),
@@ -382,16 +396,8 @@
 	addr.sin_port = htons(cb->cb_port);
 	addr.sin_addr.s_addr = htonl(cb->cb_addr);
 
-	/* Initialize rpc_program */
-	program->name = "nfs4_cb";
-	program->number = cb->cb_prog;
-	program->nrvers = ARRAY_SIZE(nfs_cb_version);
-	program->version = nfs_cb_version;
-	program->stats = &cb->cb_stat;
-
 	/* Initialize rpc_stat */
-	memset(program->stats, 0, sizeof(cb->cb_stat));
-	program->stats->program = program;
+	memset(args.program->stats, 0, sizeof(struct rpc_stat));
 
 	/* Create RPC client */
 	client = rpc_create(&args);
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
index 996bd88..5b39842 100644
--- a/fs/nfsd/nfs4idmap.c
+++ b/fs/nfsd/nfs4idmap.c
@@ -202,7 +202,7 @@
 	.alloc		= ent_alloc,
 };
 
-int
+static int
 idtoname_parse(struct cache_detail *cd, char *buf, int buflen)
 {
 	struct ent ent, *res;
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 81a75f3..55dfdd7 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1639,6 +1639,7 @@
 	locks_init_lock(&fl);
 	fl.fl_lmops = &nfsd_lease_mng_ops;
 	fl.fl_flags = FL_LEASE;
+	fl.fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
 	fl.fl_end = OFFSET_MAX;
 	fl.fl_owner =  (fl_owner_t)dp;
 	fl.fl_file = stp->st_vfs_file;
@@ -1647,8 +1648,7 @@
 	/* vfs_setlease checks to see if delegation should be handed out.
 	 * the lock_manager callbacks fl_mylease and fl_change are used
 	 */
-	if ((status = vfs_setlease(stp->st_vfs_file,
-		flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK, &flp))) {
+	if ((status = vfs_setlease(stp->st_vfs_file, fl.fl_type, &flp))) {
 		dprintk("NFSD: setlease failed [%d], no delegation\n", status);
 		unhash_delegation(dp);
 		flag = NFS4_OPEN_DELEGATE_NONE;
@@ -1763,10 +1763,6 @@
 	return status;
 }
 
-static struct workqueue_struct *laundry_wq;
-static void laundromat_main(struct work_struct *);
-static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main);
-
 __be32
 nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	    clientid_t *clid)
@@ -1874,7 +1870,11 @@
 	return clientid_val;
 }
 
-void
+static struct workqueue_struct *laundry_wq;
+static void laundromat_main(struct work_struct *);
+static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main);
+
+static void
 laundromat_main(struct work_struct *not_used)
 {
 	time_t t;
@@ -1975,6 +1975,26 @@
 		&& mandatory_lock(inode);
 }
 
+static int check_stateid_generation(stateid_t *in, stateid_t *ref)
+{
+	/* If the client sends us a stateid from the future, it's buggy: */
+	if (in->si_generation > ref->si_generation)
+		return nfserr_bad_stateid;
+	/*
+	 * The following, however, can happen.  For example, if the
+	 * client sends an open and some IO at the same time, the open
+	 * may bump si_generation while the IO is still in flight.
+	 * Thanks to hard links and renames, the client never knows what
+	 * file an open will affect.  So it could avoid that situation
+	 * only by serializing all opens and IO from the same open
+	 * owner.  To recover from the old_stateid error, the client
+	 * will just have to retry the IO:
+	 */
+	if (in->si_generation < ref->si_generation)
+		return nfserr_old_stateid;
+	return nfs_ok;
+}
+
 /*
 * Checks for stateid operations
 */
@@ -2023,12 +2043,8 @@
 			goto out;
 		stidp = &stp->st_stateid;
 	}
-	if (stateid->si_generation > stidp->si_generation)
-		goto out;
-
-	/* OLD STATEID */
-	status = nfserr_old_stateid;
-	if (stateid->si_generation < stidp->si_generation)
+	status = check_stateid_generation(stateid, stidp);
+	if (status)
 		goto out;
 	if (stp) {
 		if ((status = nfs4_check_openmode(stp,flags)))
@@ -2036,7 +2052,7 @@
 		renew_client(stp->st_stateowner->so_client);
 		if (filpp)
 			*filpp = stp->st_vfs_file;
-	} else if (dp) {
+	} else {
 		if ((status = nfs4_check_delegmode(dp, flags)))
 			goto out;
 		renew_client(dp->dl_client);
@@ -2065,6 +2081,7 @@
 {
 	struct nfs4_stateid *stp;
 	struct nfs4_stateowner *sop;
+	__be32 status;
 
 	dprintk("NFSD: preprocess_seqid_op: seqid=%d " 
 			"stateid = (%08x/%08x/%08x/%08x)\n", seqid,
@@ -2127,7 +2144,7 @@
                }
 	}
 
-	if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) {
+	if (nfs4_check_fh(current_fh, stp)) {
 		dprintk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
 		return nfserr_bad_stateid;
 	}
@@ -2150,15 +2167,9 @@
 				" confirmed yet!\n");
 		return nfserr_bad_stateid;
 	}
-	if (stateid->si_generation > stp->st_stateid.si_generation) {
-		dprintk("NFSD: preprocess_seqid_op: future stateid?!\n");
-		return nfserr_bad_stateid;
-	}
-
-	if (stateid->si_generation < stp->st_stateid.si_generation) {
-		dprintk("NFSD: preprocess_seqid_op: old stateid!\n");
-		return nfserr_old_stateid;
-	}
+	status = check_stateid_generation(stateid, &stp->st_stateid);
+	if (status)
+		return status;
 	renew_client(sop->so_client);
 	return nfs_ok;
 
@@ -2194,7 +2205,7 @@
 
 	if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh,
 					oc->oc_seqid, &oc->oc_req_stateid,
-					CHECK_FH | CONFIRM | OPEN_STATE,
+					CONFIRM | OPEN_STATE,
 					&oc->oc_stateowner, &stp, NULL)))
 		goto out; 
 
@@ -2265,7 +2276,7 @@
 	if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh,
 					od->od_seqid,
 					&od->od_stateid, 
-					CHECK_FH | OPEN_STATE, 
+					OPEN_STATE,
 					&od->od_stateowner, &stp, NULL)))
 		goto out; 
 
@@ -2318,7 +2329,7 @@
 	if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh,
 					close->cl_seqid,
 					&close->cl_stateid, 
-					CHECK_FH | OPEN_STATE | CLOSE_STATE,
+					OPEN_STATE | CLOSE_STATE,
 					&close->cl_stateowner, &stp, NULL)))
 		goto out; 
 	status = nfs_ok;
@@ -2623,7 +2634,7 @@
 		status = nfs4_preprocess_seqid_op(&cstate->current_fh,
 				        lock->lk_new_open_seqid,
 		                        &lock->lk_new_open_stateid,
-		                        CHECK_FH | OPEN_STATE,
+					OPEN_STATE,
 		                        &lock->lk_replay_owner, &open_stp,
 					lock);
 		if (status)
@@ -2650,7 +2661,7 @@
 		status = nfs4_preprocess_seqid_op(&cstate->current_fh,
 				       lock->lk_old_lock_seqid, 
 				       &lock->lk_old_lock_stateid, 
-				       CHECK_FH | LOCK_STATE, 
+				       LOCK_STATE,
 				       &lock->lk_replay_owner, &lock_stp, lock);
 		if (status)
 			goto out;
@@ -2847,7 +2858,7 @@
 	if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh,
 					locku->lu_seqid, 
 					&locku->lu_stateid, 
-					CHECK_FH | LOCK_STATE, 
+					LOCK_STATE,
 					&locku->lu_stateowner, &stp, NULL)))
 		goto out;
 
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 0e6a179..1ba7ad9 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1867,6 +1867,15 @@
 	goto out;
 }
 
+static inline int attributes_need_mount(u32 *bmval)
+{
+	if (bmval[0] & ~(FATTR4_WORD0_RDATTR_ERROR | FATTR4_WORD0_LEASE_TIME))
+		return 1;
+	if (bmval[1] & ~FATTR4_WORD1_MOUNTED_ON_FILEID)
+		return 1;
+	return 0;
+}
+
 static __be32
 nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
 		const char *name, int namlen, __be32 *p, int *buflen)
@@ -1888,9 +1897,7 @@
 	 * we will not follow the cross mount and will fill the attribtutes
 	 * directly from the mountpoint dentry.
 	 */
-	if (d_mountpoint(dentry) &&
-	    (cd->rd_bmval[0] & ~FATTR4_WORD0_RDATTR_ERROR) == 0 &&
-	    (cd->rd_bmval[1] & ~FATTR4_WORD1_MOUNTED_ON_FILEID) == 0)
+	if (d_mountpoint(dentry) && !attributes_need_mount(cd->rd_bmval))
 		ignore_crossmnt = 1;
 	else if (d_mountpoint(dentry)) {
 		int err;
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 8516137..613bcb8 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -37,6 +37,7 @@
 #include <linux/nfsd/syscall.h>
 
 #include <asm/uaccess.h>
+#include <net/ipv6.h>
 
 /*
  *	We have a single directory with 9 nodes in it.
@@ -149,7 +150,6 @@
 	.release	= simple_transaction_release,
 };
 
-extern struct seq_operations nfs_exports_op;
 static int exports_open(struct inode *inode, struct file *file)
 {
 	return seq_open(file, &nfs_exports_op);
@@ -222,6 +222,7 @@
 	struct auth_domain *clp;
 	int err = 0;
 	struct knfsd_fh *res;
+	struct in6_addr in6;
 
 	if (size < sizeof(*data))
 		return -EINVAL;
@@ -236,7 +237,11 @@
 	res = (struct knfsd_fh*)buf;
 
 	exp_readlock();
-	if (!(clp = auth_unix_lookup(sin->sin_addr)))
+
+	ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6);
+
+	clp = auth_unix_lookup(&in6);
+	if (!clp)
 		err = -EPERM;
 	else {
 		err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen);
@@ -257,6 +262,7 @@
 	int err = 0;
 	struct knfsd_fh fh;
 	char *res;
+	struct in6_addr in6;
 
 	if (size < sizeof(*data))
 		return -EINVAL;
@@ -271,7 +277,11 @@
 	res = buf;
 	sin = (struct sockaddr_in *)&data->gd_addr;
 	exp_readlock();
-	if (!(clp = auth_unix_lookup(sin->sin_addr)))
+
+	ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6);
+
+	clp = auth_unix_lookup(&in6);
+	if (!clp)
 		err = -EPERM;
 	else {
 		err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE);
@@ -347,8 +357,6 @@
 	return mesg - buf;	
 }
 
-extern int nfsd_nrthreads(void);
-
 static ssize_t write_threads(struct file *file, char *buf, size_t size)
 {
 	/* if size > 0, look for a number of threads and call nfsd_svc
@@ -371,10 +379,6 @@
 	return strlen(buf);
 }
 
-extern int nfsd_nrpools(void);
-extern int nfsd_get_nrthreads(int n, int *);
-extern int nfsd_set_nrthreads(int n, int *);
-
 static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
 {
 	/* if size > 0, look for an array of number of threads per node
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 3e6b3f4..100ae56 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -113,6 +113,124 @@
 }
 
 /*
+ * Use the given filehandle to look up the corresponding export and
+ * dentry.  On success, the results are used to set fh_export and
+ * fh_dentry.
+ */
+static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
+{
+	struct knfsd_fh	*fh = &fhp->fh_handle;
+	struct fid *fid = NULL, sfid;
+	struct svc_export *exp;
+	struct dentry *dentry;
+	int fileid_type;
+	int data_left = fh->fh_size/4;
+	__be32 error;
+
+	error = nfserr_stale;
+	if (rqstp->rq_vers > 2)
+		error = nfserr_badhandle;
+	if (rqstp->rq_vers == 4 && fh->fh_size == 0)
+		return nfserr_nofilehandle;
+
+	if (fh->fh_version == 1) {
+		int len;
+
+		if (--data_left < 0)
+			return error;
+		if (fh->fh_auth_type != 0)
+			return error;
+		len = key_len(fh->fh_fsid_type) / 4;
+		if (len == 0)
+			return error;
+		if  (fh->fh_fsid_type == FSID_MAJOR_MINOR) {
+			/* deprecated, convert to type 3 */
+			len = key_len(FSID_ENCODE_DEV)/4;
+			fh->fh_fsid_type = FSID_ENCODE_DEV;
+			fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl(fh->fh_fsid[0]), ntohl(fh->fh_fsid[1])));
+			fh->fh_fsid[1] = fh->fh_fsid[2];
+		}
+		data_left -= len;
+		if (data_left < 0)
+			return error;
+		exp = rqst_exp_find(rqstp, fh->fh_fsid_type, fh->fh_auth);
+		fid = (struct fid *)(fh->fh_auth + len);
+	} else {
+		__u32 tfh[2];
+		dev_t xdev;
+		ino_t xino;
+
+		if (fh->fh_size != NFS_FHSIZE)
+			return error;
+		/* assume old filehandle format */
+		xdev = old_decode_dev(fh->ofh_xdev);
+		xino = u32_to_ino_t(fh->ofh_xino);
+		mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL);
+		exp = rqst_exp_find(rqstp, FSID_DEV, tfh);
+	}
+
+	error = nfserr_stale;
+	if (PTR_ERR(exp) == -ENOENT)
+		return error;
+
+	if (IS_ERR(exp))
+		return nfserrno(PTR_ERR(exp));
+
+	error = nfsd_setuser_and_check_port(rqstp, exp);
+	if (error)
+		goto out;
+
+	/*
+	 * Look up the dentry using the NFS file handle.
+	 */
+	error = nfserr_stale;
+	if (rqstp->rq_vers > 2)
+		error = nfserr_badhandle;
+
+	if (fh->fh_version != 1) {
+		sfid.i32.ino = fh->ofh_ino;
+		sfid.i32.gen = fh->ofh_generation;
+		sfid.i32.parent_ino = fh->ofh_dirino;
+		fid = &sfid;
+		data_left = 3;
+		if (fh->ofh_dirino == 0)
+			fileid_type = FILEID_INO32_GEN;
+		else
+			fileid_type = FILEID_INO32_GEN_PARENT;
+	} else
+		fileid_type = fh->fh_fileid_type;
+
+	if (fileid_type == FILEID_ROOT)
+		dentry = dget(exp->ex_path.dentry);
+	else {
+		dentry = exportfs_decode_fh(exp->ex_path.mnt, fid,
+				data_left, fileid_type,
+				nfsd_acceptable, exp);
+	}
+	if (dentry == NULL)
+		goto out;
+	if (IS_ERR(dentry)) {
+		if (PTR_ERR(dentry) != -EINVAL)
+			error = nfserrno(PTR_ERR(dentry));
+		goto out;
+	}
+
+	if (S_ISDIR(dentry->d_inode->i_mode) &&
+			(dentry->d_flags & DCACHE_DISCONNECTED)) {
+		printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n",
+				dentry->d_parent->d_name.name, dentry->d_name.name);
+	}
+
+	fhp->fh_dentry = dentry;
+	fhp->fh_export = exp;
+	nfsd_nr_verified++;
+	return 0;
+out:
+	exp_put(exp);
+	return error;
+}
+
+/*
  * Perform sanity checks on the dentry in a client's file handle.
  *
  * Note that the file handle dentry may need to be freed even after
@@ -124,115 +242,18 @@
 __be32
 fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
 {
-	struct knfsd_fh	*fh = &fhp->fh_handle;
-	struct svc_export *exp = NULL;
+	struct svc_export *exp;
 	struct dentry	*dentry;
-	__be32		error = 0;
+	__be32		error;
 
 	dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));
 
 	if (!fhp->fh_dentry) {
-		struct fid *fid = NULL, sfid;
-		int fileid_type;
-		int data_left = fh->fh_size/4;
-
-		error = nfserr_stale;
-		if (rqstp->rq_vers > 2)
-			error = nfserr_badhandle;
-		if (rqstp->rq_vers == 4 && fh->fh_size == 0)
-			return nfserr_nofilehandle;
-
-		if (fh->fh_version == 1) {
-			int len;
-			if (--data_left<0) goto out;
-			switch (fh->fh_auth_type) {
-			case 0: break;
-			default: goto out;
-			}
-			len = key_len(fh->fh_fsid_type) / 4;
-			if (len == 0) goto out;
-			if  (fh->fh_fsid_type == FSID_MAJOR_MINOR) {
-				/* deprecated, convert to type 3 */
-				len = key_len(FSID_ENCODE_DEV)/4;
-				fh->fh_fsid_type = FSID_ENCODE_DEV;
-				fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl(fh->fh_fsid[0]), ntohl(fh->fh_fsid[1])));
-				fh->fh_fsid[1] = fh->fh_fsid[2];
-			}
-			if ((data_left -= len)<0) goto out;
-			exp = rqst_exp_find(rqstp, fh->fh_fsid_type,
-					    fh->fh_auth);
-			fid = (struct fid *)(fh->fh_auth + len);
-		} else {
-			__u32 tfh[2];
-			dev_t xdev;
-			ino_t xino;
-			if (fh->fh_size != NFS_FHSIZE)
-				goto out;
-			/* assume old filehandle format */
-			xdev = old_decode_dev(fh->ofh_xdev);
-			xino = u32_to_ino_t(fh->ofh_xino);
-			mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL);
-			exp = rqst_exp_find(rqstp, FSID_DEV, tfh);
-		}
-
-		error = nfserr_stale;
-		if (PTR_ERR(exp) == -ENOENT)
-			goto out;
-
-		if (IS_ERR(exp)) {
-			error = nfserrno(PTR_ERR(exp));
-			goto out;
-		}
-
-		error = nfsd_setuser_and_check_port(rqstp, exp);
+		error = nfsd_set_fh_dentry(rqstp, fhp);
 		if (error)
 			goto out;
-
-		/*
-		 * Look up the dentry using the NFS file handle.
-		 */
-		error = nfserr_stale;
-		if (rqstp->rq_vers > 2)
-			error = nfserr_badhandle;
-
-		if (fh->fh_version != 1) {
-			sfid.i32.ino = fh->ofh_ino;
-			sfid.i32.gen = fh->ofh_generation;
-			sfid.i32.parent_ino = fh->ofh_dirino;
-			fid = &sfid;
-			data_left = 3;
-			if (fh->ofh_dirino == 0)
-				fileid_type = FILEID_INO32_GEN;
-			else
-				fileid_type = FILEID_INO32_GEN_PARENT;
-		} else
-			fileid_type = fh->fh_fileid_type;
-
-		if (fileid_type == FILEID_ROOT)
-			dentry = dget(exp->ex_path.dentry);
-		else {
-			dentry = exportfs_decode_fh(exp->ex_path.mnt, fid,
-					data_left, fileid_type,
-					nfsd_acceptable, exp);
-		}
-		if (dentry == NULL)
-			goto out;
-		if (IS_ERR(dentry)) {
-			if (PTR_ERR(dentry) != -EINVAL)
-				error = nfserrno(PTR_ERR(dentry));
-			goto out;
-		}
-
-		if (S_ISDIR(dentry->d_inode->i_mode) &&
-		    (dentry->d_flags & DCACHE_DISCONNECTED)) {
-			printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n",
-			       dentry->d_parent->d_name.name, dentry->d_name.name);
-		}
-
-		fhp->fh_dentry = dentry;
-		fhp->fh_export = exp;
-		nfsd_nr_verified++;
-		cache_get(&exp->h);
+		dentry = fhp->fh_dentry;
+		exp = fhp->fh_export;
 	} else {
 		/*
 		 * just rechecking permissions
@@ -242,7 +263,6 @@
 		dprintk("nfsd: fh_verify - just checking\n");
 		dentry = fhp->fh_dentry;
 		exp = fhp->fh_export;
-		cache_get(&exp->h);
 		/*
 		 * Set user creds for this exportpoint; necessary even
 		 * in the "just checking" case because this may be a
@@ -281,8 +301,6 @@
 			access, ntohl(error));
 	}
 out:
-	if (exp && !IS_ERR(exp))
-		exp_put(exp);
 	if (error == nfserr_stale)
 		nfsdstats.fh_stale++;
 	return error;
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 9647b0f..941041f 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -244,7 +244,6 @@
 	if (error < 0)
 		return error;
 
-#ifdef CONFIG_NFSD_TCP
 	error = lockd_up(IPPROTO_TCP);
 	if (error >= 0) {
 		error = svc_create_xprt(nfsd_serv, "tcp", port,
@@ -254,7 +253,6 @@
 	}
 	if (error < 0)
 		return error;
-#endif
 	return 0;
 }
 
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 304bf5f..a3a291f 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -264,7 +264,6 @@
 	struct inode	*inode;
 	int		accmode = MAY_SATTR;
 	int		ftype = 0;
-	int		imode;
 	__be32		err;
 	int		host_err;
 	int		size_change = 0;
@@ -360,25 +359,25 @@
 		DQUOT_INIT(inode);
 	}
 
-	imode = inode->i_mode;
+	/* sanitize the mode change */
 	if (iap->ia_valid & ATTR_MODE) {
 		iap->ia_mode &= S_IALLUGO;
-		imode = iap->ia_mode |= (imode & ~S_IALLUGO);
-		/* if changing uid/gid revoke setuid/setgid in mode */
-		if ((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) {
-			iap->ia_valid |= ATTR_KILL_PRIV;
+		iap->ia_mode |= (inode->i_mode & ~S_IALLUGO);
+	}
+
+	/* Revoke setuid/setgid on chown */
+	if (((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) ||
+	    ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid)) {
+		iap->ia_valid |= ATTR_KILL_PRIV;
+		if (iap->ia_valid & ATTR_MODE) {
+			/* we're setting mode too, just clear the s*id bits */
 			iap->ia_mode &= ~S_ISUID;
+			if (iap->ia_mode & S_IXGRP)
+				iap->ia_mode &= ~S_ISGID;
+		} else {
+			/* set ATTR_KILL_* bits and let VFS handle it */
+			iap->ia_valid |= (ATTR_KILL_SUID | ATTR_KILL_SGID);
 		}
-		if ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid)
-			iap->ia_mode &= ~S_ISGID;
-	} else {
-		/*
-		 * Revoke setuid/setgid bit on chown/chgrp
-		 */
-		if ((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid)
-			iap->ia_valid |= ATTR_KILL_SUID | ATTR_KILL_PRIV;
-		if ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid)
-			iap->ia_valid |= ATTR_KILL_SGID;
 	}
 
 	/* Change the attributes. */
@@ -988,7 +987,7 @@
 	 * flushing the data to disk is handled separately below.
 	 */
 
-	if (file->f_op->fsync == 0) {/* COMMIT3 cannot work */
+	if (!file->f_op->fsync) {/* COMMIT3 cannot work */
 	       stable = 2;
 	       *stablep = 2; /* FILE_SYNC */
 	}
@@ -1152,7 +1151,7 @@
 }
 #endif /* CONFIG_NFSD_V3 */
 
-__be32
+static __be32
 nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp,
 			struct iattr *iap)
 {
diff --git a/include/asm-blackfin/.gitignore b/include/asm-blackfin/.gitignore
new file mode 100644
index 0000000..7858564
--- /dev/null
+++ b/include/asm-blackfin/.gitignore
@@ -0,0 +1 @@
++mach
diff --git a/include/asm-blackfin/bfin-global.h b/include/asm-blackfin/bfin-global.h
index 5dba3a7..716df7c 100644
--- a/include/asm-blackfin/bfin-global.h
+++ b/include/asm-blackfin/bfin-global.h
@@ -112,20 +112,10 @@
 
 extern const char bfin_board_name[];
 extern unsigned long wall_jiffies;
-extern unsigned long ipdt_table[];
-extern unsigned long dpdt_table[];
-extern unsigned long icplb_table[];
-extern unsigned long dcplb_table[];
-
-extern unsigned long ipdt_swapcount_table[];
-extern unsigned long dpdt_swapcount_table[];
-
-extern unsigned long table_start, table_end;
 
 extern unsigned long bfin_sic_iwr[];
 extern u16 _bfin_swrst; /* shadow for Software Reset Register (SWRST) */
 extern struct file_operations dpmc_fops;
-extern char _start;
 extern unsigned long _ramstart, _ramend, _rambase;
 extern unsigned long memory_start, memory_end, physical_mem_end;
 extern char _stext_l1[], _etext_l1[], _sdata_l1[], _edata_l1[], _sbss_l1[],
diff --git a/include/asm-blackfin/bug.h b/include/asm-blackfin/bug.h
index 41e53b2..6d3e11b 100644
--- a/include/asm-blackfin/bug.h
+++ b/include/asm-blackfin/bug.h
@@ -1,4 +1,17 @@
 #ifndef _BLACKFIN_BUG_H
 #define _BLACKFIN_BUG_H
+
+#ifdef CONFIG_BUG
+#define HAVE_ARCH_BUG
+
+#define BUG() do { \
+	dump_bfin_trace_buffer(); \
+	printk(KERN_EMERG "BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
+	panic("BUG!"); \
+} while (0)
+
+#endif
+
 #include <asm-generic/bug.h>
+
 #endif
diff --git a/include/asm-blackfin/cplb.h b/include/asm-blackfin/cplb.h
index 654375c..5b0da9a 100644
--- a/include/asm-blackfin/cplb.h
+++ b/include/asm-blackfin/cplb.h
@@ -74,32 +74,6 @@
 #define ASYNC_MEMORY_CPLB_COVERAGE	((ASYNC_BANK0_SIZE + ASYNC_BANK1_SIZE + \
 				 ASYNC_BANK2_SIZE + ASYNC_BANK3_SIZE) / SIZE_4M)
 
-/*
-* Number of required data CPLB switchtable entries
-* MEMSIZE / 4 (we mostly install 4M page size CPLBs
-* approx 16 for smaller 1MB page size CPLBs for allignment purposes
-* 1 for L1 Data Memory
-* possibly 1 for L2 Data Memory
-* 1 for CONFIG_DEBUG_HUNT_FOR_ZERO
-* 1 for ASYNC Memory
-*/
-
-
-#define MAX_SWITCH_D_CPLBS (((CONFIG_MEM_SIZE / 4) + 16 + 1 + 1 + 1 \
-				 + ASYNC_MEMORY_CPLB_COVERAGE) * 2)
-
-/*
-* Number of required instruction CPLB switchtable entries
-* MEMSIZE / 4 (we mostly install 4M page size CPLBs
-* approx 12 for smaller 1MB page size CPLBs for allignment purposes
-* 1 for L1 Instruction Memory
-* possibly 1 for L2 Instruction Memory
-* 1 for CONFIG_DEBUG_HUNT_FOR_ZERO
-*/
-
-#define MAX_SWITCH_I_CPLBS (((CONFIG_MEM_SIZE / 4) + 12 + 1 + 1 + 1) * 2)
-
-
 #define CPLB_ENABLE_ICACHE_P	0
 #define CPLB_ENABLE_DCACHE_P	1
 #define CPLB_ENABLE_DCACHE2_P	2
diff --git a/include/asm-blackfin/dma-mapping.h b/include/asm-blackfin/dma-mapping.h
index 282fabc..1a13c2f 100644
--- a/include/asm-blackfin/dma-mapping.h
+++ b/include/asm-blackfin/dma-mapping.h
@@ -27,6 +27,14 @@
 extern dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
 				 enum dma_data_direction direction);
 
+static inline dma_addr_t
+dma_map_page(struct device *dev, struct page *page,
+	     unsigned long offset, size_t size,
+	     enum dma_data_direction dir)
+{
+	return dma_map_single(dev, page_address(page) + offset, size, dir);
+}
+
 /*
  * Unmap a single streaming mode DMA translation.  The dma_addr and size
  * must match what was provided for in a previous pci_map_single call.  All
@@ -38,6 +46,13 @@
 extern void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
 			  enum dma_data_direction direction);
 
+static inline void
+dma_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
+	       enum dma_data_direction dir)
+{
+	dma_unmap_single(dev, dma_addr, size, dir);
+}
+
 /*
  * Map a set of buffers described by scatterlist in streaming
  * mode for DMA.  This is the scather-gather version of the
diff --git a/include/asm-blackfin/dma.h b/include/asm-blackfin/dma.h
index 16d4935..c0d5259 100644
--- a/include/asm-blackfin/dma.h
+++ b/include/asm-blackfin/dma.h
@@ -191,4 +191,7 @@
 void *dma_memcpy(void *dest, const void *src, size_t count);
 void *safe_dma_memcpy(void *dest, const void *src, size_t count);
 
+extern int channel2irq(unsigned int channel);
+extern struct dma_register *dma_io_base_addr[MAX_BLACKFIN_DMA_CHANNEL];
+
 #endif
diff --git a/include/asm-blackfin/gptimers.h b/include/asm-blackfin/gptimers.h
index 4f318f1..0520d2a 100644
--- a/include/asm-blackfin/gptimers.h
+++ b/include/asm-blackfin/gptimers.h
@@ -22,6 +22,18 @@
 # define TIMER0_GROUP_REG      TIMER_ENABLE
 #endif
 /*
+ * BF54x: 11 timers (BF542: 8 timers):
+ */
+#if defined(BF548_FAMILY)
+# ifdef CONFIG_BF542
+#  define MAX_BLACKFIN_GPTIMERS 8
+# else
+#  define MAX_BLACKFIN_GPTIMERS 11
+#  define TIMER8_GROUP_REG      TIMER_ENABLE1
+# endif
+# define TIMER0_GROUP_REG       TIMER_ENABLE0
+#endif
+/*
  * BF561: 12 timers:
  */
 #if defined(CONFIG_BF561)
@@ -44,40 +56,28 @@
 #define TIMER0bit  0x0001  /*  0001b */
 #define TIMER1bit  0x0002  /*  0010b */
 #define TIMER2bit  0x0004  /*  0100b */
-
-#if (MAX_BLACKFIN_GPTIMERS > 3)
-# define TIMER3bit  0x0008
-# define TIMER4bit  0x0010
-# define TIMER5bit  0x0020
-# define TIMER6bit  0x0040
-# define TIMER7bit  0x0080
-#endif
-
-#if (MAX_BLACKFIN_GPTIMERS > 8)
-# define TIMER8bit  0x0100
-# define TIMER9bit  0x0200
-# define TIMER10bit 0x0400
-# define TIMER11bit 0x0800
-#endif
+#define TIMER3bit  0x0008
+#define TIMER4bit  0x0010
+#define TIMER5bit  0x0020
+#define TIMER6bit  0x0040
+#define TIMER7bit  0x0080
+#define TIMER8bit  0x0100
+#define TIMER9bit  0x0200
+#define TIMER10bit 0x0400
+#define TIMER11bit 0x0800
 
 #define TIMER0_id   0
 #define TIMER1_id   1
 #define TIMER2_id   2
-
-#if (MAX_BLACKFIN_GPTIMERS > 3)
-# define TIMER3_id   3
-# define TIMER4_id   4
-# define TIMER5_id   5
-# define TIMER6_id   6
-# define TIMER7_id   7
-#endif
-
-#if (MAX_BLACKFIN_GPTIMERS > 8)
-# define TIMER8_id   8
-# define TIMER9_id   9
-# define TIMER10_id 10
-# define TIMER11_id 11
-#endif
+#define TIMER3_id   3
+#define TIMER4_id   4
+#define TIMER5_id   5
+#define TIMER6_id   6
+#define TIMER7_id   7
+#define TIMER8_id   8
+#define TIMER9_id   9
+#define TIMER10_id 10
+#define TIMER11_id 11
 
 /* associated timers for ppi framesync: */
 
@@ -124,45 +124,31 @@
 /*
  * Timer Status Register Bits
  */
-#define TIMER_STATUS_TIMIL0 0x0001
-#define TIMER_STATUS_TIMIL1 0x0002
-#define TIMER_STATUS_TIMIL2 0x0004
-#if (MAX_BLACKFIN_GPTIMERS > 3)
-# define TIMER_STATUS_TIMIL3 0x00000008
-# define TIMER_STATUS_TIMIL4 0x00010000
-# define TIMER_STATUS_TIMIL5 0x00020000
-# define TIMER_STATUS_TIMIL6 0x00040000
-# define TIMER_STATUS_TIMIL7 0x00080000
-# if (MAX_BLACKFIN_GPTIMERS > 8)
-#  define TIMER_STATUS_TIMIL8  0x0001
-#  define TIMER_STATUS_TIMIL9  0x0002
-#  define TIMER_STATUS_TIMIL10 0x0004
-#  define TIMER_STATUS_TIMIL11 0x0008
-# endif
-# define TIMER_STATUS_INTR   0x000F000F
-#else
-# define TIMER_STATUS_INTR   0x0007	/* any timer interrupt */
-#endif
+#define TIMER_STATUS_TIMIL0  0x0001
+#define TIMER_STATUS_TIMIL1  0x0002
+#define TIMER_STATUS_TIMIL2  0x0004
+#define TIMER_STATUS_TIMIL3  0x00000008
+#define TIMER_STATUS_TIMIL4  0x00010000
+#define TIMER_STATUS_TIMIL5  0x00020000
+#define TIMER_STATUS_TIMIL6  0x00040000
+#define TIMER_STATUS_TIMIL7  0x00080000
+#define TIMER_STATUS_TIMIL8  0x0001
+#define TIMER_STATUS_TIMIL9  0x0002
+#define TIMER_STATUS_TIMIL10 0x0004
+#define TIMER_STATUS_TIMIL11 0x0008
 
-#define TIMER_STATUS_TOVF0  0x0010	/* timer 0 overflow error */
-#define TIMER_STATUS_TOVF1  0x0020
-#define TIMER_STATUS_TOVF2  0x0040
-#if (MAX_BLACKFIN_GPTIMERS > 3)
-# define TIMER_STATUS_TOVF3  0x00000080
-# define TIMER_STATUS_TOVF4  0x00100000
-# define TIMER_STATUS_TOVF5  0x00200000
-# define TIMER_STATUS_TOVF6  0x00400000
-# define TIMER_STATUS_TOVF7  0x00800000
-# if (MAX_BLACKFIN_GPTIMERS > 8)
-#  define TIMER_STATUS_TOVF8   0x0010
-#  define TIMER_STATUS_TOVF9   0x0020
-#  define TIMER_STATUS_TOVF10  0x0040
-#  define TIMER_STATUS_TOVF11  0x0080
-# endif
-# define TIMER_STATUS_OFLOW  0x00F000F0
-#else
-# define TIMER_STATUS_OFLOW  0x0070	/* any timer overflow */
-#endif
+#define TIMER_STATUS_TOVF0   0x0010	/* timer 0 overflow error */
+#define TIMER_STATUS_TOVF1   0x0020
+#define TIMER_STATUS_TOVF2   0x0040
+#define TIMER_STATUS_TOVF3   0x00000080
+#define TIMER_STATUS_TOVF4   0x00100000
+#define TIMER_STATUS_TOVF5   0x00200000
+#define TIMER_STATUS_TOVF6   0x00400000
+#define TIMER_STATUS_TOVF7   0x00800000
+#define TIMER_STATUS_TOVF8   0x0010
+#define TIMER_STATUS_TOVF9   0x0020
+#define TIMER_STATUS_TOVF10  0x0040
+#define TIMER_STATUS_TOVF11  0x0080
 
 /*
  * Timer Slave Enable Status : write 1 to clear
@@ -170,22 +156,16 @@
 #define TIMER_STATUS_TRUN0  0x1000
 #define TIMER_STATUS_TRUN1  0x2000
 #define TIMER_STATUS_TRUN2  0x4000
-#if (MAX_BLACKFIN_GPTIMERS > 3)
-# define TIMER_STATUS_TRUN3  0x00008000
-# define TIMER_STATUS_TRUN4  0x10000000
-# define TIMER_STATUS_TRUN5  0x20000000
-# define TIMER_STATUS_TRUN6  0x40000000
-# define TIMER_STATUS_TRUN7  0x80000000
-# define TIMER_STATUS_TRUN   0xF000F000
-# if (MAX_BLACKFIN_GPTIMERS > 8)
-#  define TIMER_STATUS_TRUN8  0x1000
-#  define TIMER_STATUS_TRUN9  0x2000
-#  define TIMER_STATUS_TRUN10 0x4000
-#  define TIMER_STATUS_TRUN11 0x8000
-# endif
-#else
-# define TIMER_STATUS_TRUN   0x7000
-#endif
+#define TIMER_STATUS_TRUN3  0x00008000
+#define TIMER_STATUS_TRUN4  0x10000000
+#define TIMER_STATUS_TRUN5  0x20000000
+#define TIMER_STATUS_TRUN6  0x40000000
+#define TIMER_STATUS_TRUN7  0x80000000
+#define TIMER_STATUS_TRUN   0xF000F000
+#define TIMER_STATUS_TRUN8  0x1000
+#define TIMER_STATUS_TRUN9  0x2000
+#define TIMER_STATUS_TRUN10 0x4000
+#define TIMER_STATUS_TRUN11 0x8000
 
 /* The actual gptimer API */
 
diff --git a/include/asm-blackfin/mach-bf527/anomaly.h b/include/asm-blackfin/mach-bf527/anomaly.h
index a891204..735fa02 100644
--- a/include/asm-blackfin/mach-bf527/anomaly.h
+++ b/include/asm-blackfin/mach-bf527/anomaly.h
@@ -2,12 +2,12 @@
  * File: include/asm-blackfin/mach-bf527/anomaly.h
  * Bugs: Enter bugs at http://blackfin.uclinux.org/
  *
- * Copyright (C) 2004-2007 Analog Devices Inc.
+ * Copyright (C) 2004-2008 Analog Devices Inc.
  * Licensed under the GPL-2 or later.
  */
 
 /* This file shoule be up to date with:
- *  - Revision A, May 30, 2007; ADSP-BF527 Blackfin Processor Anomaly List
+ *  - Revision C, 01/25/2008; ADSP-BF527 Blackfin Processor Anomaly List
  */
 
 #ifndef _MACH_ANOMALY_H_
@@ -15,35 +15,85 @@
 
 /* Multi-Issue Instruction with dsp32shiftimm in slot1 and P-reg Store in slot2 Not Supported */
 #define ANOMALY_05000074 (1)
-/* DMA_RUN Bit Is Not Valid after a Peripheral Receive Channel DMA Stops */
-#define ANOMALY_05000119 (1)
 /* Rx.H Cannot Be Used to Access 16-bit System MMR Registers */
 #define ANOMALY_05000122 (1)
 /* Spurious Hardware Error from an Access in the Shadow of a Conditional Branch */
 #define ANOMALY_05000245 (1)
 /* Sensitivity To Noise with Slow Input Edge Rates on External SPORT TX and RX Clocks */
 #define ANOMALY_05000265 (1)
-/* Memory-To-Memory DMA Source/Destination Descriptors Must Be in Same Memory Space */
-#define ANOMALY_05000301 (1)
-/* Errors When SSYNC, CSYNC, or Loads to LT, LB and LC Registers Are Interrupted */
-#define ANOMALY_05000312 (1)
 /* Incorrect Access of OTP_STATUS During otp_write() Function */
 #define ANOMALY_05000328 (1)
 /* Disallowed Configuration Prevents Subsequent Allowed Configuration on Host DMA Port */
 #define ANOMALY_05000337 (1)
-/* TWI Does Not Operate Correctly Under Certain Signal Termination Conditions */
+/* Ethernet MAC MDIO Reads Do Not Meet IEEE Specification */
+#define ANOMALY_05000341 (1)
+/* TWI May Not Operate Correctly Under Certain Signal Termination Conditions */
 #define ANOMALY_05000342 (1)
-/* Boot ROM Kernel Incorrectly Alters Reset Value of USB Register */
+/* USB Calibration Value Is Not Initialized */
+#define ANOMALY_05000346 (1)
+/* Preboot Routine Incorrectly Alters Reset Value of USB Register */
 #define ANOMALY_05000347 (1)
+/* Security Features Are Not Functional */
+#define ANOMALY_05000348 (__SILICON_REVISION__ < 1)
+/* Regulator Programming Blocked when Hibernate Wakeup Source Remains Active */
+#define ANOMALY_05000355 (1)
+/* Serial Port (SPORT) Multichannel Transmit Failure when Channel 0 Is Disabled */
+#define ANOMALY_05000357 (1)
+/* Incorrect Revision Number in DSPID Register */
+#define ANOMALY_05000364 (__SILICON_REVISION__ > 0)
+/* PPI Underflow Error Goes Undetected in ITU-R 656 Mode */
+#define ANOMALY_05000366 (1)
+/* New Feature: Higher Default CCLK Rate */
+#define ANOMALY_05000368 (1)
+/* Possible RETS Register Corruption when Subroutine Is under 5 Cycles in Duration */
+#define ANOMALY_05000371 (1)
+/* Authentication Fails To Initiate */
+#define ANOMALY_05000376 (__SILICON_REVISION__ > 0)
+/* Data Read From L3 Memory by USB DMA May be Corrupted */
+#define ANOMALY_05000380 (1)
+/* USB Full-speed Mode not Fully Tested */
+#define ANOMALY_05000381 (1)
+/* New Feature: Boot from OTP Memory */
+#define ANOMALY_05000385 (1)
+/* New Feature: bfrom_SysControl() Routine */
+#define ANOMALY_05000386 (1)
+/* New Feature: Programmable Preboot Settings */
+#define ANOMALY_05000387 (1)
+/* Reset Vector Must Not Be in SDRAM Memory Space */
+#define ANOMALY_05000389 (1)
+/* New Feature: pTempCurrent Added to ADI_BOOT_DATA Structure */
+#define ANOMALY_05000392 (1)
+/* New Feature: dTempByteCount Value Increased in ADI_BOOT_DATA Structure */
+#define ANOMALY_05000393 (1)
+/* New Feature: Log Buffer Functionality */
+#define ANOMALY_05000394 (1)
+/* New Feature: Hook Routine Functionality */
+#define ANOMALY_05000395 (1)
+/* New Feature: Header Indirect Bit */
+#define ANOMALY_05000396 (1)
+/* New Feature: BK_ONES, BK_ZEROS, and BK_DATECODE Constants */
+#define ANOMALY_05000397 (1)
+/* New Feature: SWRESET, DFRESET and WDRESET Bits Added to SYSCR Register */
+#define ANOMALY_05000398 (1)
+/* New Feature: BCODE_NOBOOT Added to BCODE Field of SYSCR Register */
+#define ANOMALY_05000399 (1)
+/* PPI Data Signals D0 and D8 do not Tristate After Disabling PPI */
+#define ANOMALY_05000401 (1)
 
 /* Anomalies that don't exist on this proc */
-#define ANOMALY_05000323 (0)
-#define ANOMALY_05000244 (0)
-#define ANOMALY_05000198 (0)
 #define ANOMALY_05000125 (0)
 #define ANOMALY_05000158 (0)
-#define ANOMALY_05000273 (0)
-#define ANOMALY_05000263 (0)
-#define ANOMALY_05000311 (0)
+#define ANOMALY_05000183 (0)
+#define ANOMALY_05000198 (0)
 #define ANOMALY_05000230 (0)
+#define ANOMALY_05000244 (0)
+#define ANOMALY_05000261 (0)
+#define ANOMALY_05000263 (0)
+#define ANOMALY_05000266 (0)
+#define ANOMALY_05000273 (0)
+#define ANOMALY_05000311 (0)
+#define ANOMALY_05000312 (0)
+#define ANOMALY_05000323 (0)
+#define ANOMALY_05000363 (0)
+
 #endif
diff --git a/include/asm-blackfin/mach-bf527/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf527/bfin_serial_5xx.h
index c0694ec..f0ab273 100644
--- a/include/asm-blackfin/mach-bf527/bfin_serial_5xx.h
+++ b/include/asm-blackfin/mach-bf527/bfin_serial_5xx.h
@@ -1,22 +1,38 @@
+/*
+ * file:        include/asm-blackfin/mach-bf527/bfin_serial_5xx.h
+ * based on:
+ * author:
+ *
+ * created:
+ * description:
+ *	blackfin serial driver head file
+ * rev:
+ *
+ * modified:
+ *
+ *
+ * bugs:         enter bugs at http://blackfin.uclinux.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, 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,
+ * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ */
+
 #include <linux/serial.h>
 #include <asm/dma.h>
 #include <asm/portmux.h>
 
-#define NR_PORTS		2
-
-#define OFFSET_THR              0x00	/* Transmit Holding register            */
-#define OFFSET_RBR              0x00	/* Receive Buffer register              */
-#define OFFSET_DLL              0x00	/* Divisor Latch (Low-Byte)             */
-#define OFFSET_IER              0x04	/* Interrupt Enable Register            */
-#define OFFSET_DLH              0x04	/* Divisor Latch (High-Byte)            */
-#define OFFSET_IIR              0x08	/* Interrupt Identification Register    */
-#define OFFSET_LCR              0x0C	/* Line Control Register                */
-#define OFFSET_MCR              0x10	/* Modem Control Register               */
-#define OFFSET_LSR              0x14	/* Line Status Register                 */
-#define OFFSET_MSR              0x18	/* Modem Status Register                */
-#define OFFSET_SCR              0x1C	/* SCR Scratch Register                 */
-#define OFFSET_GCTL             0x24	/* Global Control Register              */
-
 #define UART_GET_CHAR(uart)     bfin_read16(((uart)->port.membase + OFFSET_RBR))
 #define UART_GET_DLL(uart)	bfin_read16(((uart)->port.membase + OFFSET_DLL))
 #define UART_GET_IER(uart)      bfin_read16(((uart)->port.membase + OFFSET_IER))
@@ -92,7 +108,7 @@
 	bfin_write16(uart->port.membase + OFFSET_LSR, -1);
 }
 
-struct bfin_serial_port bfin_serial_ports[NR_PORTS];
+struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
 struct bfin_serial_res {
 	unsigned long uart_base_addr;
 	int uart_irq;
diff --git a/include/asm-blackfin/mach-bf527/bfin_sir.h b/include/asm-blackfin/mach-bf527/bfin_sir.h
new file mode 100644
index 0000000..0612d0c
--- /dev/null
+++ b/include/asm-blackfin/mach-bf527/bfin_sir.h
@@ -0,0 +1,133 @@
+/*
+ * Blackfin Infra-red Driver
+ *
+ * Copyright 2006-2008 Analog Devices Inc.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ *
+ */
+
+#include <linux/serial.h>
+#include <asm/dma.h>
+#include <asm/portmux.h>
+
+#define SIR_UART_GET_CHAR(port)   bfin_read16((port)->membase + OFFSET_RBR)
+#define SIR_UART_GET_DLL(port)    bfin_read16((port)->membase + OFFSET_DLL)
+#define SIR_UART_GET_IER(port)    bfin_read16((port)->membase + OFFSET_IER)
+#define SIR_UART_GET_DLH(port)    bfin_read16((port)->membase + OFFSET_DLH)
+#define SIR_UART_GET_IIR(port)    bfin_read16((port)->membase + OFFSET_IIR)
+#define SIR_UART_GET_LCR(port)    bfin_read16((port)->membase + OFFSET_LCR)
+#define SIR_UART_GET_GCTL(port)   bfin_read16((port)->membase + OFFSET_GCTL)
+
+#define SIR_UART_PUT_CHAR(port, v) bfin_write16(((port)->membase + OFFSET_THR), v)
+#define SIR_UART_PUT_DLL(port, v)  bfin_write16(((port)->membase + OFFSET_DLL), v)
+#define SIR_UART_PUT_IER(port, v)  bfin_write16(((port)->membase + OFFSET_IER), v)
+#define SIR_UART_PUT_DLH(port, v)  bfin_write16(((port)->membase + OFFSET_DLH), v)
+#define SIR_UART_PUT_LCR(port, v)  bfin_write16(((port)->membase + OFFSET_LCR), v)
+#define SIR_UART_PUT_GCTL(port, v) bfin_write16(((port)->membase + OFFSET_GCTL), v)
+
+#ifdef CONFIG_SIR_BFIN_DMA
+struct dma_rx_buf {
+	char *buf;
+	int head;
+	int tail;
+	};
+#endif /* CONFIG_SIR_BFIN_DMA */
+
+struct bfin_sir_port {
+	unsigned char __iomem   *membase;
+	unsigned int            irq;
+	unsigned int            lsr;
+	unsigned long           clk;
+	struct net_device       *dev;
+#ifdef CONFIG_SIR_BFIN_DMA
+	int                     tx_done;
+	struct dma_rx_buf       rx_dma_buf;
+	struct timer_list       rx_dma_timer;
+	int                     rx_dma_nrows;
+#endif /* CONFIG_SIR_BFIN_DMA */
+	unsigned int            tx_dma_channel;
+	unsigned int            rx_dma_channel;
+};
+
+struct bfin_sir_port sir_ports[BFIN_UART_NR_PORTS];
+
+struct bfin_sir_port_res {
+	unsigned long   base_addr;
+	int             irq;
+	unsigned int    rx_dma_channel;
+	unsigned int    tx_dma_channel;
+};
+
+struct bfin_sir_port_res bfin_sir_port_resource[] = {
+#ifdef CONFIG_BFIN_SIR0
+	{
+	0xFFC00400,
+	IRQ_UART0_RX,
+	CH_UART0_RX,
+	CH_UART0_TX,
+	},
+#endif
+#ifdef CONFIG_BFIN_SIR1
+	{
+	0xFFC02000,
+	IRQ_UART1_RX,
+	CH_UART1_RX,
+	CH_UART1_TX,
+	},
+#endif
+};
+
+int nr_sirs = ARRAY_SIZE(bfin_sir_port_resource);
+
+struct bfin_sir_self {
+	struct bfin_sir_port    *sir_port;
+	spinlock_t              lock;
+	unsigned int            open;
+	int                     speed;
+	int                     newspeed;
+
+	struct sk_buff          *txskb;
+	struct sk_buff          *rxskb;
+	struct net_device_stats stats;
+	struct device           *dev;
+	struct irlap_cb         *irlap;
+	struct qos_info         qos;
+
+	iobuff_t                tx_buff;
+	iobuff_t                rx_buff;
+
+	struct work_struct      work;
+	int                     mtt;
+};
+
+static inline unsigned int SIR_UART_GET_LSR(struct bfin_sir_port *port)
+{
+	unsigned int lsr = bfin_read16(port->membase + OFFSET_LSR);
+	port->lsr |= (lsr & (BI|FE|PE|OE));
+	return lsr | port->lsr;
+}
+
+static inline void SIR_UART_CLEAR_LSR(struct bfin_sir_port *port)
+{
+	port->lsr = 0;
+	bfin_read16(port->membase + OFFSET_LSR);
+}
+
+#define DRIVER_NAME "bfin_sir"
+
+static void bfin_sir_hw_init(void)
+{
+#ifdef CONFIG_BFIN_SIR0
+	peripheral_request(P_UART0_TX, DRIVER_NAME);
+	peripheral_request(P_UART0_RX, DRIVER_NAME);
+#endif
+
+#ifdef CONFIG_BFIN_SIR1
+	peripheral_request(P_UART1_TX, DRIVER_NAME);
+	peripheral_request(P_UART1_RX, DRIVER_NAME);
+#endif
+	SSYNC();
+}
diff --git a/include/asm-blackfin/mach-bf527/blackfin.h b/include/asm-blackfin/mach-bf527/blackfin.h
index 1bd07e3..2891727 100644
--- a/include/asm-blackfin/mach-bf527/blackfin.h
+++ b/include/asm-blackfin/mach-bf527/blackfin.h
@@ -64,6 +64,21 @@
 #define STATUS_P1	0x02
 #define STATUS_P0	0x01
 
+#define BFIN_UART_NR_PORTS	2
+
+#define OFFSET_THR              0x00	/* Transmit Holding register            */
+#define OFFSET_RBR              0x00	/* Receive Buffer register              */
+#define OFFSET_DLL              0x00	/* Divisor Latch (Low-Byte)             */
+#define OFFSET_IER              0x04	/* Interrupt Enable Register            */
+#define OFFSET_DLH              0x04	/* Divisor Latch (High-Byte)            */
+#define OFFSET_IIR              0x08	/* Interrupt Identification Register    */
+#define OFFSET_LCR              0x0C	/* Line Control Register                */
+#define OFFSET_MCR              0x10	/* Modem Control Register               */
+#define OFFSET_LSR              0x14	/* Line Status Register                 */
+#define OFFSET_MSR              0x18	/* Modem Status Register                */
+#define OFFSET_SCR              0x1C	/* SCR Scratch Register                 */
+#define OFFSET_GCTL             0x24	/* Global Control Register              */
+
 /* DPMC*/
 #define bfin_read_STOPCK_OFF() bfin_read_STOPCK()
 #define bfin_write_STOPCK_OFF(val) bfin_write_STOPCK(val)
diff --git a/include/asm-blackfin/mach-bf527/cdefBF52x_base.h b/include/asm-blackfin/mach-bf527/cdefBF52x_base.h
index 3f4de5d..9dbdbec 100644
--- a/include/asm-blackfin/mach-bf527/cdefBF52x_base.h
+++ b/include/asm-blackfin/mach-bf527/cdefBF52x_base.h
@@ -29,18 +29,71 @@
  */
 
 #ifndef _CDEF_BF52X_H
+#define _CDEF_BF52X_H
+
+#include <asm/system.h>
+#include <asm/blackfin.h>
 
 #include "defBF52x_base.h"
 
+/* Include core specific register pointer definitions 								*/
+#include <asm/mach-common/cdef_LPBlackfin.h>
+
 /* ==== begin from cdefBF534.h ==== */
 
 /* Clock and System Control	(0xFFC00000 - 0xFFC000FF)								*/
 #define bfin_read_PLL_CTL()			bfin_read16(PLL_CTL)
-#define bfin_write_PLL_CTL(val)			bfin_write16(PLL_CTL, val)
+/* Writing to PLL_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_PLL_CTL(unsigned int val)
+{
+	unsigned long flags, iwr0, iwr1;
+
+	if (val == bfin_read_PLL_CTL())
+		return;
+
+	local_irq_save(flags);
+	/* Enable the PLL Wakeup bit in SIC IWR */
+	iwr0 = bfin_read32(SIC_IWR0);
+	iwr1 = bfin_read32(SIC_IWR1);
+	/* Only allow PPL Wakeup) */
+	bfin_write32(SIC_IWR0, IWR_ENABLE(0));
+	bfin_write32(SIC_IWR1, 0);
+
+	bfin_write16(PLL_CTL, val);
+	SSYNC();
+	asm("IDLE;");
+
+	bfin_write32(SIC_IWR0, iwr0);
+	bfin_write32(SIC_IWR1, iwr1);
+	local_irq_restore(flags);
+}
 #define bfin_read_PLL_DIV()			bfin_read16(PLL_DIV)
 #define bfin_write_PLL_DIV(val)			bfin_write16(PLL_DIV, val)
 #define bfin_read_VR_CTL()			bfin_read16(VR_CTL)
-#define bfin_write_VR_CTL(val)			bfin_write16(VR_CTL, val)
+/* Writing to VR_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_VR_CTL(unsigned int val)
+{
+	unsigned long flags, iwr0, iwr1;
+
+	if (val == bfin_read_VR_CTL())
+		return;
+
+	local_irq_save(flags);
+	/* Enable the PLL Wakeup bit in SIC IWR */
+	iwr0 = bfin_read32(SIC_IWR0);
+	iwr1 = bfin_read32(SIC_IWR1);
+	/* Only allow PPL Wakeup) */
+	bfin_write32(SIC_IWR0, IWR_ENABLE(0));
+	bfin_write32(SIC_IWR1, 0);
+
+	bfin_write16(VR_CTL, val);
+	SSYNC();
+	asm("IDLE;");
+
+	bfin_write32(SIC_IWR0, iwr0);
+	bfin_write32(SIC_IWR1, iwr1);
+	local_irq_restore(flags);
+}
 #define bfin_read_PLL_STAT()			bfin_read16(PLL_STAT)
 #define bfin_write_PLL_STAT(val)		bfin_write16(PLL_STAT, val)
 #define bfin_read_PLL_LOCKCNT()			bfin_read16(PLL_LOCKCNT)
@@ -873,39 +926,6 @@
 
 
 /* Two-Wire Interface		(0xFFC01400 - 0xFFC014FF)								*/
-#define bfin_read_TWI_CLKDIV()			bfin_read16(TWI_CLKDIV)
-#define bfin_write_TWI_CLKDIV(val)		bfin_write16(TWI_CLKDIV, val)
-#define bfin_read_TWI_CONTROL()			bfin_read16(TWI_CONTROL)
-#define bfin_write_TWI_CONTROL(val)		bfin_write16(TWI_CONTROL, val)
-#define bfin_read_TWI_SLAVE_CTL()		bfin_read16(TWI_SLAVE_CTL)
-#define bfin_write_TWI_SLAVE_CTL(val)		bfin_write16(TWI_SLAVE_CTL, val)
-#define bfin_read_TWI_SLAVE_STAT()		bfin_read16(TWI_SLAVE_STAT)
-#define bfin_write_TWI_SLAVE_STAT(val)		bfin_write16(TWI_SLAVE_STAT, val)
-#define bfin_read_TWI_SLAVE_ADDR()		bfin_read16(TWI_SLAVE_ADDR)
-#define bfin_write_TWI_SLAVE_ADDR(val)		bfin_write16(TWI_SLAVE_ADDR, val)
-#define bfin_read_TWI_MASTER_CTL()		bfin_read16(TWI_MASTER_CTL)
-#define bfin_write_TWI_MASTER_CTL(val)		bfin_write16(TWI_MASTER_CTL, val)
-#define bfin_read_TWI_MASTER_STAT()		bfin_read16(TWI_MASTER_STAT)
-#define bfin_write_TWI_MASTER_STAT(val)		bfin_write16(TWI_MASTER_STAT, val)
-#define bfin_read_TWI_MASTER_ADDR()		bfin_read16(TWI_MASTER_ADDR)
-#define bfin_write_TWI_MASTER_ADDR(val)		bfin_write16(TWI_MASTER_ADDR, val)
-#define bfin_read_TWI_INT_STAT()		bfin_read16(TWI_INT_STAT)
-#define bfin_write_TWI_INT_STAT(val)		bfin_write16(TWI_INT_STAT, val)
-#define bfin_read_TWI_INT_MASK()		bfin_read16(TWI_INT_MASK)
-#define bfin_write_TWI_INT_MASK(val)		bfin_write16(TWI_INT_MASK, val)
-#define bfin_read_TWI_FIFO_CTL()		bfin_read16(TWI_FIFO_CTL)
-#define bfin_write_TWI_FIFO_CTL(val)		bfin_write16(TWI_FIFO_CTL, val)
-#define bfin_read_TWI_FIFO_STAT()		bfin_read16(TWI_FIFO_STAT)
-#define bfin_write_TWI_FIFO_STAT(val)		bfin_write16(TWI_FIFO_STAT, val)
-#define bfin_read_TWI_XMT_DATA8()		bfin_read16(TWI_XMT_DATA8)
-#define bfin_write_TWI_XMT_DATA8(val)		bfin_write16(TWI_XMT_DATA8, val)
-#define bfin_read_TWI_XMT_DATA16()		bfin_read16(TWI_XMT_DATA16)
-#define bfin_write_TWI_XMT_DATA16(val)		bfin_write16(TWI_XMT_DATA16, val)
-#define bfin_read_TWI_RCV_DATA8()		bfin_read16(TWI_RCV_DATA8)
-#define bfin_write_TWI_RCV_DATA8(val)		bfin_write16(TWI_RCV_DATA8, val)
-#define bfin_read_TWI_RCV_DATA16()		bfin_read16(TWI_RCV_DATA16)
-#define bfin_write_TWI_RCV_DATA16(val)		bfin_write16(TWI_RCV_DATA16, val)
-
 
 /* General Purpose I/O Port G (0xFFC01500 - 0xFFC015FF)								*/
 #define bfin_read_PORTGIO()			bfin_read16(PORTGIO)
diff --git a/include/asm-blackfin/mach-bf527/dma.h b/include/asm-blackfin/mach-bf527/dma.h
index 2dfee12..49dd693 100644
--- a/include/asm-blackfin/mach-bf527/dma.h
+++ b/include/asm-blackfin/mach-bf527/dma.h
@@ -59,7 +59,4 @@
 #define CH_NFC			CH_EMAC_TX /* PPI receive/transmit or NFC */
 #endif
 
-extern int channel2irq(unsigned int channel);
-extern struct dma_register *base_addr[];
-
 #endif
diff --git a/include/asm-blackfin/mach-bf533/anomaly.h b/include/asm-blackfin/mach-bf533/anomaly.h
index 98209d4..5a6dcc5 100644
--- a/include/asm-blackfin/mach-bf533/anomaly.h
+++ b/include/asm-blackfin/mach-bf533/anomaly.h
@@ -7,7 +7,7 @@
  */
 
 /* This file shoule be up to date with:
- *  - Revision B, 12/10/2007; ADSP-BF531/BF532/BF533 Blackfin Processor Anomaly List
+ *  - Revision C, 02/08/2008; ADSP-BF531/BF532/BF533 Blackfin Processor Anomaly List
  */
 
 #ifndef _MACH_ANOMALY_H_
@@ -251,10 +251,18 @@
 #define ANOMALY_05000206 (__SILICON_REVISION__ < 3)
 /* Serial Port (SPORT) Multichannel Transmit Failure when Channel 0 Is Disabled */
 #define ANOMALY_05000357 (1)
+/* UART Break Signal Issues */
+#define ANOMALY_05000363 (__SILICON_REVISION__ < 5)
 /* PPI Underflow Error Goes Undetected in ITU-R 656 Mode */
 #define ANOMALY_05000366 (1)
 /* Possible RETS Register Corruption when Subroutine Is under 5 Cycles in Duration */
 #define ANOMALY_05000371 (1)
+/* PPI Does Not Start Properly In Specific Mode */
+#define ANOMALY_05000400 (__SILICON_REVISION__ == 5)
+/* SSYNC Stalls Processor when Executed from Non-Cacheable Memory */
+#define ANOMALY_05000402 (__SILICON_REVISION__ == 5)
+/* Level-Sensitive External GPIO Wakeups May Cause Indefinite Stall */
+#define ANOMALY_05000403 (1)
 
 /* Anomalies that don't exist on this proc */
 #define ANOMALY_05000266 (0)
diff --git a/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
index b6f513b..fbe88de 100644
--- a/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
+++ b/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
@@ -1,22 +1,38 @@
+/*
+ * file:        include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
+ * based on:
+ * author:
+ *
+ * created:
+ * description:
+ *	blackfin serial driver head file
+ * rev:
+ *
+ * modified:
+ *
+ *
+ * bugs:         enter bugs at http://blackfin.uclinux.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, 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,
+ * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ */
+
 #include <linux/serial.h>
 #include <asm/dma.h>
 #include <asm/portmux.h>
 
-#define NR_PORTS                1
-
-#define OFFSET_THR              0x00	/* Transmit Holding register            */
-#define OFFSET_RBR              0x00	/* Receive Buffer register              */
-#define OFFSET_DLL              0x00	/* Divisor Latch (Low-Byte)             */
-#define OFFSET_IER              0x04	/* Interrupt Enable Register            */
-#define OFFSET_DLH              0x04	/* Divisor Latch (High-Byte)            */
-#define OFFSET_IIR              0x08	/* Interrupt Identification Register    */
-#define OFFSET_LCR              0x0C	/* Line Control Register                */
-#define OFFSET_MCR              0x10	/* Modem Control Register               */
-#define OFFSET_LSR              0x14	/* Line Status Register                 */
-#define OFFSET_MSR              0x18	/* Modem Status Register                */
-#define OFFSET_SCR              0x1C	/* SCR Scratch Register                 */
-#define OFFSET_GCTL             0x24	/* Global Control Register              */
-
 #define UART_GET_CHAR(uart)     bfin_read16(((uart)->port.membase + OFFSET_RBR))
 #define UART_GET_DLL(uart)	bfin_read16(((uart)->port.membase + OFFSET_DLL))
 #define UART_GET_IER(uart)      bfin_read16(((uart)->port.membase + OFFSET_IER))
@@ -84,7 +100,7 @@
 	bfin_write16(uart->port.membase + OFFSET_LSR, -1);
 }
 
-struct bfin_serial_port bfin_serial_ports[NR_PORTS];
+struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
 struct bfin_serial_res {
 	unsigned long	uart_base_addr;
 	int		uart_irq;
@@ -115,7 +131,7 @@
 
 #define DRIVER_NAME "bfin-uart"
 
-int nr_ports = NR_PORTS;
+int nr_ports = BFIN_UART_NR_PORTS;
 static void bfin_serial_hw_init(struct bfin_serial_port *uart)
 {
 
diff --git a/include/asm-blackfin/mach-bf533/bfin_sir.h b/include/asm-blackfin/mach-bf533/bfin_sir.h
new file mode 100644
index 0000000..cefcf8b
--- /dev/null
+++ b/include/asm-blackfin/mach-bf533/bfin_sir.h
@@ -0,0 +1,120 @@
+/*
+ * Blackfin Infra-red Driver
+ *
+ * Copyright 2006-2008 Analog Devices Inc.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ *
+ */
+
+#include <linux/serial.h>
+#include <asm/dma.h>
+#include <asm/portmux.h>
+
+#define SIR_UART_GET_CHAR(port)   bfin_read16((port)->membase + OFFSET_RBR)
+#define SIR_UART_GET_DLL(port)    bfin_read16((port)->membase + OFFSET_DLL)
+#define SIR_UART_GET_IER(port)    bfin_read16((port)->membase + OFFSET_IER)
+#define SIR_UART_GET_DLH(port)    bfin_read16((port)->membase + OFFSET_DLH)
+#define SIR_UART_GET_IIR(port)    bfin_read16((port)->membase + OFFSET_IIR)
+#define SIR_UART_GET_LCR(port)    bfin_read16((port)->membase + OFFSET_LCR)
+#define SIR_UART_GET_GCTL(port)   bfin_read16((port)->membase + OFFSET_GCTL)
+
+#define SIR_UART_PUT_CHAR(port, v) bfin_write16(((port)->membase + OFFSET_THR), v)
+#define SIR_UART_PUT_DLL(port, v)  bfin_write16(((port)->membase + OFFSET_DLL), v)
+#define SIR_UART_PUT_IER(port, v)  bfin_write16(((port)->membase + OFFSET_IER), v)
+#define SIR_UART_PUT_DLH(port, v)  bfin_write16(((port)->membase + OFFSET_DLH), v)
+#define SIR_UART_PUT_LCR(port, v)  bfin_write16(((port)->membase + OFFSET_LCR), v)
+#define SIR_UART_PUT_GCTL(port, v) bfin_write16(((port)->membase + OFFSET_GCTL), v)
+
+#ifdef CONFIG_SIR_BFIN_DMA
+struct dma_rx_buf {
+	char *buf;
+	int head;
+	int tail;
+	};
+#endif /* CONFIG_SIR_BFIN_DMA */
+
+struct bfin_sir_port {
+	unsigned char __iomem   *membase;
+	unsigned int            irq;
+	unsigned int            lsr;
+	unsigned long           clk;
+	struct net_device       *dev;
+#ifdef CONFIG_SIR_BFIN_DMA
+	int                     tx_done;
+	struct dma_rx_buf       rx_dma_buf;
+	struct timer_list       rx_dma_timer;
+	int                     rx_dma_nrows;
+#endif /* CONFIG_SIR_BFIN_DMA */
+	unsigned int            tx_dma_channel;
+	unsigned int            rx_dma_channel;
+};
+
+struct bfin_sir_port sir_ports[BFIN_UART_NR_PORTS];
+
+struct bfin_sir_port_res {
+	unsigned long   base_addr;
+	int             irq;
+	unsigned int    rx_dma_channel;
+	unsigned int    tx_dma_channel;
+};
+
+struct bfin_sir_port_res bfin_sir_port_resource[] = {
+#ifdef CONFIG_BFIN_SIR0
+	{
+	0xFFC00400,
+	IRQ_UART_RX,
+	CH_UART_RX,
+	CH_UART_TX,
+	},
+#endif
+};
+
+int nr_sirs = ARRAY_SIZE(bfin_sir_port_resource);
+
+struct bfin_sir_self {
+	struct bfin_sir_port    *sir_port;
+	spinlock_t              lock;
+	unsigned int            open;
+	int                     speed;
+	int                     newspeed;
+
+	struct sk_buff          *txskb;
+	struct sk_buff          *rxskb;
+	struct net_device_stats stats;
+	struct device           *dev;
+	struct irlap_cb         *irlap;
+	struct qos_info         qos;
+
+	iobuff_t                tx_buff;
+	iobuff_t                rx_buff;
+
+	struct work_struct      work;
+	int                     mtt;
+};
+
+static inline unsigned int SIR_UART_GET_LSR(struct bfin_sir_port *port)
+{
+	unsigned int lsr = bfin_read16(port->membase + OFFSET_LSR);
+	port->lsr |= (lsr & (BI|FE|PE|OE));
+	return lsr | port->lsr;
+}
+
+static inline void SIR_UART_CLEAR_LSR(struct bfin_sir_port *port)
+{
+	port->lsr = 0;
+	bfin_read16(port->membase + OFFSET_LSR);
+}
+
+#define DRIVER_NAME "bfin_sir"
+
+static void bfin_sir_hw_init(void)
+{
+#ifdef CONFIG_BFIN_SIR0
+	peripheral_request(P_UART0_TX, DRIVER_NAME);
+	peripheral_request(P_UART0_RX, DRIVER_NAME);
+#endif
+	SSYNC();
+}
diff --git a/include/asm-blackfin/mach-bf533/blackfin.h b/include/asm-blackfin/mach-bf533/blackfin.h
index f3b240ab..d80971b 100644
--- a/include/asm-blackfin/mach-bf533/blackfin.h
+++ b/include/asm-blackfin/mach-bf533/blackfin.h
@@ -42,4 +42,19 @@
 #include "cdefBF532.h"
 #endif
 
+#define BFIN_UART_NR_PORTS      1
+
+#define OFFSET_THR              0x00	/* Transmit Holding register            */
+#define OFFSET_RBR              0x00	/* Receive Buffer register              */
+#define OFFSET_DLL              0x00	/* Divisor Latch (Low-Byte)             */
+#define OFFSET_IER              0x04	/* Interrupt Enable Register            */
+#define OFFSET_DLH              0x04	/* Divisor Latch (High-Byte)            */
+#define OFFSET_IIR              0x08	/* Interrupt Identification Register    */
+#define OFFSET_LCR              0x0C	/* Line Control Register                */
+#define OFFSET_MCR              0x10	/* Modem Control Register               */
+#define OFFSET_LSR              0x14	/* Line Status Register                 */
+#define OFFSET_MSR              0x18	/* Modem Status Register                */
+#define OFFSET_SCR              0x1C	/* SCR Scratch Register                 */
+#define OFFSET_GCTL             0x24	/* Global Control Register              */
+
 #endif				/* _MACH_BLACKFIN_H_ */
diff --git a/include/asm-blackfin/mach-bf533/cdefBF532.h b/include/asm-blackfin/mach-bf533/cdefBF532.h
index c803e14..1546554 100644
--- a/include/asm-blackfin/mach-bf533/cdefBF532.h
+++ b/include/asm-blackfin/mach-bf533/cdefBF532.h
@@ -43,7 +43,27 @@
 
 /* Clock and System Control (0xFFC0 0400-0xFFC0 07FF) */
 #define bfin_read_PLL_CTL()                  bfin_read16(PLL_CTL)
-#define bfin_write_PLL_CTL(val)              bfin_write16(PLL_CTL,val)
+/* Writing to PLL_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_PLL_CTL(unsigned int val)
+{
+	unsigned long flags, iwr;
+
+	if (val == bfin_read_PLL_CTL())
+		return;
+
+	local_irq_save(flags);
+	/* Enable the PLL Wakeup bit in SIC IWR */
+	iwr = bfin_read32(SIC_IWR);
+	/* Only allow PPL Wakeup) */
+	bfin_write32(SIC_IWR, IWR_ENABLE(0));
+
+	bfin_write16(PLL_CTL, val);
+	SSYNC();
+	asm("IDLE;");
+
+	bfin_write32(SIC_IWR, iwr);
+	local_irq_restore(flags);
+}
 #define bfin_read_PLL_STAT()                 bfin_read16(PLL_STAT)
 #define bfin_write_PLL_STAT(val)             bfin_write16(PLL_STAT,val)
 #define bfin_read_PLL_LOCKCNT()              bfin_read16(PLL_LOCKCNT)
@@ -57,6 +77,10 @@
 {
 	unsigned long flags, iwr;
 
+	if (val == bfin_read_VR_CTL())
+		return;
+
+	local_irq_save(flags);
 	/* Enable the PLL Wakeup bit in SIC IWR */
 	iwr = bfin_read32(SIC_IWR);
 	/* Only allow PPL Wakeup) */
@@ -64,11 +88,10 @@
 
 	bfin_write16(VR_CTL, val);
 	SSYNC();
-
-	local_irq_save(flags);
 	asm("IDLE;");
-	local_irq_restore(flags);
+
 	bfin_write32(SIC_IWR, iwr);
+	local_irq_restore(flags);
 }
 
 /* System Interrupt Controller (0xFFC0 0C00-0xFFC0 0FFF) */
diff --git a/include/asm-blackfin/mach-bf533/defBF532.h b/include/asm-blackfin/mach-bf533/defBF532.h
index 37134aa..17e1548 100644
--- a/include/asm-blackfin/mach-bf533/defBF532.h
+++ b/include/asm-blackfin/mach-bf533/defBF532.h
@@ -88,20 +88,25 @@
 #define RTC_PREN			0xFFC00314	/* RTC Prescaler Enable Register (alternate macro) */
 
 /* UART Controller (0xFFC00400 - 0xFFC004FF) */
-#define UART_THR             		 0xFFC00400	/* Transmit Holding register */
-#define UART_RBR             		 0xFFC00400	/* Receive Buffer register */
-#define UART_DLL              		 0xFFC00400	/* Divisor Latch (Low-Byte) */
-#define UART_IER              		 0xFFC00404	/* Interrupt Enable Register */
-#define UART_DLH              		 0xFFC00404	/* Divisor Latch (High-Byte) */
-#define UART_IIR              		 0xFFC00408	/* Interrupt Identification Register */
-#define UART_LCR              		 0xFFC0040C	/* Line Control Register */
-#define UART_MCR			 0xFFC00410	/* Modem Control Register */
-#define UART_LSR              		 0xFFC00414	/* Line Status Register */
+
+/*
+ * Because include/linux/serial_reg.h have defined UART_*,
+ * So we define blackfin uart regs to BFIN_UART_*.
+ */
+#define BFIN_UART_THR			0xFFC00400	/* Transmit Holding register */
+#define BFIN_UART_RBR			0xFFC00400	/* Receive Buffer register */
+#define BFIN_UART_DLL			0xFFC00400	/* Divisor Latch (Low-Byte) */
+#define BFIN_UART_IER			0xFFC00404	/* Interrupt Enable Register */
+#define BFIN_UART_DLH			0xFFC00404	/* Divisor Latch (High-Byte) */
+#define BFIN_UART_IIR			0xFFC00408	/* Interrupt Identification Register */
+#define BFIN_UART_LCR			0xFFC0040C	/* Line Control Register */
+#define BFIN_UART_MCR			0xFFC00410	/* Modem Control Register */
+#define BFIN_UART_LSR			0xFFC00414	/* Line Status Register */
 #if 0
-#define UART_MSR            		 0xFFC00418   /* Modem Status Register (UNUSED in ADSP-BF532) */
+#define BFIN_UART_MSR			0xFFC00418	/* Modem Status Register (UNUSED in ADSP-BF532) */
 #endif
-#define UART_SCR              		 0xFFC0041C	/* SCR Scratch Register */
-#define UART_GCTL      	      		 0xFFC00424	/* Global Control Register */
+#define BFIN_UART_SCR			0xFFC0041C	/* SCR Scratch Register */
+#define BFIN_UART_GCTL			0xFFC00424	/* Global Control Register */
 
 /* SPI Controller (0xFFC00500 - 0xFFC005FF) */
 #define SPI0_REGBASE          		0xFFC00500
diff --git a/include/asm-blackfin/mach-bf533/dma.h b/include/asm-blackfin/mach-bf533/dma.h
index 16c672c..bd9d5e9 100644
--- a/include/asm-blackfin/mach-bf533/dma.h
+++ b/include/asm-blackfin/mach-bf533/dma.h
@@ -51,7 +51,4 @@
 #define CH_MEM_STREAM1_DEST     10	 /* TX */
 #define CH_MEM_STREAM1_SRC      11	 /* RX */
 
-extern int channel2irq(unsigned int channel);
-extern struct dma_register *base_addr[];
-
 #endif
diff --git a/include/asm-blackfin/mach-bf533/mem_init.h b/include/asm-blackfin/mach-bf533/mem_init.h
index 1620dae..f8f3190 100644
--- a/include/asm-blackfin/mach-bf533/mem_init.h
+++ b/include/asm-blackfin/mach-bf533/mem_init.h
@@ -29,7 +29,8 @@
  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
-#if (CONFIG_MEM_MT48LC16M16A2TG_75 || CONFIG_MEM_MT48LC64M4A2FB_7E || CONFIG_MEM_GENERIC_BOARD)
+#if (CONFIG_MEM_MT48LC16M16A2TG_75 || CONFIG_MEM_MT48LC64M4A2FB_7E || \
+     CONFIG_MEM_MT48LC32M16A2TG_75 || CONFIG_MEM_GENERIC_BOARD)
 #if (CONFIG_SCLK_HZ > 119402985)
 #define SDRAM_tRP       TRP_2
 #define SDRAM_tRP_num   2
@@ -118,6 +119,13 @@
 #define SDRAM_CL    CL_3
 #endif
 
+#if (CONFIG_MEM_MT48LC32M16A2TG_75)
+  /*SDRAM INFORMATION: */
+#define SDRAM_Tref  64		/* Refresh period in milliseconds   */
+#define SDRAM_NRA   8192	/* Number of row addresses in SDRAM */
+#define SDRAM_CL    CL_3
+#endif
+
 #if (CONFIG_MEM_GENERIC_BOARD)
   /*SDRAM INFORMATION: Modify this for your board */
 #define SDRAM_Tref  64		/* Refresh period in milliseconds   */
diff --git a/include/asm-blackfin/mach-bf537/anomaly.h b/include/asm-blackfin/mach-bf537/anomaly.h
index 746a794..a6b08fa 100644
--- a/include/asm-blackfin/mach-bf537/anomaly.h
+++ b/include/asm-blackfin/mach-bf537/anomaly.h
@@ -7,7 +7,7 @@
  */
 
 /* This file shoule be up to date with:
- *  - Revision A, 09/04/2007; ADSP-BF534/ADSP-BF536/ADSP-BF537 Blackfin Processor Anomaly List
+ *  - Revision C, 02/08/2008; ADSP-BF534/ADSP-BF536/ADSP-BF537 Blackfin Processor Anomaly List
  */
 
 #ifndef _MACH_ANOMALY_H_
@@ -132,10 +132,24 @@
 #define ANOMALY_05000322 (1)
 /* Ethernet MAC MDIO Reads Do Not Meet IEEE Specification */
 #define ANOMALY_05000341 (__SILICON_REVISION__ >= 3)
+/* New Feature: UART Remains Enabled after UART Boot (Not Available on Older Silicon) */
+#define ANOMALY_05000350 (__SILICON_REVISION__ < 3)
+/* Regulator Programming Blocked when Hibernate Wakeup Source Remains Active */
+#define ANOMALY_05000355 (1)
 /* Serial Port (SPORT) Multichannel Transmit Failure when Channel 0 Is Disabled */
 #define ANOMALY_05000357 (1)
 /* DMAs that Go Urgent during Tight Core Writes to External Memory Are Blocked */
 #define ANOMALY_05000359 (1)
+/* PPI Underflow Error Goes Undetected in ITU-R 656 Mode */
+#define ANOMALY_05000366 (1)
+/* Possible RETS Register Corruption when Subroutine Is under 5 Cycles in Duration */
+#define ANOMALY_05000371 (1)
+/* SSYNC Stalls Processor when Executed from Non-Cacheable Memory */
+#define ANOMALY_05000402 (__SILICON_REVISION__ >= 3)
+/* Level-Sensitive External GPIO Wakeups May Cause Indefinite Stall */
+#define ANOMALY_05000403 (1)
+
+
 
 /* Anomalies that don't exist on this proc */
 #define ANOMALY_05000125 (0)
@@ -146,5 +160,6 @@
 #define ANOMALY_05000266 (0)
 #define ANOMALY_05000311 (0)
 #define ANOMALY_05000323 (0)
+#define ANOMALY_05000363 (0)
 
 #endif
diff --git a/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
index 8fc672d..fd100a4 100644
--- a/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
+++ b/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
@@ -1,22 +1,38 @@
+/*
+ * file:         include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
+ * based on:
+ * author:
+ *
+ * created:
+ * description:
+ *	blackfin serial driver header files
+ * rev:
+ *
+ * modified:
+ *
+ *
+ * bugs:         enter bugs at http://blackfin.uclinux.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, 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,
+ * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ */
+
 #include <linux/serial.h>
 #include <asm/dma.h>
 #include <asm/portmux.h>
 
-#define NR_PORTS		2
-
-#define OFFSET_THR              0x00	/* Transmit Holding register            */
-#define OFFSET_RBR              0x00	/* Receive Buffer register              */
-#define OFFSET_DLL              0x00	/* Divisor Latch (Low-Byte)             */
-#define OFFSET_IER              0x04	/* Interrupt Enable Register            */
-#define OFFSET_DLH              0x04	/* Divisor Latch (High-Byte)            */
-#define OFFSET_IIR              0x08	/* Interrupt Identification Register    */
-#define OFFSET_LCR              0x0C	/* Line Control Register                */
-#define OFFSET_MCR              0x10	/* Modem Control Register               */
-#define OFFSET_LSR              0x14	/* Line Status Register                 */
-#define OFFSET_MSR              0x18	/* Modem Status Register                */
-#define OFFSET_SCR              0x1C	/* SCR Scratch Register                 */
-#define OFFSET_GCTL             0x24	/* Global Control Register              */
-
 #define UART_GET_CHAR(uart)     bfin_read16(((uart)->port.membase + OFFSET_RBR))
 #define UART_GET_DLL(uart)	bfin_read16(((uart)->port.membase + OFFSET_DLL))
 #define UART_GET_IER(uart)      bfin_read16(((uart)->port.membase + OFFSET_IER))
@@ -92,7 +108,7 @@
 	bfin_write16(uart->port.membase + OFFSET_LSR, -1);
 }
 
-struct bfin_serial_port bfin_serial_ports[NR_PORTS];
+struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
 struct bfin_serial_res {
 	unsigned long	uart_base_addr;
 	int		uart_irq;
diff --git a/include/asm-blackfin/mach-bf537/bfin_sir.h b/include/asm-blackfin/mach-bf537/bfin_sir.h
new file mode 100644
index 0000000..0612d0c
--- /dev/null
+++ b/include/asm-blackfin/mach-bf537/bfin_sir.h
@@ -0,0 +1,133 @@
+/*
+ * Blackfin Infra-red Driver
+ *
+ * Copyright 2006-2008 Analog Devices Inc.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ *
+ */
+
+#include <linux/serial.h>
+#include <asm/dma.h>
+#include <asm/portmux.h>
+
+#define SIR_UART_GET_CHAR(port)   bfin_read16((port)->membase + OFFSET_RBR)
+#define SIR_UART_GET_DLL(port)    bfin_read16((port)->membase + OFFSET_DLL)
+#define SIR_UART_GET_IER(port)    bfin_read16((port)->membase + OFFSET_IER)
+#define SIR_UART_GET_DLH(port)    bfin_read16((port)->membase + OFFSET_DLH)
+#define SIR_UART_GET_IIR(port)    bfin_read16((port)->membase + OFFSET_IIR)
+#define SIR_UART_GET_LCR(port)    bfin_read16((port)->membase + OFFSET_LCR)
+#define SIR_UART_GET_GCTL(port)   bfin_read16((port)->membase + OFFSET_GCTL)
+
+#define SIR_UART_PUT_CHAR(port, v) bfin_write16(((port)->membase + OFFSET_THR), v)
+#define SIR_UART_PUT_DLL(port, v)  bfin_write16(((port)->membase + OFFSET_DLL), v)
+#define SIR_UART_PUT_IER(port, v)  bfin_write16(((port)->membase + OFFSET_IER), v)
+#define SIR_UART_PUT_DLH(port, v)  bfin_write16(((port)->membase + OFFSET_DLH), v)
+#define SIR_UART_PUT_LCR(port, v)  bfin_write16(((port)->membase + OFFSET_LCR), v)
+#define SIR_UART_PUT_GCTL(port, v) bfin_write16(((port)->membase + OFFSET_GCTL), v)
+
+#ifdef CONFIG_SIR_BFIN_DMA
+struct dma_rx_buf {
+	char *buf;
+	int head;
+	int tail;
+	};
+#endif /* CONFIG_SIR_BFIN_DMA */
+
+struct bfin_sir_port {
+	unsigned char __iomem   *membase;
+	unsigned int            irq;
+	unsigned int            lsr;
+	unsigned long           clk;
+	struct net_device       *dev;
+#ifdef CONFIG_SIR_BFIN_DMA
+	int                     tx_done;
+	struct dma_rx_buf       rx_dma_buf;
+	struct timer_list       rx_dma_timer;
+	int                     rx_dma_nrows;
+#endif /* CONFIG_SIR_BFIN_DMA */
+	unsigned int            tx_dma_channel;
+	unsigned int            rx_dma_channel;
+};
+
+struct bfin_sir_port sir_ports[BFIN_UART_NR_PORTS];
+
+struct bfin_sir_port_res {
+	unsigned long   base_addr;
+	int             irq;
+	unsigned int    rx_dma_channel;
+	unsigned int    tx_dma_channel;
+};
+
+struct bfin_sir_port_res bfin_sir_port_resource[] = {
+#ifdef CONFIG_BFIN_SIR0
+	{
+	0xFFC00400,
+	IRQ_UART0_RX,
+	CH_UART0_RX,
+	CH_UART0_TX,
+	},
+#endif
+#ifdef CONFIG_BFIN_SIR1
+	{
+	0xFFC02000,
+	IRQ_UART1_RX,
+	CH_UART1_RX,
+	CH_UART1_TX,
+	},
+#endif
+};
+
+int nr_sirs = ARRAY_SIZE(bfin_sir_port_resource);
+
+struct bfin_sir_self {
+	struct bfin_sir_port    *sir_port;
+	spinlock_t              lock;
+	unsigned int            open;
+	int                     speed;
+	int                     newspeed;
+
+	struct sk_buff          *txskb;
+	struct sk_buff          *rxskb;
+	struct net_device_stats stats;
+	struct device           *dev;
+	struct irlap_cb         *irlap;
+	struct qos_info         qos;
+
+	iobuff_t                tx_buff;
+	iobuff_t                rx_buff;
+
+	struct work_struct      work;
+	int                     mtt;
+};
+
+static inline unsigned int SIR_UART_GET_LSR(struct bfin_sir_port *port)
+{
+	unsigned int lsr = bfin_read16(port->membase + OFFSET_LSR);
+	port->lsr |= (lsr & (BI|FE|PE|OE));
+	return lsr | port->lsr;
+}
+
+static inline void SIR_UART_CLEAR_LSR(struct bfin_sir_port *port)
+{
+	port->lsr = 0;
+	bfin_read16(port->membase + OFFSET_LSR);
+}
+
+#define DRIVER_NAME "bfin_sir"
+
+static void bfin_sir_hw_init(void)
+{
+#ifdef CONFIG_BFIN_SIR0
+	peripheral_request(P_UART0_TX, DRIVER_NAME);
+	peripheral_request(P_UART0_RX, DRIVER_NAME);
+#endif
+
+#ifdef CONFIG_BFIN_SIR1
+	peripheral_request(P_UART1_TX, DRIVER_NAME);
+	peripheral_request(P_UART1_RX, DRIVER_NAME);
+#endif
+	SSYNC();
+}
diff --git a/include/asm-blackfin/mach-bf537/blackfin.h b/include/asm-blackfin/mach-bf537/blackfin.h
index 53fcfa3..cffc786 100644
--- a/include/asm-blackfin/mach-bf537/blackfin.h
+++ b/include/asm-blackfin/mach-bf537/blackfin.h
@@ -82,8 +82,6 @@
 #define STATUS_P1	0x02
 #define STATUS_P0	0x01
 
-/* UART 0*/
-
 /* DMA Channnel */
 #define bfin_read_CH_UART_RX() bfin_read_CH_UART0_RX()
 #define bfin_write_CH_UART_RX(val) bfin_write_CH_UART0_RX(val)
@@ -106,37 +104,52 @@
 /* MMR Registers*/
 #define bfin_read_UART_THR() bfin_read_UART0_THR()
 #define bfin_write_UART_THR(val) bfin_write_UART0_THR(val)
-#define UART_THR UART0_THR
+#define BFIN_UART_THR UART0_THR
 #define bfin_read_UART_RBR() bfin_read_UART0_RBR()
 #define bfin_write_UART_RBR(val) bfin_write_UART0_RBR(val)
-#define UART_RBR UART0_RBR
+#define BFIN_UART_RBR UART0_RBR
 #define bfin_read_UART_DLL() bfin_read_UART0_DLL()
 #define bfin_write_UART_DLL(val) bfin_write_UART0_DLL(val)
-#define UART_DLL UART0_DLL
+#define BFIN_UART_DLL UART0_DLL
 #define bfin_read_UART_IER() bfin_read_UART0_IER()
 #define bfin_write_UART_IER(val) bfin_write_UART0_IER(val)
-#define UART_IER UART0_IER
+#define BFIN_UART_IER UART0_IER
 #define bfin_read_UART_DLH() bfin_read_UART0_DLH()
 #define bfin_write_UART_DLH(val) bfin_write_UART0_DLH(val)
-#define UART_DLH UART0_DLH
+#define BFIN_UART_DLH UART0_DLH
 #define bfin_read_UART_IIR() bfin_read_UART0_IIR()
 #define bfin_write_UART_IIR(val) bfin_write_UART0_IIR(val)
-#define UART_IIR UART0_IIR
+#define BFIN_UART_IIR UART0_IIR
 #define bfin_read_UART_LCR() bfin_read_UART0_LCR()
 #define bfin_write_UART_LCR(val) bfin_write_UART0_LCR(val)
-#define UART_LCR UART0_LCR
+#define BFIN_UART_LCR UART0_LCR
 #define bfin_read_UART_MCR() bfin_read_UART0_MCR()
 #define bfin_write_UART_MCR(val) bfin_write_UART0_MCR(val)
-#define UART_MCR UART0_MCR
+#define BFIN_UART_MCR UART0_MCR
 #define bfin_read_UART_LSR() bfin_read_UART0_LSR()
 #define bfin_write_UART_LSR(val) bfin_write_UART0_LSR(val)
-#define UART_LSR UART0_LSR
+#define BFIN_UART_LSR UART0_LSR
 #define bfin_read_UART_SCR() bfin_read_UART0_SCR()
 #define bfin_write_UART_SCR(val) bfin_write_UART0_SCR(val)
-#define UART_SCR  UART0_SCR
+#define BFIN_UART_SCR  UART0_SCR
 #define bfin_read_UART_GCTL() bfin_read_UART0_GCTL()
 #define bfin_write_UART_GCTL(val) bfin_write_UART0_GCTL(val)
-#define UART_GCTL UART0_GCTL
+#define BFIN_UART_GCTL UART0_GCTL
+
+#define BFIN_UART_NR_PORTS	2
+
+#define OFFSET_THR              0x00	/* Transmit Holding register            */
+#define OFFSET_RBR              0x00	/* Receive Buffer register              */
+#define OFFSET_DLL              0x00	/* Divisor Latch (Low-Byte)             */
+#define OFFSET_IER              0x04	/* Interrupt Enable Register            */
+#define OFFSET_DLH              0x04	/* Divisor Latch (High-Byte)            */
+#define OFFSET_IIR              0x08	/* Interrupt Identification Register    */
+#define OFFSET_LCR              0x0C	/* Line Control Register                */
+#define OFFSET_MCR              0x10	/* Modem Control Register               */
+#define OFFSET_LSR              0x14	/* Line Status Register                 */
+#define OFFSET_MSR              0x18	/* Modem Status Register                */
+#define OFFSET_SCR              0x1C	/* SCR Scratch Register                 */
+#define OFFSET_GCTL             0x24	/* Global Control Register              */
 
 /* DPMC*/
 #define bfin_read_STOPCK_OFF() bfin_read_STOPCK()
diff --git a/include/asm-blackfin/mach-bf537/cdefBF534.h b/include/asm-blackfin/mach-bf537/cdefBF534.h
index 78227bc..82de526 100644
--- a/include/asm-blackfin/mach-bf537/cdefBF534.h
+++ b/include/asm-blackfin/mach-bf537/cdefBF534.h
@@ -44,7 +44,27 @@
 
 /* Clock and System Control	(0xFFC00000 - 0xFFC000FF)								*/
 #define bfin_read_PLL_CTL()                  bfin_read16(PLL_CTL)
-#define bfin_write_PLL_CTL(val)              bfin_write16(PLL_CTL,val)
+/* Writing to PLL_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_PLL_CTL(unsigned int val)
+{
+	unsigned long flags, iwr;
+
+	if (val == bfin_read_PLL_CTL())
+		return;
+
+	local_irq_save(flags);
+	/* Enable the PLL Wakeup bit in SIC IWR */
+	iwr = bfin_read32(SIC_IWR);
+	/* Only allow PPL Wakeup) */
+	bfin_write32(SIC_IWR, IWR_ENABLE(0));
+
+	bfin_write16(PLL_CTL, val);
+	SSYNC();
+	asm("IDLE;");
+
+	bfin_write32(SIC_IWR, iwr);
+	local_irq_restore(flags);
+}
 #define bfin_read_PLL_DIV()                  bfin_read16(PLL_DIV)
 #define bfin_write_PLL_DIV(val)              bfin_write16(PLL_DIV,val)
 #define bfin_read_VR_CTL()                   bfin_read16(VR_CTL)
@@ -53,6 +73,10 @@
 {
 	unsigned long flags, iwr;
 
+	if (val == bfin_read_VR_CTL())
+		return;
+
+	local_irq_save(flags);
 	/* Enable the PLL Wakeup bit in SIC IWR */
 	iwr = bfin_read32(SIC_IWR);
 	/* Only allow PPL Wakeup) */
@@ -60,11 +84,10 @@
 
 	bfin_write16(VR_CTL, val);
 	SSYNC();
-
-	local_irq_save(flags);
 	asm("IDLE;");
-	local_irq_restore(flags);
+
 	bfin_write32(SIC_IWR, iwr);
+	local_irq_restore(flags);
 }
 #define bfin_read_PLL_STAT()                 bfin_read16(PLL_STAT)
 #define bfin_write_PLL_STAT(val)             bfin_write16(PLL_STAT,val)
@@ -858,39 +881,7 @@
 #define bfin_read_PPI_FRAME()                bfin_read16(PPI_FRAME)
 #define bfin_write_PPI_FRAME(val)            bfin_write16(PPI_FRAME,val)
 
-/* Two-Wire Interface		(0xFFC01400 - 0xFFC014FF)								*/
-#define bfin_read_TWI_CLKDIV()               bfin_read16(TWI_CLKDIV)
-#define bfin_write_TWI_CLKDIV(val)           bfin_write16(TWI_CLKDIV,val)
-#define bfin_read_TWI_CONTROL()              bfin_read16(TWI_CONTROL)
-#define bfin_write_TWI_CONTROL(val)          bfin_write16(TWI_CONTROL,val)
-#define bfin_read_TWI_SLAVE_CTL()            bfin_read16(TWI_SLAVE_CTL)
-#define bfin_write_TWI_SLAVE_CTL(val)        bfin_write16(TWI_SLAVE_CTL,val)
-#define bfin_read_TWI_SLAVE_STAT()           bfin_read16(TWI_SLAVE_STAT)
-#define bfin_write_TWI_SLAVE_STAT(val)       bfin_write16(TWI_SLAVE_STAT,val)
-#define bfin_read_TWI_SLAVE_ADDR()           bfin_read16(TWI_SLAVE_ADDR)
-#define bfin_write_TWI_SLAVE_ADDR(val)       bfin_write16(TWI_SLAVE_ADDR,val)
-#define bfin_read_TWI_MASTER_CTL()           bfin_read16(TWI_MASTER_CTL)
-#define bfin_write_TWI_MASTER_CTL(val)       bfin_write16(TWI_MASTER_CTL,val)
-#define bfin_read_TWI_MASTER_STAT()          bfin_read16(TWI_MASTER_STAT)
-#define bfin_write_TWI_MASTER_STAT(val)      bfin_write16(TWI_MASTER_STAT,val)
-#define bfin_read_TWI_MASTER_ADDR()          bfin_read16(TWI_MASTER_ADDR)
-#define bfin_write_TWI_MASTER_ADDR(val)      bfin_write16(TWI_MASTER_ADDR,val)
-#define bfin_read_TWI_INT_STAT()             bfin_read16(TWI_INT_STAT)
-#define bfin_write_TWI_INT_STAT(val)         bfin_write16(TWI_INT_STAT,val)
-#define bfin_read_TWI_INT_MASK()             bfin_read16(TWI_INT_MASK)
-#define bfin_write_TWI_INT_MASK(val)         bfin_write16(TWI_INT_MASK,val)
-#define bfin_read_TWI_FIFO_CTL()             bfin_read16(TWI_FIFO_CTL)
-#define bfin_write_TWI_FIFO_CTL(val)         bfin_write16(TWI_FIFO_CTL,val)
-#define bfin_read_TWI_FIFO_STAT()            bfin_read16(TWI_FIFO_STAT)
-#define bfin_write_TWI_FIFO_STAT(val)        bfin_write16(TWI_FIFO_STAT,val)
-#define bfin_read_TWI_XMT_DATA8()            bfin_read16(TWI_XMT_DATA8)
-#define bfin_write_TWI_XMT_DATA8(val)        bfin_write16(TWI_XMT_DATA8,val)
-#define bfin_read_TWI_XMT_DATA16()           bfin_read16(TWI_XMT_DATA16)
-#define bfin_write_TWI_XMT_DATA16(val)       bfin_write16(TWI_XMT_DATA16,val)
-#define bfin_read_TWI_RCV_DATA8()            bfin_read16(TWI_RCV_DATA8)
-#define bfin_write_TWI_RCV_DATA8(val)        bfin_write16(TWI_RCV_DATA8,val)
-#define bfin_read_TWI_RCV_DATA16()           bfin_read16(TWI_RCV_DATA16)
-#define bfin_write_TWI_RCV_DATA16(val)       bfin_write16(TWI_RCV_DATA16,val)
+/* Two-Wire Interface (0xFFC01400 - 0xFFC014FF) */
 
 /* General Purpose I/O Port G (0xFFC01500 - 0xFFC015FF)								*/
 #define bfin_read_PORTGIO()                  bfin_read16(PORTGIO)
diff --git a/include/asm-blackfin/mach-bf537/dma.h b/include/asm-blackfin/mach-bf537/dma.h
index 0219919..7a96404 100644
--- a/include/asm-blackfin/mach-bf537/dma.h
+++ b/include/asm-blackfin/mach-bf537/dma.h
@@ -52,7 +52,4 @@
 #define CH_MEM_STREAM1_DEST	14	 /* TX */
 #define CH_MEM_STREAM1_SRC 	15	 /* RX */
 
-extern int channel2irq(unsigned int channel);
-extern struct dma_register *base_addr[];
-
 #endif
diff --git a/include/asm-blackfin/mach-bf548/anomaly.h b/include/asm-blackfin/mach-bf548/anomaly.h
index 850dc12..49d3ceb 100644
--- a/include/asm-blackfin/mach-bf548/anomaly.h
+++ b/include/asm-blackfin/mach-bf548/anomaly.h
@@ -93,5 +93,6 @@
 #define ANOMALY_05000273 (0)
 #define ANOMALY_05000311 (0)
 #define ANOMALY_05000323 (0)
+#define ANOMALY_05000363 (0)
 
 #endif
diff --git a/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h
index 7e6339f..6547027 100644
--- a/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h
+++ b/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h
@@ -1,22 +1,38 @@
+/*
+ * file:        include/asm-blackfin/mach-bf548/bfin_serial_5xx.h
+ * based on:
+ * author:
+ *
+ * created:
+ * description:
+ *	blackfin serial driver head file
+ * rev:
+ *
+ * modified:
+ *
+ *
+ * bugs:         enter bugs at http://blackfin.uclinux.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, 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,
+ * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ */
+
 #include <linux/serial.h>
 #include <asm/dma.h>
 #include <asm/portmux.h>
 
-#define NR_PORTS		4
-
-#define OFFSET_DLL              0x00	/* Divisor Latch (Low-Byte)             */
-#define OFFSET_DLH              0x04	/* Divisor Latch (High-Byte)            */
-#define OFFSET_GCTL             0x08	/* Global Control Register              */
-#define OFFSET_LCR              0x0C	/* Line Control Register                */
-#define OFFSET_MCR              0x10	/* Modem Control Register               */
-#define OFFSET_LSR              0x14	/* Line Status Register                 */
-#define OFFSET_MSR              0x18	/* Modem Status Register                */
-#define OFFSET_SCR              0x1C	/* SCR Scratch Register                 */
-#define OFFSET_IER_SET          0x20	/* Set Interrupt Enable Register        */
-#define OFFSET_IER_CLEAR        0x24	/* Clear Interrupt Enable Register      */
-#define OFFSET_THR              0x28	/* Transmit Holding register            */
-#define OFFSET_RBR              0x2C	/* Receive Buffer register              */
-
 #define UART_GET_CHAR(uart)     bfin_read16(((uart)->port.membase + OFFSET_RBR))
 #define UART_GET_DLL(uart)	bfin_read16(((uart)->port.membase + OFFSET_DLL))
 #define UART_GET_DLH(uart)	bfin_read16(((uart)->port.membase + OFFSET_DLH))
@@ -80,7 +96,7 @@
 #endif
 };
 
-struct bfin_serial_port bfin_serial_ports[NR_PORTS];
+struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
 struct bfin_serial_res {
 	unsigned long	uart_base_addr;
 	int		uart_irq;
diff --git a/include/asm-blackfin/mach-bf548/bfin_sir.h b/include/asm-blackfin/mach-bf548/bfin_sir.h
new file mode 100644
index 0000000..5e94271
--- /dev/null
+++ b/include/asm-blackfin/mach-bf548/bfin_sir.h
@@ -0,0 +1,149 @@
+/*
+ * Blackfin Infra-red Driver
+ *
+ * Copyright 2006-2008 Analog Devices Inc.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ *
+ */
+
+#include <linux/serial.h>
+#include <asm/dma.h>
+#include <asm/portmux.h>
+
+#define SIR_UART_GET_CHAR(port)   bfin_read16((port)->membase + OFFSET_RBR)
+#define SIR_UART_GET_DLL(port)    bfin_read16((port)->membase + OFFSET_DLL)
+#define SIR_UART_GET_IER(port)    bfin_read16((port)->membase + OFFSET_IER_SET)
+#define SIR_UART_GET_DLH(port)    bfin_read16((port)->membase + OFFSET_DLH)
+#define SIR_UART_GET_LCR(port)    bfin_read16((port)->membase + OFFSET_LCR)
+#define SIR_UART_GET_LSR(port)    bfin_read16((port)->membase + OFFSET_LSR)
+#define SIR_UART_GET_GCTL(port)   bfin_read16((port)->membase + OFFSET_GCTL)
+
+#define SIR_UART_PUT_CHAR(port, v) bfin_write16(((port)->membase + OFFSET_THR), v)
+#define SIR_UART_PUT_DLL(port, v)  bfin_write16(((port)->membase + OFFSET_DLL), v)
+#define SIR_UART_SET_IER(port, v)  bfin_write16(((port)->membase + OFFSET_IER_SET), v)
+#define SIR_UART_CLEAR_IER(port, v)  bfin_write16(((port)->membase + OFFSET_IER_CLEAR), v)
+#define SIR_UART_PUT_DLH(port, v)  bfin_write16(((port)->membase + OFFSET_DLH), v)
+#define SIR_UART_PUT_LSR(port, v)  bfin_write16(((port)->membase + OFFSET_LSR), v)
+#define SIR_UART_PUT_LCR(port, v)  bfin_write16(((port)->membase + OFFSET_LCR), v)
+#define SIR_UART_CLEAR_LSR(port)  bfin_write16(((port)->membase + OFFSET_LSR), -1)
+#define SIR_UART_PUT_GCTL(port, v) bfin_write16(((port)->membase + OFFSET_GCTL), v)
+
+#ifdef CONFIG_SIR_BFIN_DMA
+struct dma_rx_buf {
+	char *buf;
+	int head;
+	int tail;
+	};
+#endif /* CONFIG_SIR_BFIN_DMA */
+
+struct bfin_sir_port {
+	unsigned char __iomem   *membase;
+	unsigned int            irq;
+	unsigned int            lsr;
+	unsigned long           clk;
+	struct net_device       *dev;
+#ifdef CONFIG_SIR_BFIN_DMA
+	int                     tx_done;
+	struct dma_rx_buf       rx_dma_buf;
+	struct timer_list       rx_dma_timer;
+	int                     rx_dma_nrows;
+#endif /* CONFIG_SIR_BFIN_DMA */
+	unsigned int            tx_dma_channel;
+	unsigned int            rx_dma_channel;
+};
+
+struct bfin_sir_port sir_ports[BFIN_UART_NR_PORTS];
+
+struct bfin_sir_port_res {
+	unsigned long   base_addr;
+	int             irq;
+	unsigned int    rx_dma_channel;
+	unsigned int    tx_dma_channel;
+};
+
+struct bfin_sir_port_res bfin_sir_port_resource[] = {
+#ifdef CONFIG_BFIN_SIR0
+	{
+	0xFFC00400,
+	IRQ_UART0_RX,
+	CH_UART0_RX,
+	CH_UART0_TX,
+	},
+#endif
+#ifdef CONFIG_BFIN_SIR1
+	{
+	0xFFC02000,
+	IRQ_UART1_RX,
+	CH_UART1_RX,
+	CH_UART1_TX,
+	},
+#endif
+#ifdef CONFIG_BFIN_SIR2
+	{
+	0xFFC02100,
+	IRQ_UART2_RX,
+	CH_UART2_RX,
+	CH_UART2_TX,
+	},
+#endif
+#ifdef CONFIG_BFIN_SIR3
+	{
+	0xFFC03100,
+	IRQ_UART3_RX,
+	CH_UART3_RX,
+	CH_UART3_TX,
+	},
+#endif
+};
+
+int nr_sirs = ARRAY_SIZE(bfin_sir_port_resource);
+
+struct bfin_sir_self {
+	struct bfin_sir_port    *sir_port;
+	spinlock_t              lock;
+	unsigned int            open;
+	int                     speed;
+	int                     newspeed;
+
+	struct sk_buff          *txskb;
+	struct sk_buff          *rxskb;
+	struct net_device_stats stats;
+	struct device           *dev;
+	struct irlap_cb         *irlap;
+	struct qos_info         qos;
+
+	iobuff_t                tx_buff;
+	iobuff_t                rx_buff;
+
+	struct work_struct      work;
+	int                     mtt;
+};
+
+#define DRIVER_NAME "bfin_sir"
+
+static void bfin_sir_hw_init(void)
+{
+#ifdef CONFIG_BFIN_SIR0
+	peripheral_request(P_UART0_TX, DRIVER_NAME);
+	peripheral_request(P_UART0_RX, DRIVER_NAME);
+#endif
+
+#ifdef CONFIG_BFIN_SIR1
+	peripheral_request(P_UART1_TX, DRIVER_NAME);
+	peripheral_request(P_UART1_RX, DRIVER_NAME);
+#endif
+
+#ifdef CONFIG_BFIN_SIR2
+	peripheral_request(P_UART2_TX, DRIVER_NAME);
+	peripheral_request(P_UART2_RX, DRIVER_NAME);
+#endif
+
+#ifdef CONFIG_BFIN_SIR3
+	peripheral_request(P_UART3_TX, DRIVER_NAME);
+	peripheral_request(P_UART3_RX, DRIVER_NAME);
+#endif
+	SSYNC();
+}
diff --git a/include/asm-blackfin/mach-bf548/blackfin.h b/include/asm-blackfin/mach-bf548/blackfin.h
index 3bd67da..d6ee74a 100644
--- a/include/asm-blackfin/mach-bf548/blackfin.h
+++ b/include/asm-blackfin/mach-bf548/blackfin.h
@@ -153,17 +153,33 @@
 #define bfin_write_UART_SCR(val)	bfin_write_UART1_SCR(val)
 #define bfin_read_UART_GCTL()		bfin_read_UART1_GCTL()
 #define bfin_write_UART_GCTL(val)	bfin_write_UART1_GCTL(val)
-#define UART_THR			UART1_THR
-#define UART_RBR			UART1_RBR
-#define UART_DLL			UART1_DLL
-#define UART_IER			UART1_IER
-#define UART_DLH			UART1_DLH
-#define UART_IIR			UART1_IIR
-#define UART_LCR			UART1_LCR
-#define UART_MCR			UART1_MCR
-#define UART_LSR			UART1_LSR
-#define UART_SCR			UART1_SCR
-#define UART_GCTL			UART1_GCTL
+
+#define BFIN_UART_THR			UART1_THR
+#define BFIN_UART_RBR			UART1_RBR
+#define BFIN_UART_DLL			UART1_DLL
+#define BFIN_UART_IER			UART1_IER
+#define BFIN_UART_DLH			UART1_DLH
+#define BFIN_UART_IIR			UART1_IIR
+#define BFIN_UART_LCR			UART1_LCR
+#define BFIN_UART_MCR			UART1_MCR
+#define BFIN_UART_LSR			UART1_LSR
+#define BFIN_UART_SCR			UART1_SCR
+#define BFIN_UART_GCTL			UART1_GCTL
+
+#define BFIN_UART_NR_PORTS	4
+
+#define OFFSET_DLL              0x00	/* Divisor Latch (Low-Byte)             */
+#define OFFSET_DLH              0x04	/* Divisor Latch (High-Byte)            */
+#define OFFSET_GCTL             0x08	/* Global Control Register              */
+#define OFFSET_LCR              0x0C	/* Line Control Register                */
+#define OFFSET_MCR              0x10	/* Modem Control Register               */
+#define OFFSET_LSR              0x14	/* Line Status Register                 */
+#define OFFSET_MSR              0x18	/* Modem Status Register                */
+#define OFFSET_SCR              0x1C	/* SCR Scratch Register                 */
+#define OFFSET_IER_SET          0x20	/* Set Interrupt Enable Register        */
+#define OFFSET_IER_CLEAR        0x24	/* Clear Interrupt Enable Register      */
+#define OFFSET_THR              0x28	/* Transmit Holding register            */
+#define OFFSET_RBR              0x2C	/* Receive Buffer register              */
 
 /* PLL_DIV Masks */
 #define CCLK_DIV1 CSEL_DIV1	/* CCLK = VCO / 1 */
diff --git a/include/asm-blackfin/mach-bf548/cdefBF542.h b/include/asm-blackfin/mach-bf548/cdefBF542.h
index 308b33a..60b9f77 100644
--- a/include/asm-blackfin/mach-bf548/cdefBF542.h
+++ b/include/asm-blackfin/mach-bf548/cdefBF542.h
@@ -123,12 +123,12 @@
 #define bfin_write_SDH_DATA_LGTH(val)	bfin_write16(SDH_DATA_LGTH, val)
 #define bfin_read_SDH_DATA_CTL()	bfin_read16(SDH_DATA_CTL)
 #define bfin_write_SDH_DATA_CTL(val)	bfin_write16(SDH_DATA_CTL, val)
-#define bfin_read_SDH_DATA_CNT()	fin_read16(SDH_DATA_CNT)
+#define bfin_read_SDH_DATA_CNT()	bfin_read16(SDH_DATA_CNT)
 #define bfin_write_SDH_DATA_CNT(val)	bfin_write16(SDH_DATA_CNT, val)
 #define bfin_read_SDH_STATUS()		bfin_read32(SDH_STATUS)
 #define bfin_write_SDH_STATUS(val)	bfin_write32(SDH_STATUS, val)
-#define bfin_read_SDH_STATUS_CLR()	fin_read16(SDH_STATUS_CLR)
-#define bfin_write_SDH_STATUS_CLR(val)	fin_write16(SDH_STATUS_CLR, val)
+#define bfin_read_SDH_STATUS_CLR()	bfin_read16(SDH_STATUS_CLR)
+#define bfin_write_SDH_STATUS_CLR(val)	bfin_write16(SDH_STATUS_CLR, val)
 #define bfin_read_SDH_MASK0()		bfin_read32(SDH_MASK0)
 #define bfin_write_SDH_MASK0(val)	bfin_write32(SDH_MASK0, val)
 #define bfin_read_SDH_MASK1()		bfin_read32(SDH_MASK1)
@@ -184,8 +184,8 @@
 #define bfin_write_USB_FRAME(val)	bfin_write16(USB_FRAME, val)
 #define bfin_read_USB_INDEX()		bfin_read16(USB_INDEX)
 #define bfin_write_USB_INDEX(val)	bfin_write16(USB_INDEX, val)
-#define bfin_read_USB_TESTMODE()	fin_read16(USB_TESTMODE)
-#define bfin_write_USB_TESTMODE(val)	fin_write16(USB_TESTMODE, val)
+#define bfin_read_USB_TESTMODE()	bfin_read16(USB_TESTMODE)
+#define bfin_write_USB_TESTMODE(val)	bfin_write16(USB_TESTMODE, val)
 #define bfin_read_USB_GLOBINTR()	bfin_read16(USB_GLOBINTR)
 #define bfin_write_USB_GLOBINTR(val)	bfin_write16(USB_GLOBINTR, val)
 #define bfin_read_USB_GLOBAL_CTL()	bfin_read16(USB_GLOBAL_CTL)
@@ -244,7 +244,7 @@
 #define bfin_read_USB_OTG_DEV_CTL()		bfin_read16(USB_OTG_DEV_CTL)
 #define bfin_write_USB_OTG_DEV_CTL(val)		bfin_write16(USB_OTG_DEV_CTL, val)
 #define bfin_read_USB_OTG_VBUS_IRQ()		bfin_read16(USB_OTG_VBUS_IRQ)
-#define bfin_write_USB_OTG_VBUS_IRQ(val)	fin_write16(USB_OTG_VBUS_IRQ, val)
+#define bfin_write_USB_OTG_VBUS_IRQ(val)	bfin_write16(USB_OTG_VBUS_IRQ, val)
 #define bfin_read_USB_OTG_VBUS_MASK()		bfin_read16(USB_OTG_VBUS_MASK)
 #define bfin_write_USB_OTG_VBUS_MASK(val)	bfin_write16(USB_OTG_VBUS_MASK, val)
 
diff --git a/include/asm-blackfin/mach-bf548/cdefBF544.h b/include/asm-blackfin/mach-bf548/cdefBF544.h
index 7a2d177..ea9b4ab 100644
--- a/include/asm-blackfin/mach-bf548/cdefBF544.h
+++ b/include/asm-blackfin/mach-bf548/cdefBF544.h
@@ -113,39 +113,6 @@
 
 /* Two Wire Interface Registers (TWI1) */
 
-#define bfin_read_TWI1_CLKDIV()			bfin_read16(TWI1_CLKDIV)
-#define bfin_write_TWI1_CLKDIV(val)		bfin_write16(TWI1_CLKDIV, val)
-#define bfin_read_TWI1_CONTROL()		bfin_read16(TWI1_CONTROL)
-#define bfin_write_TWI1_CONTROL(val)		bfin_write16(TWI1_CONTROL, val)
-#define bfin_read_TWI1_SLAVE_CTRL()		bfin_read16(TWI1_SLAVE_CTRL)
-#define bfin_write_TWI1_SLAVE_CTRL(val)		bfin_write16(TWI1_SLAVE_CTRL, val)
-#define bfin_read_TWI1_SLAVE_STAT()		bfin_read16(TWI1_SLAVE_STAT)
-#define bfin_write_TWI1_SLAVE_STAT(val)		bfin_write16(TWI1_SLAVE_STAT, val)
-#define bfin_read_TWI1_SLAVE_ADDR()		bfin_read16(TWI1_SLAVE_ADDR)
-#define bfin_write_TWI1_SLAVE_ADDR(val)		bfin_write16(TWI1_SLAVE_ADDR, val)
-#define bfin_read_TWI1_MASTER_CTRL()		bfin_read16(TWI1_MASTER_CTRL)
-#define bfin_write_TWI1_MASTER_CTRL(val)	bfin_write16(TWI1_MASTER_CTRL, val)
-#define bfin_read_TWI1_MASTER_STAT()		bfin_read16(TWI1_MASTER_STAT)
-#define bfin_write_TWI1_MASTER_STAT(val)	bfin_write16(TWI1_MASTER_STAT, val)
-#define bfin_read_TWI1_MASTER_ADDR()		bfin_read16(TWI1_MASTER_ADDR)
-#define bfin_write_TWI1_MASTER_ADDR(val)	bfin_write16(TWI1_MASTER_ADDR, val)
-#define bfin_read_TWI1_INT_STAT()		bfin_read16(TWI1_INT_STAT)
-#define bfin_write_TWI1_INT_STAT(val)		bfin_write16(TWI1_INT_STAT, val)
-#define bfin_read_TWI1_INT_MASK()		bfin_read16(TWI1_INT_MASK)
-#define bfin_write_TWI1_INT_MASK(val)		bfin_write16(TWI1_INT_MASK, val)
-#define bfin_read_TWI1_FIFO_CTRL()		bfin_read16(TWI1_FIFO_CTRL)
-#define bfin_write_TWI1_FIFO_CTRL(val)		bfin_write16(TWI1_FIFO_CTRL, val)
-#define bfin_read_TWI1_FIFO_STAT()		bfin_read16(TWI1_FIFO_STAT)
-#define bfin_write_TWI1_FIFO_STAT(val)		bfin_write16(TWI1_FIFO_STAT, val)
-#define bfin_read_TWI1_XMT_DATA8()		bfin_read16(TWI1_XMT_DATA8)
-#define bfin_write_TWI1_XMT_DATA8(val)		bfin_write16(TWI1_XMT_DATA8, val)
-#define bfin_read_TWI1_XMT_DATA16()		bfin_read16(TWI1_XMT_DATA16)
-#define bfin_write_TWI1_XMT_DATA16(val)		bfin_write16(TWI1_XMT_DATA16, val)
-#define bfin_read_TWI1_RCV_DATA8()		bfin_read16(TWI1_RCV_DATA8)
-#define bfin_write_TWI1_RCV_DATA8(val)		bfin_write16(TWI1_RCV_DATA8, val)
-#define bfin_read_TWI1_RCV_DATA16()		bfin_read16(TWI1_RCV_DATA16)
-#define bfin_write_TWI1_RCV_DATA16(val)		bfin_write16(TWI1_RCV_DATA16, val)
-
 /* CAN Controller 1 Config 1 Registers */
 
 #define bfin_read_CAN1_MC1()		bfin_read16(CAN1_MC1)
diff --git a/include/asm-blackfin/mach-bf548/cdefBF547.h b/include/asm-blackfin/mach-bf548/cdefBF547.h
index d0a200b..ba71627 100644
--- a/include/asm-blackfin/mach-bf548/cdefBF547.h
+++ b/include/asm-blackfin/mach-bf548/cdefBF547.h
@@ -185,39 +185,6 @@
 
 /* Two Wire Interface Registers (TWI1) */
 
-#define bfin_read_TWI1_CLKDIV()			bfin_read16(TWI1_CLKDIV)
-#define bfin_write_TWI1_CLKDIV(val)		bfin_write16(TWI1_CLKDIV, val)
-#define bfin_read_TWI1_CONTROL()		bfin_read16(TWI1_CONTROL)
-#define bfin_write_TWI1_CONTROL(val)		bfin_write16(TWI1_CONTROL, val)
-#define bfin_read_TWI1_SLAVE_CTRL()		bfin_read16(TWI1_SLAVE_CTRL)
-#define bfin_write_TWI1_SLAVE_CTRL(val)		bfin_write16(TWI1_SLAVE_CTRL, val)
-#define bfin_read_TWI1_SLAVE_STAT()		bfin_read16(TWI1_SLAVE_STAT)
-#define bfin_write_TWI1_SLAVE_STAT(val)		bfin_write16(TWI1_SLAVE_STAT, val)
-#define bfin_read_TWI1_SLAVE_ADDR()		bfin_read16(TWI1_SLAVE_ADDR)
-#define bfin_write_TWI1_SLAVE_ADDR(val)		bfin_write16(TWI1_SLAVE_ADDR, val)
-#define bfin_read_TWI1_MASTER_CTRL()		bfin_read16(TWI1_MASTER_CTRL)
-#define bfin_write_TWI1_MASTER_CTRL(val)	bfin_write16(TWI1_MASTER_CTRL, val)
-#define bfin_read_TWI1_MASTER_STAT()		bfin_read16(TWI1_MASTER_STAT)
-#define bfin_write_TWI1_MASTER_STAT(val)	bfin_write16(TWI1_MASTER_STAT, val)
-#define bfin_read_TWI1_MASTER_ADDR()		bfin_read16(TWI1_MASTER_ADDR)
-#define bfin_write_TWI1_MASTER_ADDR(val)	bfin_write16(TWI1_MASTER_ADDR, val)
-#define bfin_read_TWI1_INT_STAT()		bfin_read16(TWI1_INT_STAT)
-#define bfin_write_TWI1_INT_STAT(val)		bfin_write16(TWI1_INT_STAT, val)
-#define bfin_read_TWI1_INT_MASK()		bfin_read16(TWI1_INT_MASK)
-#define bfin_write_TWI1_INT_MASK(val)		bfin_write16(TWI1_INT_MASK, val)
-#define bfin_read_TWI1_FIFO_CTRL()		bfin_read16(TWI1_FIFO_CTRL)
-#define bfin_write_TWI1_FIFO_CTRL(val)		bfin_write16(TWI1_FIFO_CTRL, val)
-#define bfin_read_TWI1_FIFO_STAT()		bfin_read16(TWI1_FIFO_STAT)
-#define bfin_write_TWI1_FIFO_STAT(val)		bfin_write16(TWI1_FIFO_STAT, val)
-#define bfin_read_TWI1_XMT_DATA8()		bfin_read16(TWI1_XMT_DATA8)
-#define bfin_write_TWI1_XMT_DATA8(val)		bfin_write16(TWI1_XMT_DATA8, val)
-#define bfin_read_TWI1_XMT_DATA16()		bfin_read16(TWI1_XMT_DATA16)
-#define bfin_write_TWI1_XMT_DATA16(val)		bfin_write16(TWI1_XMT_DATA16, val)
-#define bfin_read_TWI1_RCV_DATA8()		bfin_read16(TWI1_RCV_DATA8)
-#define bfin_write_TWI1_RCV_DATA8(val)		bfin_write16(TWI1_RCV_DATA8, val)
-#define bfin_read_TWI1_RCV_DATA16()		bfin_read16(TWI1_RCV_DATA16)
-#define bfin_write_TWI1_RCV_DATA16(val)		bfin_write16(TWI1_RCV_DATA16, val)
-
 /* SPI2  Registers */
 
 #define bfin_read_SPI2_CTL()		bfin_read16(SPI2_CTL)
diff --git a/include/asm-blackfin/mach-bf548/cdefBF548.h b/include/asm-blackfin/mach-bf548/cdefBF548.h
index 674be02..ae971eb 100644
--- a/include/asm-blackfin/mach-bf548/cdefBF548.h
+++ b/include/asm-blackfin/mach-bf548/cdefBF548.h
@@ -185,39 +185,6 @@
 
 /* Two Wire Interface Registers (TWI1) */
 
-#define bfin_read_TWI1_CLKDIV()			bfin_read16(TWI1_CLKDIV)
-#define bfin_write_TWI1_CLKDIV(val)		bfin_write16(TWI1_CLKDIV, val)
-#define bfin_read_TWI1_CONTROL()		bfin_read16(TWI1_CONTROL)
-#define bfin_write_TWI1_CONTROL(val)		bfin_write16(TWI1_CONTROL, val)
-#define bfin_read_TWI1_SLAVE_CTRL()		bfin_read16(TWI1_SLAVE_CTRL)
-#define bfin_write_TWI1_SLAVE_CTRL(val)		bfin_write16(TWI1_SLAVE_CTRL, val)
-#define bfin_read_TWI1_SLAVE_STAT()		bfin_read16(TWI1_SLAVE_STAT)
-#define bfin_write_TWI1_SLAVE_STAT(val)		bfin_write16(TWI1_SLAVE_STAT, val)
-#define bfin_read_TWI1_SLAVE_ADDR()		bfin_read16(TWI1_SLAVE_ADDR)
-#define bfin_write_TWI1_SLAVE_ADDR(val)		bfin_write16(TWI1_SLAVE_ADDR, val)
-#define bfin_read_TWI1_MASTER_CTRL()		bfin_read16(TWI1_MASTER_CTRL)
-#define bfin_write_TWI1_MASTER_CTRL(val)	bfin_write16(TWI1_MASTER_CTRL, val)
-#define bfin_read_TWI1_MASTER_STAT()		bfin_read16(TWI1_MASTER_STAT)
-#define bfin_write_TWI1_MASTER_STAT(val)	bfin_write16(TWI1_MASTER_STAT, val)
-#define bfin_read_TWI1_MASTER_ADDR()		bfin_read16(TWI1_MASTER_ADDR)
-#define bfin_write_TWI1_MASTER_ADDR(val)	bfin_write16(TWI1_MASTER_ADDR, val)
-#define bfin_read_TWI1_INT_STAT()		bfin_read16(TWI1_INT_STAT)
-#define bfin_write_TWI1_INT_STAT(val)		bfin_write16(TWI1_INT_STAT, val)
-#define bfin_read_TWI1_INT_MASK()		bfin_read16(TWI1_INT_MASK)
-#define bfin_write_TWI1_INT_MASK(val)		bfin_write16(TWI1_INT_MASK, val)
-#define bfin_read_TWI1_FIFO_CTRL()		bfin_read16(TWI1_FIFO_CTRL)
-#define bfin_write_TWI1_FIFO_CTRL(val)		bfin_write16(TWI1_FIFO_CTRL, val)
-#define bfin_read_TWI1_FIFO_STAT()		bfin_read16(TWI1_FIFO_STAT)
-#define bfin_write_TWI1_FIFO_STAT(val)		bfin_write16(TWI1_FIFO_STAT, val)
-#define bfin_read_TWI1_XMT_DATA8()		bfin_read16(TWI1_XMT_DATA8)
-#define bfin_write_TWI1_XMT_DATA8(val)		bfin_write16(TWI1_XMT_DATA8, val)
-#define bfin_read_TWI1_XMT_DATA16()		bfin_read16(TWI1_XMT_DATA16)
-#define bfin_write_TWI1_XMT_DATA16(val)		bfin_write16(TWI1_XMT_DATA16, val)
-#define bfin_read_TWI1_RCV_DATA8()		bfin_read16(TWI1_RCV_DATA8)
-#define bfin_write_TWI1_RCV_DATA8(val)		bfin_write16(TWI1_RCV_DATA8, val)
-#define bfin_read_TWI1_RCV_DATA16()		bfin_read16(TWI1_RCV_DATA16)
-#define bfin_write_TWI1_RCV_DATA16(val)		bfin_write16(TWI1_RCV_DATA16, val)
-
 /* SPI2  Registers */
 
 #define bfin_read_SPI2_CTL()		bfin_read16(SPI2_CTL)
diff --git a/include/asm-blackfin/mach-bf548/cdefBF549.h b/include/asm-blackfin/mach-bf548/cdefBF549.h
index 2ab5b7c..92d07d9 100644
--- a/include/asm-blackfin/mach-bf548/cdefBF549.h
+++ b/include/asm-blackfin/mach-bf548/cdefBF549.h
@@ -185,39 +185,6 @@
 
 /* Two Wire Interface Registers (TWI1) */
 
-#define bfin_read_TWI1_CLKDIV()			bfin_read16(TWI1_CLKDIV)
-#define bfin_write_TWI1_CLKDIV(val)		bfin_write16(TWI1_CLKDIV, val)
-#define bfin_read_TWI1_CONTROL()		bfin_read16(TWI1_CONTROL)
-#define bfin_write_TWI1_CONTROL(val)		bfin_write16(TWI1_CONTROL, val)
-#define bfin_read_TWI1_SLAVE_CTRL()		bfin_read16(TWI1_SLAVE_CTRL)
-#define bfin_write_TWI1_SLAVE_CTRL(val)		bfin_write16(TWI1_SLAVE_CTRL, val)
-#define bfin_read_TWI1_SLAVE_STAT()		bfin_read16(TWI1_SLAVE_STAT)
-#define bfin_write_TWI1_SLAVE_STAT(val)		bfin_write16(TWI1_SLAVE_STAT, val)
-#define bfin_read_TWI1_SLAVE_ADDR()		bfin_read16(TWI1_SLAVE_ADDR)
-#define bfin_write_TWI1_SLAVE_ADDR(val)		bfin_write16(TWI1_SLAVE_ADDR, val)
-#define bfin_read_TWI1_MASTER_CTRL()		bfin_read16(TWI1_MASTER_CTRL)
-#define bfin_write_TWI1_MASTER_CTRL(val)	bfin_write16(TWI1_MASTER_CTRL, val)
-#define bfin_read_TWI1_MASTER_STAT()		bfin_read16(TWI1_MASTER_STAT)
-#define bfin_write_TWI1_MASTER_STAT(val)	bfin_write16(TWI1_MASTER_STAT, val)
-#define bfin_read_TWI1_MASTER_ADDR()		bfin_read16(TWI1_MASTER_ADDR)
-#define bfin_write_TWI1_MASTER_ADDR(val)	bfin_write16(TWI1_MASTER_ADDR, val)
-#define bfin_read_TWI1_INT_STAT()		bfin_read16(TWI1_INT_STAT)
-#define bfin_write_TWI1_INT_STAT(val)		bfin_write16(TWI1_INT_STAT, val)
-#define bfin_read_TWI1_INT_MASK()		bfin_read16(TWI1_INT_MASK)
-#define bfin_write_TWI1_INT_MASK(val)		bfin_write16(TWI1_INT_MASK, val)
-#define bfin_read_TWI1_FIFO_CTRL()		bfin_read16(TWI1_FIFO_CTRL)
-#define bfin_write_TWI1_FIFO_CTRL(val)		bfin_write16(TWI1_FIFO_CTRL, val)
-#define bfin_read_TWI1_FIFO_STAT()		bfin_read16(TWI1_FIFO_STAT)
-#define bfin_write_TWI1_FIFO_STAT(val)		bfin_write16(TWI1_FIFO_STAT, val)
-#define bfin_read_TWI1_XMT_DATA8()		bfin_read16(TWI1_XMT_DATA8)
-#define bfin_write_TWI1_XMT_DATA8(val)		bfin_write16(TWI1_XMT_DATA8, val)
-#define bfin_read_TWI1_XMT_DATA16()		bfin_read16(TWI1_XMT_DATA16)
-#define bfin_write_TWI1_XMT_DATA16(val)		bfin_write16(TWI1_XMT_DATA16, val)
-#define bfin_read_TWI1_RCV_DATA8()		bfin_read16(TWI1_RCV_DATA8)
-#define bfin_write_TWI1_RCV_DATA8(val)		bfin_write16(TWI1_RCV_DATA8, val)
-#define bfin_read_TWI1_RCV_DATA16()		bfin_read16(TWI1_RCV_DATA16)
-#define bfin_write_TWI1_RCV_DATA16(val)		bfin_write16(TWI1_RCV_DATA16, val)
-
 /* SPI2 Registers */
 
 #define bfin_read_SPI2_CTL()		bfin_read16(SPI2_CTL)
@@ -1773,7 +1740,7 @@
 #define bfin_read_USB_DMA5ADDRHIGH()		bfin_read16(USB_DMA5ADDRHIGH)
 #define bfin_write_USB_DMA5ADDRHIGH(val)		bfin_write16(USB_DMA5ADDRHIGH, val)
 #define bfin_read_USB_DMA5COUNTLOW()		bfin_read16(USB_DMA5COUNTLOW)
-#define bfin_write_USB_DMA5COUNTLOW(val)	fin_write16(USB_DMA5COUNTLOW, val)
+#define bfin_write_USB_DMA5COUNTLOW(val)	bfin_write16(USB_DMA5COUNTLOW, val)
 #define bfin_read_USB_DMA5COUNTHIGH()		bfin_read16(USB_DMA5COUNTHIGH)
 #define bfin_write_USB_DMA5COUNTHIGH(val)	bfin_write16(USB_DMA5COUNTHIGH, val)
 
diff --git a/include/asm-blackfin/mach-bf548/cdefBF54x_base.h b/include/asm-blackfin/mach-bf548/cdefBF54x_base.h
index 19ddcd8..57ac8cb 100644
--- a/include/asm-blackfin/mach-bf548/cdefBF54x_base.h
+++ b/include/asm-blackfin/mach-bf548/cdefBF54x_base.h
@@ -43,7 +43,33 @@
 /* PLL Registers */
 
 #define bfin_read_PLL_CTL()		bfin_read16(PLL_CTL)
-#define bfin_write_PLL_CTL(val)		bfin_write16(PLL_CTL, val)
+/* Writing to PLL_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_PLL_CTL(unsigned int val)
+{
+	unsigned long flags, iwr0, iwr1, iwr2;
+
+	if (val == bfin_read_PLL_CTL())
+		return;
+
+	local_irq_save(flags);
+	/* Enable the PLL Wakeup bit in SIC IWR */
+	iwr0 = bfin_read32(SIC_IWR0);
+	iwr1 = bfin_read32(SIC_IWR1);
+	iwr2 = bfin_read32(SIC_IWR2);
+	/* Only allow PPL Wakeup) */
+	bfin_write32(SIC_IWR0, IWR_ENABLE(0));
+	bfin_write32(SIC_IWR1, 0);
+	bfin_write32(SIC_IWR2, 0);
+
+	bfin_write16(PLL_CTL, val);
+	SSYNC();
+	asm("IDLE;");
+
+	bfin_write32(SIC_IWR0, iwr0);
+	bfin_write32(SIC_IWR1, iwr1);
+	bfin_write32(SIC_IWR2, iwr2);
+	local_irq_restore(flags);
+}
 #define bfin_read_PLL_DIV()		bfin_read16(PLL_DIV)
 #define bfin_write_PLL_DIV(val)		bfin_write16(PLL_DIV, val)
 #define bfin_read_VR_CTL()		bfin_read16(VR_CTL)
@@ -52,6 +78,10 @@
 {
 	unsigned long flags, iwr0, iwr1, iwr2;
 
+	if (val == bfin_read_VR_CTL())
+		return;
+
+	local_irq_save(flags);
 	/* Enable the PLL Wakeup bit in SIC IWR */
 	iwr0 = bfin_read32(SIC_IWR0);
 	iwr1 = bfin_read32(SIC_IWR1);
@@ -63,13 +93,12 @@
 
 	bfin_write16(VR_CTL, val);
 	SSYNC();
-
-	local_irq_save(flags);
 	asm("IDLE;");
-	local_irq_restore(flags);
+
 	bfin_write32(SIC_IWR0, iwr0);
 	bfin_write32(SIC_IWR1, iwr1);
 	bfin_write32(SIC_IWR2, iwr2);
+	local_irq_restore(flags);
 }
 #define bfin_read_PLL_STAT()		bfin_read16(PLL_STAT)
 #define bfin_write_PLL_STAT(val)	bfin_write16(PLL_STAT, val)
@@ -211,39 +240,6 @@
 
 /* Two Wire Interface Registers (TWI0) */
 
-#define bfin_read_TWI0_CLKDIV()			bfin_read16(TWI0_CLKDIV)
-#define bfin_write_TWI0_CLKDIV(val)		bfin_write16(TWI0_CLKDIV, val)
-#define bfin_read_TWI0_CONTROL()		bfin_read16(TWI0_CONTROL)
-#define bfin_write_TWI0_CONTROL(val)		bfin_write16(TWI0_CONTROL, val)
-#define bfin_read_TWI0_SLAVE_CTRL()		bfin_read16(TWI0_SLAVE_CTRL)
-#define bfin_write_TWI0_SLAVE_CTRL(val)		bfin_write16(TWI0_SLAVE_CTRL, val)
-#define bfin_read_TWI0_SLAVE_STAT()		bfin_read16(TWI0_SLAVE_STAT)
-#define bfin_write_TWI0_SLAVE_STAT(val)		bfin_write16(TWI0_SLAVE_STAT, val)
-#define bfin_read_TWI0_SLAVE_ADDR()		bfin_read16(TWI0_SLAVE_ADDR)
-#define bfin_write_TWI0_SLAVE_ADDR(val)		bfin_write16(TWI0_SLAVE_ADDR, val)
-#define bfin_read_TWI0_MASTER_CTRL()		bfin_read16(TWI0_MASTER_CTRL)
-#define bfin_write_TWI0_MASTER_CTRL(val)	bfin_write16(TWI0_MASTER_CTRL, val)
-#define bfin_read_TWI0_MASTER_STAT()		bfin_read16(TWI0_MASTER_STAT)
-#define bfin_write_TWI0_MASTER_STAT(val)	bfin_write16(TWI0_MASTER_STAT, val)
-#define bfin_read_TWI0_MASTER_ADDR()		bfin_read16(TWI0_MASTER_ADDR)
-#define bfin_write_TWI0_MASTER_ADDR(val)	bfin_write16(TWI0_MASTER_ADDR, val)
-#define bfin_read_TWI0_INT_STAT()		bfin_read16(TWI0_INT_STAT)
-#define bfin_write_TWI0_INT_STAT(val)		bfin_write16(TWI0_INT_STAT, val)
-#define bfin_read_TWI0_INT_MASK()		bfin_read16(TWI0_INT_MASK)
-#define bfin_write_TWI0_INT_MASK(val)		bfin_write16(TWI0_INT_MASK, val)
-#define bfin_read_TWI0_FIFO_CTRL()		bfin_read16(TWI0_FIFO_CTRL)
-#define bfin_write_TWI0_FIFO_CTRL(val)		bfin_write16(TWI0_FIFO_CTRL, val)
-#define bfin_read_TWI0_FIFO_STAT()		bfin_read16(TWI0_FIFO_STAT)
-#define bfin_write_TWI0_FIFO_STAT(val)		bfin_write16(TWI0_FIFO_STAT, val)
-#define bfin_read_TWI0_XMT_DATA8()		bfin_read16(TWI0_XMT_DATA8)
-#define bfin_write_TWI0_XMT_DATA8(val)		bfin_write16(TWI0_XMT_DATA8, val)
-#define bfin_read_TWI0_XMT_DATA16()		bfin_read16(TWI0_XMT_DATA16)
-#define bfin_write_TWI0_XMT_DATA16(val)		bfin_write16(TWI0_XMT_DATA16, val)
-#define bfin_read_TWI0_RCV_DATA8()		bfin_read16(TWI0_RCV_DATA8)
-#define bfin_write_TWI0_RCV_DATA8(val)		bfin_write16(TWI0_RCV_DATA8, val)
-#define bfin_read_TWI0_RCV_DATA16()		bfin_read16(TWI0_RCV_DATA16)
-#define bfin_write_TWI0_RCV_DATA16(val)		bfin_write16(TWI0_RCV_DATA16, val)
-
 /* SPORT0 is not defined in the shared file because it is not available on the ADSP-BF542 and ADSP-BF544 bfin_read_()rocessors */
 
 /* SPORT1 Registers */
@@ -323,7 +319,7 @@
 #define bfin_read_EBIU_DDRQUE()		bfin_read32(EBIU_DDRQUE)
 #define bfin_write_EBIU_DDRQUE(val)	bfin_write32(EBIU_DDRQUE, val)
 #define bfin_read_EBIU_ERRADD() 	bfin_read32(EBIU_ERRADD)
-#define bfin_write_EBIU_ERRADD(val) 	bfin_write32(EBIU_ERRADD)
+#define bfin_write_EBIU_ERRADD(val) 	bfin_write32(EBIU_ERRADD, val)
 #define bfin_read_EBIU_ERRMST()		bfin_read16(EBIU_ERRMST)
 #define bfin_write_EBIU_ERRMST(val)	bfin_write16(EBIU_ERRMST, val)
 #define bfin_read_EBIU_RSTCTL()		bfin_read16(EBIU_RSTCTL)
@@ -392,23 +388,23 @@
 /* DMA Channel 0 Registers */
 
 #define bfin_read_DMA0_NEXT_DESC_PTR() 		bfin_read32(DMA0_NEXT_DESC_PTR)
-#define bfin_write_DMA0_NEXT_DESC_PTR(val) 	bfin_write32(DMA0_NEXT_DESC_PTR)
+#define bfin_write_DMA0_NEXT_DESC_PTR(val) 	bfin_write32(DMA0_NEXT_DESC_PTR, val)
 #define bfin_read_DMA0_START_ADDR() 		bfin_read32(DMA0_START_ADDR)
-#define bfin_write_DMA0_START_ADDR(val) 	bfin_write32(DMA0_START_ADDR)
+#define bfin_write_DMA0_START_ADDR(val) 	bfin_write32(DMA0_START_ADDR, val)
 #define bfin_read_DMA0_CONFIG()			bfin_read16(DMA0_CONFIG)
 #define bfin_write_DMA0_CONFIG(val)		bfin_write16(DMA0_CONFIG, val)
 #define bfin_read_DMA0_X_COUNT()		bfin_read16(DMA0_X_COUNT)
 #define bfin_write_DMA0_X_COUNT(val)		bfin_write16(DMA0_X_COUNT, val)
 #define bfin_read_DMA0_X_MODIFY()		bfin_read16(DMA0_X_MODIFY)
-#define bfin_write_DMA0_X_MODIFY(val) 		bfin_write16(DMA0_X_MODIFY)
+#define bfin_write_DMA0_X_MODIFY(val) 		bfin_write16(DMA0_X_MODIFY, val)
 #define bfin_read_DMA0_Y_COUNT()		bfin_read16(DMA0_Y_COUNT)
 #define bfin_write_DMA0_Y_COUNT(val)		bfin_write16(DMA0_Y_COUNT, val)
 #define bfin_read_DMA0_Y_MODIFY()		bfin_read16(DMA0_Y_MODIFY)
-#define bfin_write_DMA0_Y_MODIFY(val) 		bfin_write16(DMA0_Y_MODIFY)
+#define bfin_write_DMA0_Y_MODIFY(val) 		bfin_write16(DMA0_Y_MODIFY, val)
 #define bfin_read_DMA0_CURR_DESC_PTR() 		bfin_read32(DMA0_CURR_DESC_PTR)
-#define bfin_write_DMA0_CURR_DESC_PTR(val) 	bfin_write32(DMA0_CURR_DESC_PTR)
+#define bfin_write_DMA0_CURR_DESC_PTR(val) 	bfin_write32(DMA0_CURR_DESC_PTR, val)
 #define bfin_read_DMA0_CURR_ADDR() 		bfin_read32(DMA0_CURR_ADDR)
-#define bfin_write_DMA0_CURR_ADDR(val) 		bfin_write32(DMA0_CURR_ADDR)
+#define bfin_write_DMA0_CURR_ADDR(val) 		bfin_write32(DMA0_CURR_ADDR, val)
 #define bfin_read_DMA0_IRQ_STATUS()		bfin_read16(DMA0_IRQ_STATUS)
 #define bfin_write_DMA0_IRQ_STATUS(val)		bfin_write16(DMA0_IRQ_STATUS, val)
 #define bfin_read_DMA0_PERIPHERAL_MAP()		bfin_read16(DMA0_PERIPHERAL_MAP)
@@ -421,23 +417,23 @@
 /* DMA Channel 1 Registers */
 
 #define bfin_read_DMA1_NEXT_DESC_PTR() 		bfin_read32(DMA1_NEXT_DESC_PTR)
-#define bfin_write_DMA1_NEXT_DESC_PTR(val) 	bfin_write32(DMA1_NEXT_DESC_PTR)
+#define bfin_write_DMA1_NEXT_DESC_PTR(val) 	bfin_write32(DMA1_NEXT_DESC_PTR, val)
 #define bfin_read_DMA1_START_ADDR() 		bfin_read32(DMA1_START_ADDR)
-#define bfin_write_DMA1_START_ADDR(val) 	bfin_write32(DMA1_START_ADDR)
+#define bfin_write_DMA1_START_ADDR(val) 	bfin_write32(DMA1_START_ADDR, val)
 #define bfin_read_DMA1_CONFIG()			bfin_read16(DMA1_CONFIG)
 #define bfin_write_DMA1_CONFIG(val)		bfin_write16(DMA1_CONFIG, val)
 #define bfin_read_DMA1_X_COUNT()		bfin_read16(DMA1_X_COUNT)
 #define bfin_write_DMA1_X_COUNT(val)		bfin_write16(DMA1_X_COUNT, val)
 #define bfin_read_DMA1_X_MODIFY()		bfin_read16(DMA1_X_MODIFY)
-#define bfin_write_DMA1_X_MODIFY(val) 		bfin_write16(DMA1_X_MODIFY)
+#define bfin_write_DMA1_X_MODIFY(val) 		bfin_write16(DMA1_X_MODIFY, val)
 #define bfin_read_DMA1_Y_COUNT()		bfin_read16(DMA1_Y_COUNT)
 #define bfin_write_DMA1_Y_COUNT(val)		bfin_write16(DMA1_Y_COUNT, val)
 #define bfin_read_DMA1_Y_MODIFY()		bfin_read16(DMA1_Y_MODIFY)
-#define bfin_write_DMA1_Y_MODIFY(val) 		bfin_write16(DMA1_Y_MODIFY)
+#define bfin_write_DMA1_Y_MODIFY(val) 		bfin_write16(DMA1_Y_MODIFY, val)
 #define bfin_read_DMA1_CURR_DESC_PTR() 		bfin_read32(DMA1_CURR_DESC_PTR)
-#define bfin_write_DMA1_CURR_DESC_PTR(val) 	bfin_write32(DMA1_CURR_DESC_PTR)
+#define bfin_write_DMA1_CURR_DESC_PTR(val) 	bfin_write32(DMA1_CURR_DESC_PTR, val)
 #define bfin_read_DMA1_CURR_ADDR() 		bfin_read32(DMA1_CURR_ADDR)
-#define bfin_write_DMA1_CURR_ADDR(val) 		bfin_write32(DMA1_CURR_ADDR)
+#define bfin_write_DMA1_CURR_ADDR(val) 		bfin_write32(DMA1_CURR_ADDR, val)
 #define bfin_read_DMA1_IRQ_STATUS()		bfin_read16(DMA1_IRQ_STATUS)
 #define bfin_write_DMA1_IRQ_STATUS(val)		bfin_write16(DMA1_IRQ_STATUS, val)
 #define bfin_read_DMA1_PERIPHERAL_MAP()		bfin_read16(DMA1_PERIPHERAL_MAP)
@@ -450,23 +446,23 @@
 /* DMA Channel 2 Registers */
 
 #define bfin_read_DMA2_NEXT_DESC_PTR() 		bfin_read32(DMA2_NEXT_DESC_PTR)
-#define bfin_write_DMA2_NEXT_DESC_PTR(val) 	bfin_write32(DMA2_NEXT_DESC_PTR)
+#define bfin_write_DMA2_NEXT_DESC_PTR(val) 	bfin_write32(DMA2_NEXT_DESC_PTR, val)
 #define bfin_read_DMA2_START_ADDR() 		bfin_read32(DMA2_START_ADDR)
-#define bfin_write_DMA2_START_ADDR(val) 	bfin_write32(DMA2_START_ADDR)
+#define bfin_write_DMA2_START_ADDR(val) 	bfin_write32(DMA2_START_ADDR, val)
 #define bfin_read_DMA2_CONFIG()			bfin_read16(DMA2_CONFIG)
 #define bfin_write_DMA2_CONFIG(val)		bfin_write16(DMA2_CONFIG, val)
 #define bfin_read_DMA2_X_COUNT()		bfin_read16(DMA2_X_COUNT)
 #define bfin_write_DMA2_X_COUNT(val)		bfin_write16(DMA2_X_COUNT, val)
 #define bfin_read_DMA2_X_MODIFY()		bfin_read16(DMA2_X_MODIFY)
-#define bfin_write_DMA2_X_MODIFY(val) 		bfin_write16(DMA2_X_MODIFY)
+#define bfin_write_DMA2_X_MODIFY(val) 		bfin_write16(DMA2_X_MODIFY, val)
 #define bfin_read_DMA2_Y_COUNT()		bfin_read16(DMA2_Y_COUNT)
 #define bfin_write_DMA2_Y_COUNT(val)		bfin_write16(DMA2_Y_COUNT, val)
 #define bfin_read_DMA2_Y_MODIFY()		bfin_read16(DMA2_Y_MODIFY)
-#define bfin_write_DMA2_Y_MODIFY(val) 		bfin_write16(DMA2_Y_MODIFY)
+#define bfin_write_DMA2_Y_MODIFY(val) 		bfin_write16(DMA2_Y_MODIFY, val)
 #define bfin_read_DMA2_CURR_DESC_PTR() 		bfin_read32(DMA2_CURR_DESC_PTR)
-#define bfin_write_DMA2_CURR_DESC_PTR(val) 	bfin_write32(DMA2_CURR_DESC_PTR)
+#define bfin_write_DMA2_CURR_DESC_PTR(val) 	bfin_write32(DMA2_CURR_DESC_PTR, val)
 #define bfin_read_DMA2_CURR_ADDR() 		bfin_read32(DMA2_CURR_ADDR)
-#define bfin_write_DMA2_CURR_ADDR(val) 		bfin_write32(DMA2_CURR_ADDR)
+#define bfin_write_DMA2_CURR_ADDR(val) 		bfin_write32(DMA2_CURR_ADDR, val)
 #define bfin_read_DMA2_IRQ_STATUS()		bfin_read16(DMA2_IRQ_STATUS)
 #define bfin_write_DMA2_IRQ_STATUS(val)		bfin_write16(DMA2_IRQ_STATUS, val)
 #define bfin_read_DMA2_PERIPHERAL_MAP()		bfin_read16(DMA2_PERIPHERAL_MAP)
@@ -479,23 +475,23 @@
 /* DMA Channel 3 Registers */
 
 #define bfin_read_DMA3_NEXT_DESC_PTR() 		bfin_read32(DMA3_NEXT_DESC_PTR)
-#define bfin_write_DMA3_NEXT_DESC_PTR(val) 	bfin_write32(DMA3_NEXT_DESC_PTR)
+#define bfin_write_DMA3_NEXT_DESC_PTR(val) 	bfin_write32(DMA3_NEXT_DESC_PTR, val)
 #define bfin_read_DMA3_START_ADDR() 		bfin_read32(DMA3_START_ADDR)
-#define bfin_write_DMA3_START_ADDR(val) 	bfin_write32(DMA3_START_ADDR)
+#define bfin_write_DMA3_START_ADDR(val) 	bfin_write32(DMA3_START_ADDR, val)
 #define bfin_read_DMA3_CONFIG()			bfin_read16(DMA3_CONFIG)
 #define bfin_write_DMA3_CONFIG(val)		bfin_write16(DMA3_CONFIG, val)
 #define bfin_read_DMA3_X_COUNT()		bfin_read16(DMA3_X_COUNT)
 #define bfin_write_DMA3_X_COUNT(val)		bfin_write16(DMA3_X_COUNT, val)
 #define bfin_read_DMA3_X_MODIFY()		bfin_read16(DMA3_X_MODIFY)
-#define bfin_write_DMA3_X_MODIFY(val) 		bfin_write16(DMA3_X_MODIFY)
+#define bfin_write_DMA3_X_MODIFY(val) 		bfin_write16(DMA3_X_MODIFY, val)
 #define bfin_read_DMA3_Y_COUNT()		bfin_read16(DMA3_Y_COUNT)
 #define bfin_write_DMA3_Y_COUNT(val)		bfin_write16(DMA3_Y_COUNT, val)
 #define bfin_read_DMA3_Y_MODIFY()		bfin_read16(DMA3_Y_MODIFY)
-#define bfin_write_DMA3_Y_MODIFY(val) 		bfin_write16(DMA3_Y_MODIFY)
+#define bfin_write_DMA3_Y_MODIFY(val) 		bfin_write16(DMA3_Y_MODIFY, val)
 #define bfin_read_DMA3_CURR_DESC_PTR() 		bfin_read32(DMA3_CURR_DESC_PTR)
-#define bfin_write_DMA3_CURR_DESC_PTR(val) 	bfin_write32(DMA3_CURR_DESC_PTR)
+#define bfin_write_DMA3_CURR_DESC_PTR(val) 	bfin_write32(DMA3_CURR_DESC_PTR, val)
 #define bfin_read_DMA3_CURR_ADDR() 		bfin_read32(DMA3_CURR_ADDR)
-#define bfin_write_DMA3_CURR_ADDR(val) 		bfin_write32(DMA3_CURR_ADDR)
+#define bfin_write_DMA3_CURR_ADDR(val) 		bfin_write32(DMA3_CURR_ADDR, val)
 #define bfin_read_DMA3_IRQ_STATUS()		bfin_read16(DMA3_IRQ_STATUS)
 #define bfin_write_DMA3_IRQ_STATUS(val)		bfin_write16(DMA3_IRQ_STATUS, val)
 #define bfin_read_DMA3_PERIPHERAL_MAP()		bfin_read16(DMA3_PERIPHERAL_MAP)
@@ -508,23 +504,23 @@
 /* DMA Channel 4 Registers */
 
 #define bfin_read_DMA4_NEXT_DESC_PTR() 		bfin_read32(DMA4_NEXT_DESC_PTR)
-#define bfin_write_DMA4_NEXT_DESC_PTR(val) 	bfin_write32(DMA4_NEXT_DESC_PTR)
+#define bfin_write_DMA4_NEXT_DESC_PTR(val) 	bfin_write32(DMA4_NEXT_DESC_PTR, val)
 #define bfin_read_DMA4_START_ADDR() 		bfin_read32(DMA4_START_ADDR)
-#define bfin_write_DMA4_START_ADDR(val) 	bfin_write32(DMA4_START_ADDR)
+#define bfin_write_DMA4_START_ADDR(val) 	bfin_write32(DMA4_START_ADDR, val)
 #define bfin_read_DMA4_CONFIG()			bfin_read16(DMA4_CONFIG)
 #define bfin_write_DMA4_CONFIG(val)		bfin_write16(DMA4_CONFIG, val)
 #define bfin_read_DMA4_X_COUNT()		bfin_read16(DMA4_X_COUNT)
 #define bfin_write_DMA4_X_COUNT(val)		bfin_write16(DMA4_X_COUNT, val)
 #define bfin_read_DMA4_X_MODIFY()		bfin_read16(DMA4_X_MODIFY)
-#define bfin_write_DMA4_X_MODIFY(val) 		bfin_write16(DMA4_X_MODIFY)
+#define bfin_write_DMA4_X_MODIFY(val) 		bfin_write16(DMA4_X_MODIFY, val)
 #define bfin_read_DMA4_Y_COUNT()		bfin_read16(DMA4_Y_COUNT)
 #define bfin_write_DMA4_Y_COUNT(val)		bfin_write16(DMA4_Y_COUNT, val)
 #define bfin_read_DMA4_Y_MODIFY()		bfin_read16(DMA4_Y_MODIFY)
-#define bfin_write_DMA4_Y_MODIFY(val) 		bfin_write16(DMA4_Y_MODIFY)
+#define bfin_write_DMA4_Y_MODIFY(val) 		bfin_write16(DMA4_Y_MODIFY, val)
 #define bfin_read_DMA4_CURR_DESC_PTR() 		bfin_read32(DMA4_CURR_DESC_PTR)
-#define bfin_write_DMA4_CURR_DESC_PTR(val) 	bfin_write32(DMA4_CURR_DESC_PTR)
+#define bfin_write_DMA4_CURR_DESC_PTR(val) 	bfin_write32(DMA4_CURR_DESC_PTR, val)
 #define bfin_read_DMA4_CURR_ADDR() 		bfin_read32(DMA4_CURR_ADDR)
-#define bfin_write_DMA4_CURR_ADDR(val) 		bfin_write32(DMA4_CURR_ADDR)
+#define bfin_write_DMA4_CURR_ADDR(val) 		bfin_write32(DMA4_CURR_ADDR, val)
 #define bfin_read_DMA4_IRQ_STATUS()		bfin_read16(DMA4_IRQ_STATUS)
 #define bfin_write_DMA4_IRQ_STATUS(val)		bfin_write16(DMA4_IRQ_STATUS, val)
 #define bfin_read_DMA4_PERIPHERAL_MAP()		bfin_read16(DMA4_PERIPHERAL_MAP)
@@ -537,23 +533,23 @@
 /* DMA Channel 5 Registers */
 
 #define bfin_read_DMA5_NEXT_DESC_PTR() 		bfin_read32(DMA5_NEXT_DESC_PTR)
-#define bfin_write_DMA5_NEXT_DESC_PTR(val) 	bfin_write32(DMA5_NEXT_DESC_PTR)
+#define bfin_write_DMA5_NEXT_DESC_PTR(val) 	bfin_write32(DMA5_NEXT_DESC_PTR, val)
 #define bfin_read_DMA5_START_ADDR() 		bfin_read32(DMA5_START_ADDR)
-#define bfin_write_DMA5_START_ADDR(val) 	bfin_write32(DMA5_START_ADDR)
+#define bfin_write_DMA5_START_ADDR(val) 	bfin_write32(DMA5_START_ADDR, val)
 #define bfin_read_DMA5_CONFIG()			bfin_read16(DMA5_CONFIG)
 #define bfin_write_DMA5_CONFIG(val)		bfin_write16(DMA5_CONFIG, val)
 #define bfin_read_DMA5_X_COUNT()		bfin_read16(DMA5_X_COUNT)
 #define bfin_write_DMA5_X_COUNT(val)		bfin_write16(DMA5_X_COUNT, val)
 #define bfin_read_DMA5_X_MODIFY()		bfin_read16(DMA5_X_MODIFY)
-#define bfin_write_DMA5_X_MODIFY(val) 		bfin_write16(DMA5_X_MODIFY)
+#define bfin_write_DMA5_X_MODIFY(val) 		bfin_write16(DMA5_X_MODIFY, val)
 #define bfin_read_DMA5_Y_COUNT()		bfin_read16(DMA5_Y_COUNT)
 #define bfin_write_DMA5_Y_COUNT(val)		bfin_write16(DMA5_Y_COUNT, val)
 #define bfin_read_DMA5_Y_MODIFY()		bfin_read16(DMA5_Y_MODIFY)
-#define bfin_write_DMA5_Y_MODIFY(val) 		bfin_write16(DMA5_Y_MODIFY)
+#define bfin_write_DMA5_Y_MODIFY(val) 		bfin_write16(DMA5_Y_MODIFY, val)
 #define bfin_read_DMA5_CURR_DESC_PTR() 		bfin_read32(DMA5_CURR_DESC_PTR)
-#define bfin_write_DMA5_CURR_DESC_PTR(val) 	bfin_write32(DMA5_CURR_DESC_PTR)
+#define bfin_write_DMA5_CURR_DESC_PTR(val) 	bfin_write32(DMA5_CURR_DESC_PTR, val)
 #define bfin_read_DMA5_CURR_ADDR() 		bfin_read32(DMA5_CURR_ADDR)
-#define bfin_write_DMA5_CURR_ADDR(val) 		bfin_write32(DMA5_CURR_ADDR)
+#define bfin_write_DMA5_CURR_ADDR(val) 		bfin_write32(DMA5_CURR_ADDR, val)
 #define bfin_read_DMA5_IRQ_STATUS()		bfin_read16(DMA5_IRQ_STATUS)
 #define bfin_write_DMA5_IRQ_STATUS(val)		bfin_write16(DMA5_IRQ_STATUS, val)
 #define bfin_read_DMA5_PERIPHERAL_MAP()		bfin_read16(DMA5_PERIPHERAL_MAP)
@@ -566,23 +562,23 @@
 /* DMA Channel 6 Registers */
 
 #define bfin_read_DMA6_NEXT_DESC_PTR() 		bfin_read32(DMA6_NEXT_DESC_PTR)
-#define bfin_write_DMA6_NEXT_DESC_PTR(val) 	bfin_write32(DMA6_NEXT_DESC_PTR)
+#define bfin_write_DMA6_NEXT_DESC_PTR(val) 	bfin_write32(DMA6_NEXT_DESC_PTR, val)
 #define bfin_read_DMA6_START_ADDR() 		bfin_read32(DMA6_START_ADDR)
-#define bfin_write_DMA6_START_ADDR(val) 	bfin_write32(DMA6_START_ADDR)
+#define bfin_write_DMA6_START_ADDR(val) 	bfin_write32(DMA6_START_ADDR, val)
 #define bfin_read_DMA6_CONFIG()			bfin_read16(DMA6_CONFIG)
 #define bfin_write_DMA6_CONFIG(val)		bfin_write16(DMA6_CONFIG, val)
 #define bfin_read_DMA6_X_COUNT()		bfin_read16(DMA6_X_COUNT)
 #define bfin_write_DMA6_X_COUNT(val)		bfin_write16(DMA6_X_COUNT, val)
 #define bfin_read_DMA6_X_MODIFY()		bfin_read16(DMA6_X_MODIFY)
-#define bfin_write_DMA6_X_MODIFY(val) 		bfin_write16(DMA6_X_MODIFY)
+#define bfin_write_DMA6_X_MODIFY(val) 		bfin_write16(DMA6_X_MODIFY, val)
 #define bfin_read_DMA6_Y_COUNT()		bfin_read16(DMA6_Y_COUNT)
 #define bfin_write_DMA6_Y_COUNT(val)		bfin_write16(DMA6_Y_COUNT, val)
 #define bfin_read_DMA6_Y_MODIFY()		bfin_read16(DMA6_Y_MODIFY)
-#define bfin_write_DMA6_Y_MODIFY(val) 		bfin_write16(DMA6_Y_MODIFY)
+#define bfin_write_DMA6_Y_MODIFY(val) 		bfin_write16(DMA6_Y_MODIFY, val)
 #define bfin_read_DMA6_CURR_DESC_PTR() 		bfin_read32(DMA6_CURR_DESC_PTR)
-#define bfin_write_DMA6_CURR_DESC_PTR(val) 	bfin_write32(DMA6_CURR_DESC_PTR)
+#define bfin_write_DMA6_CURR_DESC_PTR(val) 	bfin_write32(DMA6_CURR_DESC_PTR, val)
 #define bfin_read_DMA6_CURR_ADDR() 		bfin_read32(DMA6_CURR_ADDR)
-#define bfin_write_DMA6_CURR_ADDR(val) 		bfin_write32(DMA6_CURR_ADDR)
+#define bfin_write_DMA6_CURR_ADDR(val) 		bfin_write32(DMA6_CURR_ADDR, val)
 #define bfin_read_DMA6_IRQ_STATUS()		bfin_read16(DMA6_IRQ_STATUS)
 #define bfin_write_DMA6_IRQ_STATUS(val)		bfin_write16(DMA6_IRQ_STATUS, val)
 #define bfin_read_DMA6_PERIPHERAL_MAP()		bfin_read16(DMA6_PERIPHERAL_MAP)
@@ -595,23 +591,23 @@
 /* DMA Channel 7 Registers */
 
 #define bfin_read_DMA7_NEXT_DESC_PTR() 		bfin_read32(DMA7_NEXT_DESC_PTR)
-#define bfin_write_DMA7_NEXT_DESC_PTR(val) 	bfin_write32(DMA7_NEXT_DESC_PTR)
+#define bfin_write_DMA7_NEXT_DESC_PTR(val) 	bfin_write32(DMA7_NEXT_DESC_PTR, val)
 #define bfin_read_DMA7_START_ADDR() 		bfin_read32(DMA7_START_ADDR)
-#define bfin_write_DMA7_START_ADDR(val) 	bfin_write32(DMA7_START_ADDR)
+#define bfin_write_DMA7_START_ADDR(val) 	bfin_write32(DMA7_START_ADDR, val)
 #define bfin_read_DMA7_CONFIG()			bfin_read16(DMA7_CONFIG)
 #define bfin_write_DMA7_CONFIG(val)		bfin_write16(DMA7_CONFIG, val)
 #define bfin_read_DMA7_X_COUNT()		bfin_read16(DMA7_X_COUNT)
 #define bfin_write_DMA7_X_COUNT(val)		bfin_write16(DMA7_X_COUNT, val)
 #define bfin_read_DMA7_X_MODIFY()		bfin_read16(DMA7_X_MODIFY)
-#define bfin_write_DMA7_X_MODIFY(val) 		bfin_write16(DMA7_X_MODIFY)
+#define bfin_write_DMA7_X_MODIFY(val) 		bfin_write16(DMA7_X_MODIFY, val)
 #define bfin_read_DMA7_Y_COUNT()		bfin_read16(DMA7_Y_COUNT)
 #define bfin_write_DMA7_Y_COUNT(val)		bfin_write16(DMA7_Y_COUNT, val)
 #define bfin_read_DMA7_Y_MODIFY()		bfin_read16(DMA7_Y_MODIFY)
-#define bfin_write_DMA7_Y_MODIFY(val) 		bfin_write16(DMA7_Y_MODIFY)
+#define bfin_write_DMA7_Y_MODIFY(val) 		bfin_write16(DMA7_Y_MODIFY, val)
 #define bfin_read_DMA7_CURR_DESC_PTR() 		bfin_read32(DMA7_CURR_DESC_PTR)
-#define bfin_write_DMA7_CURR_DESC_PTR(val) 	bfin_write32(DMA7_CURR_DESC_PTR)
+#define bfin_write_DMA7_CURR_DESC_PTR(val) 	bfin_write32(DMA7_CURR_DESC_PTR, val)
 #define bfin_read_DMA7_CURR_ADDR() 		bfin_read32(DMA7_CURR_ADDR)
-#define bfin_write_DMA7_CURR_ADDR(val) 		bfin_write32(DMA7_CURR_ADDR)
+#define bfin_write_DMA7_CURR_ADDR(val) 		bfin_write32(DMA7_CURR_ADDR, val)
 #define bfin_read_DMA7_IRQ_STATUS()		bfin_read16(DMA7_IRQ_STATUS)
 #define bfin_write_DMA7_IRQ_STATUS(val)		bfin_write16(DMA7_IRQ_STATUS, val)
 #define bfin_read_DMA7_PERIPHERAL_MAP()		bfin_read16(DMA7_PERIPHERAL_MAP)
@@ -624,23 +620,23 @@
 /* DMA Channel 8 Registers */
 
 #define bfin_read_DMA8_NEXT_DESC_PTR() 		bfin_read32(DMA8_NEXT_DESC_PTR)
-#define bfin_write_DMA8_NEXT_DESC_PTR(val) 	bfin_write32(DMA8_NEXT_DESC_PTR)
+#define bfin_write_DMA8_NEXT_DESC_PTR(val) 	bfin_write32(DMA8_NEXT_DESC_PTR, val)
 #define bfin_read_DMA8_START_ADDR() 		bfin_read32(DMA8_START_ADDR)
-#define bfin_write_DMA8_START_ADDR(val) 	bfin_write32(DMA8_START_ADDR)
+#define bfin_write_DMA8_START_ADDR(val) 	bfin_write32(DMA8_START_ADDR, val)
 #define bfin_read_DMA8_CONFIG()			bfin_read16(DMA8_CONFIG)
 #define bfin_write_DMA8_CONFIG(val)		bfin_write16(DMA8_CONFIG, val)
 #define bfin_read_DMA8_X_COUNT()		bfin_read16(DMA8_X_COUNT)
 #define bfin_write_DMA8_X_COUNT(val)		bfin_write16(DMA8_X_COUNT, val)
 #define bfin_read_DMA8_X_MODIFY()		bfin_read16(DMA8_X_MODIFY)
-#define bfin_write_DMA8_X_MODIFY(val) 		bfin_write16(DMA8_X_MODIFY)
+#define bfin_write_DMA8_X_MODIFY(val) 		bfin_write16(DMA8_X_MODIFY, val)
 #define bfin_read_DMA8_Y_COUNT()		bfin_read16(DMA8_Y_COUNT)
 #define bfin_write_DMA8_Y_COUNT(val)		bfin_write16(DMA8_Y_COUNT, val)
 #define bfin_read_DMA8_Y_MODIFY()		bfin_read16(DMA8_Y_MODIFY)
-#define bfin_write_DMA8_Y_MODIFY(val) 		bfin_write16(DMA8_Y_MODIFY)
+#define bfin_write_DMA8_Y_MODIFY(val) 		bfin_write16(DMA8_Y_MODIFY, val)
 #define bfin_read_DMA8_CURR_DESC_PTR() 		bfin_read32(DMA8_CURR_DESC_PTR)
-#define bfin_write_DMA8_CURR_DESC_PTR(val) 	bfin_write32(DMA8_CURR_DESC_PTR)
+#define bfin_write_DMA8_CURR_DESC_PTR(val) 	bfin_write32(DMA8_CURR_DESC_PTR, val)
 #define bfin_read_DMA8_CURR_ADDR() 		bfin_read32(DMA8_CURR_ADDR)
-#define bfin_write_DMA8_CURR_ADDR(val) 		bfin_write32(DMA8_CURR_ADDR)
+#define bfin_write_DMA8_CURR_ADDR(val) 		bfin_write32(DMA8_CURR_ADDR, val)
 #define bfin_read_DMA8_IRQ_STATUS()		bfin_read16(DMA8_IRQ_STATUS)
 #define bfin_write_DMA8_IRQ_STATUS(val)		bfin_write16(DMA8_IRQ_STATUS, val)
 #define bfin_read_DMA8_PERIPHERAL_MAP()		bfin_read16(DMA8_PERIPHERAL_MAP)
@@ -653,23 +649,23 @@
 /* DMA Channel 9 Registers */
 
 #define bfin_read_DMA9_NEXT_DESC_PTR() 		bfin_read32(DMA9_NEXT_DESC_PTR)
-#define bfin_write_DMA9_NEXT_DESC_PTR(val) 	bfin_write32(DMA9_NEXT_DESC_PTR)
+#define bfin_write_DMA9_NEXT_DESC_PTR(val) 	bfin_write32(DMA9_NEXT_DESC_PTR, val)
 #define bfin_read_DMA9_START_ADDR() 		bfin_read32(DMA9_START_ADDR)
-#define bfin_write_DMA9_START_ADDR(val) 	bfin_write32(DMA9_START_ADDR)
+#define bfin_write_DMA9_START_ADDR(val) 	bfin_write32(DMA9_START_ADDR, val)
 #define bfin_read_DMA9_CONFIG()			bfin_read16(DMA9_CONFIG)
 #define bfin_write_DMA9_CONFIG(val)		bfin_write16(DMA9_CONFIG, val)
 #define bfin_read_DMA9_X_COUNT()		bfin_read16(DMA9_X_COUNT)
 #define bfin_write_DMA9_X_COUNT(val)		bfin_write16(DMA9_X_COUNT, val)
 #define bfin_read_DMA9_X_MODIFY()		bfin_read16(DMA9_X_MODIFY)
-#define bfin_write_DMA9_X_MODIFY(val) 		bfin_write16(DMA9_X_MODIFY)
+#define bfin_write_DMA9_X_MODIFY(val) 		bfin_write16(DMA9_X_MODIFY, val)
 #define bfin_read_DMA9_Y_COUNT()		bfin_read16(DMA9_Y_COUNT)
 #define bfin_write_DMA9_Y_COUNT(val)		bfin_write16(DMA9_Y_COUNT, val)
 #define bfin_read_DMA9_Y_MODIFY()		bfin_read16(DMA9_Y_MODIFY)
-#define bfin_write_DMA9_Y_MODIFY(val) 		bfin_write16(DMA9_Y_MODIFY)
+#define bfin_write_DMA9_Y_MODIFY(val) 		bfin_write16(DMA9_Y_MODIFY, val)
 #define bfin_read_DMA9_CURR_DESC_PTR() 		bfin_read32(DMA9_CURR_DESC_PTR)
-#define bfin_write_DMA9_CURR_DESC_PTR(val) 	bfin_write32(DMA9_CURR_DESC_PTR)
+#define bfin_write_DMA9_CURR_DESC_PTR(val) 	bfin_write32(DMA9_CURR_DESC_PTR, val)
 #define bfin_read_DMA9_CURR_ADDR() 		bfin_read32(DMA9_CURR_ADDR)
-#define bfin_write_DMA9_CURR_ADDR(val) 		bfin_write32(DMA9_CURR_ADDR)
+#define bfin_write_DMA9_CURR_ADDR(val) 		bfin_write32(DMA9_CURR_ADDR, val)
 #define bfin_read_DMA9_IRQ_STATUS()		bfin_read16(DMA9_IRQ_STATUS)
 #define bfin_write_DMA9_IRQ_STATUS(val)		bfin_write16(DMA9_IRQ_STATUS, val)
 #define bfin_read_DMA9_PERIPHERAL_MAP()		bfin_read16(DMA9_PERIPHERAL_MAP)
@@ -682,23 +678,23 @@
 /* DMA Channel 10 Registers */
 
 #define bfin_read_DMA10_NEXT_DESC_PTR() 	bfin_read32(DMA10_NEXT_DESC_PTR)
-#define bfin_write_DMA10_NEXT_DESC_PTR(val) 	bfin_write32(DMA10_NEXT_DESC_PTR)
+#define bfin_write_DMA10_NEXT_DESC_PTR(val) 	bfin_write32(DMA10_NEXT_DESC_PTR, val)
 #define bfin_read_DMA10_START_ADDR() 		bfin_read32(DMA10_START_ADDR)
-#define bfin_write_DMA10_START_ADDR(val) 	bfin_write32(DMA10_START_ADDR)
+#define bfin_write_DMA10_START_ADDR(val) 	bfin_write32(DMA10_START_ADDR, val)
 #define bfin_read_DMA10_CONFIG()		bfin_read16(DMA10_CONFIG)
 #define bfin_write_DMA10_CONFIG(val)		bfin_write16(DMA10_CONFIG, val)
 #define bfin_read_DMA10_X_COUNT()		bfin_read16(DMA10_X_COUNT)
 #define bfin_write_DMA10_X_COUNT(val)		bfin_write16(DMA10_X_COUNT, val)
 #define bfin_read_DMA10_X_MODIFY()		bfin_read16(DMA10_X_MODIFY)
-#define bfin_write_DMA10_X_MODIFY(val) 		bfin_write16(DMA10_X_MODIFY)
+#define bfin_write_DMA10_X_MODIFY(val) 		bfin_write16(DMA10_X_MODIFY, val)
 #define bfin_read_DMA10_Y_COUNT()		bfin_read16(DMA10_Y_COUNT)
 #define bfin_write_DMA10_Y_COUNT(val)		bfin_write16(DMA10_Y_COUNT, val)
 #define bfin_read_DMA10_Y_MODIFY()		bfin_read16(DMA10_Y_MODIFY)
-#define bfin_write_DMA10_Y_MODIFY(val) 		bfin_write16(DMA10_Y_MODIFY)
+#define bfin_write_DMA10_Y_MODIFY(val) 		bfin_write16(DMA10_Y_MODIFY, val)
 #define bfin_read_DMA10_CURR_DESC_PTR() 	bfin_read32(DMA10_CURR_DESC_PTR)
-#define bfin_write_DMA10_CURR_DESC_PTR(val) 	bfin_write32(DMA10_CURR_DESC_PTR)
+#define bfin_write_DMA10_CURR_DESC_PTR(val) 	bfin_write32(DMA10_CURR_DESC_PTR, val)
 #define bfin_read_DMA10_CURR_ADDR() 		bfin_read32(DMA10_CURR_ADDR)
-#define bfin_write_DMA10_CURR_ADDR(val) 	bfin_write32(DMA10_CURR_ADDR)
+#define bfin_write_DMA10_CURR_ADDR(val) 	bfin_write32(DMA10_CURR_ADDR, val)
 #define bfin_read_DMA10_IRQ_STATUS()		bfin_read16(DMA10_IRQ_STATUS)
 #define bfin_write_DMA10_IRQ_STATUS(val)	bfin_write16(DMA10_IRQ_STATUS, val)
 #define bfin_read_DMA10_PERIPHERAL_MAP()	bfin_read16(DMA10_PERIPHERAL_MAP)
@@ -711,23 +707,23 @@
 /* DMA Channel 11 Registers */
 
 #define bfin_read_DMA11_NEXT_DESC_PTR() 	bfin_read32(DMA11_NEXT_DESC_PTR)
-#define bfin_write_DMA11_NEXT_DESC_PTR(val) 	bfin_write32(DMA11_NEXT_DESC_PTR)
+#define bfin_write_DMA11_NEXT_DESC_PTR(val) 	bfin_write32(DMA11_NEXT_DESC_PTR, val)
 #define bfin_read_DMA11_START_ADDR() 		bfin_read32(DMA11_START_ADDR)
-#define bfin_write_DMA11_START_ADDR(val) 	bfin_write32(DMA11_START_ADDR)
+#define bfin_write_DMA11_START_ADDR(val) 	bfin_write32(DMA11_START_ADDR, val)
 #define bfin_read_DMA11_CONFIG()		bfin_read16(DMA11_CONFIG)
 #define bfin_write_DMA11_CONFIG(val)		bfin_write16(DMA11_CONFIG, val)
 #define bfin_read_DMA11_X_COUNT()		bfin_read16(DMA11_X_COUNT)
 #define bfin_write_DMA11_X_COUNT(val)		bfin_write16(DMA11_X_COUNT, val)
 #define bfin_read_DMA11_X_MODIFY()		bfin_read16(DMA11_X_MODIFY)
-#define bfin_write_DMA11_X_MODIFY(val) 		bfin_write16(DMA11_X_MODIFY)
+#define bfin_write_DMA11_X_MODIFY(val) 		bfin_write16(DMA11_X_MODIFY, val)
 #define bfin_read_DMA11_Y_COUNT()		bfin_read16(DMA11_Y_COUNT)
 #define bfin_write_DMA11_Y_COUNT(val)		bfin_write16(DMA11_Y_COUNT, val)
 #define bfin_read_DMA11_Y_MODIFY()		bfin_read16(DMA11_Y_MODIFY)
-#define bfin_write_DMA11_Y_MODIFY(val) 		bfin_write16(DMA11_Y_MODIFY)
+#define bfin_write_DMA11_Y_MODIFY(val) 		bfin_write16(DMA11_Y_MODIFY, val)
 #define bfin_read_DMA11_CURR_DESC_PTR() 	bfin_read32(DMA11_CURR_DESC_PTR)
-#define bfin_write_DMA11_CURR_DESC_PTR(val) 	bfin_write32(DMA11_CURR_DESC_PTR)
+#define bfin_write_DMA11_CURR_DESC_PTR(val) 	bfin_write32(DMA11_CURR_DESC_PTR, val)
 #define bfin_read_DMA11_CURR_ADDR() 		bfin_read32(DMA11_CURR_ADDR)
-#define bfin_write_DMA11_CURR_ADDR(val) 	bfin_write32(DMA11_CURR_ADDR)
+#define bfin_write_DMA11_CURR_ADDR(val) 	bfin_write32(DMA11_CURR_ADDR, val)
 #define bfin_read_DMA11_IRQ_STATUS()		bfin_read16(DMA11_IRQ_STATUS)
 #define bfin_write_DMA11_IRQ_STATUS(val)	bfin_write16(DMA11_IRQ_STATUS, val)
 #define bfin_read_DMA11_PERIPHERAL_MAP()	bfin_read16(DMA11_PERIPHERAL_MAP)
@@ -740,7 +736,7 @@
 /* MDMA Stream 0 Registers */
 
 #define bfin_read_MDMA_D0_NEXT_DESC_PTR() 	bfin_read32(MDMA_D0_NEXT_DESC_PTR)
-#define bfin_write_MDMA_D0_NEXT_DESC_PTR(val) 	bfin_write32(MDMA_D0_NEXT_DESC_PTR)
+#define bfin_write_MDMA_D0_NEXT_DESC_PTR(val) 	bfin_write32(MDMA_D0_NEXT_DESC_PTR, val)
 #define bfin_read_MDMA_D0_START_ADDR() 		bfin_read32(MDMA_D0_START_ADDR)
 #define bfin_write_MDMA_D0_START_ADDR(val) 	bfin_write32(MDMA_D0_START_ADDR, val)
 #define bfin_read_MDMA_D0_CONFIG()		bfin_read16(MDMA_D0_CONFIG)
@@ -803,11 +799,11 @@
 #define bfin_read_MDMA_D1_X_COUNT()		bfin_read16(MDMA_D1_X_COUNT)
 #define bfin_write_MDMA_D1_X_COUNT(val)		bfin_write16(MDMA_D1_X_COUNT, val)
 #define bfin_read_MDMA_D1_X_MODIFY()		bfin_read16(MDMA_D1_X_MODIFY)
-#define bfin_write_MDMA_D1_X_MODIFY(val) 	bfin_write16(MDMA_D1_X_MODIFY)
+#define bfin_write_MDMA_D1_X_MODIFY(val) 	bfin_write16(MDMA_D1_X_MODIFY, val)
 #define bfin_read_MDMA_D1_Y_COUNT()		bfin_read16(MDMA_D1_Y_COUNT)
 #define bfin_write_MDMA_D1_Y_COUNT(val)		bfin_write16(MDMA_D1_Y_COUNT, val)
 #define bfin_read_MDMA_D1_Y_MODIFY()		bfin_read16(MDMA_D1_Y_MODIFY)
-#define bfin_write_MDMA_D1_Y_MODIFY(val) 	bfin_write16(MDMA_D1_Y_MODIFY)
+#define bfin_write_MDMA_D1_Y_MODIFY(val) 	bfin_write16(MDMA_D1_Y_MODIFY, val)
 #define bfin_read_MDMA_D1_CURR_DESC_PTR() 	bfin_read32(MDMA_D1_CURR_DESC_PTR)
 #define bfin_write_MDMA_D1_CURR_DESC_PTR(val) 	bfin_write32(MDMA_D1_CURR_DESC_PTR, val)
 #define bfin_read_MDMA_D1_CURR_ADDR() 		bfin_read32(MDMA_D1_CURR_ADDR)
@@ -829,11 +825,11 @@
 #define bfin_read_MDMA_S1_X_COUNT()		bfin_read16(MDMA_S1_X_COUNT)
 #define bfin_write_MDMA_S1_X_COUNT(val)		bfin_write16(MDMA_S1_X_COUNT, val)
 #define bfin_read_MDMA_S1_X_MODIFY()		bfin_read16(MDMA_S1_X_MODIFY)
-#define bfin_write_MDMA_S1_X_MODIFY(val) 	bfin_write16(MDMA_S1_X_MODIFY)
+#define bfin_write_MDMA_S1_X_MODIFY(val) 	bfin_write16(MDMA_S1_X_MODIFY, val)
 #define bfin_read_MDMA_S1_Y_COUNT()		bfin_read16(MDMA_S1_Y_COUNT)
 #define bfin_write_MDMA_S1_Y_COUNT(val)		bfin_write16(MDMA_S1_Y_COUNT, val)
 #define bfin_read_MDMA_S1_Y_MODIFY()		bfin_read16(MDMA_S1_Y_MODIFY)
-#define bfin_write_MDMA_S1_Y_MODIFY(val) 	bfin_write16(MDMA_S1_Y_MODIFY)
+#define bfin_write_MDMA_S1_Y_MODIFY(val) 	bfin_write16(MDMA_S1_Y_MODIFY, val)
 #define bfin_read_MDMA_S1_CURR_DESC_PTR() 	bfin_read32(MDMA_S1_CURR_DESC_PTR)
 #define bfin_write_MDMA_S1_CURR_DESC_PTR(val) 	bfin_write32(MDMA_S1_CURR_DESC_PTR, val)
 #define bfin_read_MDMA_S1_CURR_ADDR() 		bfin_read32(MDMA_S1_CURR_ADDR)
@@ -1246,23 +1242,23 @@
 /* DMA Channel 12 Registers */
 
 #define bfin_read_DMA12_NEXT_DESC_PTR() 	bfin_read32(DMA12_NEXT_DESC_PTR)
-#define bfin_write_DMA12_NEXT_DESC_PTR(val) 	bfin_write32(DMA12_NEXT_DESC_PTR)
+#define bfin_write_DMA12_NEXT_DESC_PTR(val) 	bfin_write32(DMA12_NEXT_DESC_PTR, val)
 #define bfin_read_DMA12_START_ADDR() 		bfin_read32(DMA12_START_ADDR)
-#define bfin_write_DMA12_START_ADDR(val) 	bfin_write32(DMA12_START_ADDR)
+#define bfin_write_DMA12_START_ADDR(val) 	bfin_write32(DMA12_START_ADDR, val)
 #define bfin_read_DMA12_CONFIG()		bfin_read16(DMA12_CONFIG)
 #define bfin_write_DMA12_CONFIG(val)		bfin_write16(DMA12_CONFIG, val)
 #define bfin_read_DMA12_X_COUNT()		bfin_read16(DMA12_X_COUNT)
 #define bfin_write_DMA12_X_COUNT(val)		bfin_write16(DMA12_X_COUNT, val)
 #define bfin_read_DMA12_X_MODIFY()		bfin_read16(DMA12_X_MODIFY)
-#define bfin_write_DMA12_X_MODIFY(val) 		bfin_write16(DMA12_X_MODIFY)
+#define bfin_write_DMA12_X_MODIFY(val) 		bfin_write16(DMA12_X_MODIFY, val)
 #define bfin_read_DMA12_Y_COUNT()		bfin_read16(DMA12_Y_COUNT)
 #define bfin_write_DMA12_Y_COUNT(val)		bfin_write16(DMA12_Y_COUNT, val)
 #define bfin_read_DMA12_Y_MODIFY()		bfin_read16(DMA12_Y_MODIFY)
-#define bfin_write_DMA12_Y_MODIFY(val) 		bfin_write16(DMA12_Y_MODIFY)
+#define bfin_write_DMA12_Y_MODIFY(val) 		bfin_write16(DMA12_Y_MODIFY, val)
 #define bfin_read_DMA12_CURR_DESC_PTR() 	bfin_read32(DMA12_CURR_DESC_PTR)
-#define bfin_write_DMA12_CURR_DESC_PTR(val) 	bfin_write32(DMA12_CURR_DESC_PTR)
+#define bfin_write_DMA12_CURR_DESC_PTR(val) 	bfin_write32(DMA12_CURR_DESC_PTR, val)
 #define bfin_read_DMA12_CURR_ADDR() 		bfin_read32(DMA12_CURR_ADDR)
-#define bfin_write_DMA12_CURR_ADDR(val) 	bfin_write32(DMA12_CURR_ADDR)
+#define bfin_write_DMA12_CURR_ADDR(val) 	bfin_write32(DMA12_CURR_ADDR, val)
 #define bfin_read_DMA12_IRQ_STATUS()		bfin_read16(DMA12_IRQ_STATUS)
 #define bfin_write_DMA12_IRQ_STATUS(val)	bfin_write16(DMA12_IRQ_STATUS, val)
 #define bfin_read_DMA12_PERIPHERAL_MAP()	bfin_read16(DMA12_PERIPHERAL_MAP)
@@ -1275,23 +1271,23 @@
 /* DMA Channel 13 Registers */
 
 #define bfin_read_DMA13_NEXT_DESC_PTR() 	bfin_read32(DMA13_NEXT_DESC_PTR)
-#define bfin_write_DMA13_NEXT_DESC_PTR(val) 	bfin_write32(DMA13_NEXT_DESC_PTR)
+#define bfin_write_DMA13_NEXT_DESC_PTR(val) 	bfin_write32(DMA13_NEXT_DESC_PTR, val)
 #define bfin_read_DMA13_START_ADDR() 		bfin_read32(DMA13_START_ADDR)
-#define bfin_write_DMA13_START_ADDR(val) 	bfin_write32(DMA13_START_ADDR)
+#define bfin_write_DMA13_START_ADDR(val) 	bfin_write32(DMA13_START_ADDR, val)
 #define bfin_read_DMA13_CONFIG()		bfin_read16(DMA13_CONFIG)
 #define bfin_write_DMA13_CONFIG(val)		bfin_write16(DMA13_CONFIG, val)
 #define bfin_read_DMA13_X_COUNT()		bfin_read16(DMA13_X_COUNT)
 #define bfin_write_DMA13_X_COUNT(val)		bfin_write16(DMA13_X_COUNT, val)
 #define bfin_read_DMA13_X_MODIFY()		bfin_read16(DMA13_X_MODIFY)
-#define bfin_write_DMA13_X_MODIFY(val) 		bfin_write16(DMA13_X_MODIFY)
+#define bfin_write_DMA13_X_MODIFY(val) 		bfin_write16(DMA13_X_MODIFY, val)
 #define bfin_read_DMA13_Y_COUNT()		bfin_read16(DMA13_Y_COUNT)
 #define bfin_write_DMA13_Y_COUNT(val)		bfin_write16(DMA13_Y_COUNT, val)
 #define bfin_read_DMA13_Y_MODIFY()		bfin_read16(DMA13_Y_MODIFY)
-#define bfin_write_DMA13_Y_MODIFY(val) 		bfin_write16(DMA13_Y_MODIFY)
+#define bfin_write_DMA13_Y_MODIFY(val) 		bfin_write16(DMA13_Y_MODIFY, val)
 #define bfin_read_DMA13_CURR_DESC_PTR() 	bfin_read32(DMA13_CURR_DESC_PTR)
-#define bfin_write_DMA13_CURR_DESC_PTR(val) 	bfin_write32(DMA13_CURR_DESC_PTR)
+#define bfin_write_DMA13_CURR_DESC_PTR(val) 	bfin_write32(DMA13_CURR_DESC_PTR, val)
 #define bfin_read_DMA13_CURR_ADDR() 		bfin_read32(DMA13_CURR_ADDR)
-#define bfin_write_DMA13_CURR_ADDR(val) 	bfin_write32(DMA13_CURR_ADDR)
+#define bfin_write_DMA13_CURR_ADDR(val) 	bfin_write32(DMA13_CURR_ADDR, val)
 #define bfin_read_DMA13_IRQ_STATUS()		bfin_read16(DMA13_IRQ_STATUS)
 #define bfin_write_DMA13_IRQ_STATUS(val)	bfin_write16(DMA13_IRQ_STATUS, val)
 #define bfin_read_DMA13_PERIPHERAL_MAP()	bfin_read16(DMA13_PERIPHERAL_MAP)
@@ -1304,23 +1300,23 @@
 /* DMA Channel 14 Registers */
 
 #define bfin_read_DMA14_NEXT_DESC_PTR() 	bfin_read32(DMA14_NEXT_DESC_PTR)
-#define bfin_write_DMA14_NEXT_DESC_PTR(val) 	bfin_write32(DMA14_NEXT_DESC_PTR)
+#define bfin_write_DMA14_NEXT_DESC_PTR(val) 	bfin_write32(DMA14_NEXT_DESC_PTR, val)
 #define bfin_read_DMA14_START_ADDR() 		bfin_read32(DMA14_START_ADDR)
-#define bfin_write_DMA14_START_ADDR(val) 	bfin_write32(DMA14_START_ADDR)
+#define bfin_write_DMA14_START_ADDR(val) 	bfin_write32(DMA14_START_ADDR, val)
 #define bfin_read_DMA14_CONFIG()		bfin_read16(DMA14_CONFIG)
 #define bfin_write_DMA14_CONFIG(val)		bfin_write16(DMA14_CONFIG, val)
 #define bfin_read_DMA14_X_COUNT()		bfin_read16(DMA14_X_COUNT)
 #define bfin_write_DMA14_X_COUNT(val)		bfin_write16(DMA14_X_COUNT, val)
 #define bfin_read_DMA14_X_MODIFY()		bfin_read16(DMA14_X_MODIFY)
-#define bfin_write_DMA14_X_MODIFY(val) 		bfin_write16(DMA14_X_MODIFY)
+#define bfin_write_DMA14_X_MODIFY(val) 		bfin_write16(DMA14_X_MODIFY, val)
 #define bfin_read_DMA14_Y_COUNT()		bfin_read16(DMA14_Y_COUNT)
 #define bfin_write_DMA14_Y_COUNT(val)		bfin_write16(DMA14_Y_COUNT, val)
 #define bfin_read_DMA14_Y_MODIFY()		bfin_read16(DMA14_Y_MODIFY)
-#define bfin_write_DMA14_Y_MODIFY(val) 		bfin_write16(DMA14_Y_MODIFY)
+#define bfin_write_DMA14_Y_MODIFY(val) 		bfin_write16(DMA14_Y_MODIFY, val)
 #define bfin_read_DMA14_CURR_DESC_PTR() 	bfin_read32(DMA14_CURR_DESC_PTR)
-#define bfin_write_DMA14_CURR_DESC_PTR(val) 	bfin_write32(DMA14_CURR_DESC_PTR)
+#define bfin_write_DMA14_CURR_DESC_PTR(val) 	bfin_write32(DMA14_CURR_DESC_PTR, val)
 #define bfin_read_DMA14_CURR_ADDR() 		bfin_read32(DMA14_CURR_ADDR)
-#define bfin_write_DMA14_CURR_ADDR(val) 	bfin_write32(DMA14_CURR_ADDR)
+#define bfin_write_DMA14_CURR_ADDR(val) 	bfin_write32(DMA14_CURR_ADDR, val)
 #define bfin_read_DMA14_IRQ_STATUS()		bfin_read16(DMA14_IRQ_STATUS)
 #define bfin_write_DMA14_IRQ_STATUS(val)	bfin_write16(DMA14_IRQ_STATUS, val)
 #define bfin_read_DMA14_PERIPHERAL_MAP()	bfin_read16(DMA14_PERIPHERAL_MAP)
@@ -1333,23 +1329,23 @@
 /* DMA Channel 15 Registers */
 
 #define bfin_read_DMA15_NEXT_DESC_PTR() 	bfin_read32(DMA15_NEXT_DESC_PTR)
-#define bfin_write_DMA15_NEXT_DESC_PTR(val) 	bfin_write32(DMA15_NEXT_DESC_PTR)
+#define bfin_write_DMA15_NEXT_DESC_PTR(val) 	bfin_write32(DMA15_NEXT_DESC_PTR, val)
 #define bfin_read_DMA15_START_ADDR() 		bfin_read32(DMA15_START_ADDR)
-#define bfin_write_DMA15_START_ADDR(val) 	bfin_write32(DMA15_START_ADDR)
+#define bfin_write_DMA15_START_ADDR(val) 	bfin_write32(DMA15_START_ADDR, val)
 #define bfin_read_DMA15_CONFIG()		bfin_read16(DMA15_CONFIG)
 #define bfin_write_DMA15_CONFIG(val)		bfin_write16(DMA15_CONFIG, val)
 #define bfin_read_DMA15_X_COUNT()		bfin_read16(DMA15_X_COUNT)
 #define bfin_write_DMA15_X_COUNT(val)		bfin_write16(DMA15_X_COUNT, val)
 #define bfin_read_DMA15_X_MODIFY()		bfin_read16(DMA15_X_MODIFY)
-#define bfin_write_DMA15_X_MODIFY(val) 		bfin_write16(DMA15_X_MODIFY)
+#define bfin_write_DMA15_X_MODIFY(val) 		bfin_write16(DMA15_X_MODIFY, val)
 #define bfin_read_DMA15_Y_COUNT()		bfin_read16(DMA15_Y_COUNT)
 #define bfin_write_DMA15_Y_COUNT(val)		bfin_write16(DMA15_Y_COUNT, val)
 #define bfin_read_DMA15_Y_MODIFY()		bfin_read16(DMA15_Y_MODIFY)
-#define bfin_write_DMA15_Y_MODIFY(val) 		bfin_write16(DMA15_Y_MODIFY)
+#define bfin_write_DMA15_Y_MODIFY(val) 		bfin_write16(DMA15_Y_MODIFY, val)
 #define bfin_read_DMA15_CURR_DESC_PTR() 	bfin_read32(DMA15_CURR_DESC_PTR)
-#define bfin_write_DMA15_CURR_DESC_PTR(val) 	bfin_write32(DMA15_CURR_DESC_PTR)
+#define bfin_write_DMA15_CURR_DESC_PTR(val) 	bfin_write32(DMA15_CURR_DESC_PTR, val)
 #define bfin_read_DMA15_CURR_ADDR() 		bfin_read32(DMA15_CURR_ADDR)
-#define bfin_write_DMA15_CURR_ADDR(val) 	bfin_write32(DMA15_CURR_ADDR)
+#define bfin_write_DMA15_CURR_ADDR(val) 	bfin_write32(DMA15_CURR_ADDR, val)
 #define bfin_read_DMA15_IRQ_STATUS()		bfin_read16(DMA15_IRQ_STATUS)
 #define bfin_write_DMA15_IRQ_STATUS(val)	bfin_write16(DMA15_IRQ_STATUS, val)
 #define bfin_read_DMA15_PERIPHERAL_MAP()	bfin_read16(DMA15_PERIPHERAL_MAP)
@@ -1362,23 +1358,23 @@
 /* DMA Channel 16 Registers */
 
 #define bfin_read_DMA16_NEXT_DESC_PTR() 	bfin_read32(DMA16_NEXT_DESC_PTR)
-#define bfin_write_DMA16_NEXT_DESC_PTR(val) 	bfin_write32(DMA16_NEXT_DESC_PTR)
+#define bfin_write_DMA16_NEXT_DESC_PTR(val) 	bfin_write32(DMA16_NEXT_DESC_PTR, val)
 #define bfin_read_DMA16_START_ADDR() 		bfin_read32(DMA16_START_ADDR)
-#define bfin_write_DMA16_START_ADDR(val) 	bfin_write32(DMA16_START_ADDR)
+#define bfin_write_DMA16_START_ADDR(val) 	bfin_write32(DMA16_START_ADDR, val)
 #define bfin_read_DMA16_CONFIG()		bfin_read16(DMA16_CONFIG)
 #define bfin_write_DMA16_CONFIG(val)		bfin_write16(DMA16_CONFIG, val)
 #define bfin_read_DMA16_X_COUNT()		bfin_read16(DMA16_X_COUNT)
 #define bfin_write_DMA16_X_COUNT(val)		bfin_write16(DMA16_X_COUNT, val)
 #define bfin_read_DMA16_X_MODIFY()		bfin_read16(DMA16_X_MODIFY)
-#define bfin_write_DMA16_X_MODIFY(val) 		bfin_write16(DMA16_X_MODIFY)
+#define bfin_write_DMA16_X_MODIFY(val) 		bfin_write16(DMA16_X_MODIFY, val)
 #define bfin_read_DMA16_Y_COUNT()		bfin_read16(DMA16_Y_COUNT)
 #define bfin_write_DMA16_Y_COUNT(val)		bfin_write16(DMA16_Y_COUNT, val)
 #define bfin_read_DMA16_Y_MODIFY()		bfin_read16(DMA16_Y_MODIFY)
-#define bfin_write_DMA16_Y_MODIFY(val) 		bfin_write16(DMA16_Y_MODIFY)
+#define bfin_write_DMA16_Y_MODIFY(val) 		bfin_write16(DMA16_Y_MODIFY, val)
 #define bfin_read_DMA16_CURR_DESC_PTR() 	bfin_read32(DMA16_CURR_DESC_PTR)
-#define bfin_write_DMA16_CURR_DESC_PTR(val) 	bfin_write32(DMA16_CURR_DESC_PTR)
+#define bfin_write_DMA16_CURR_DESC_PTR(val) 	bfin_write32(DMA16_CURR_DESC_PTR, val)
 #define bfin_read_DMA16_CURR_ADDR() 		bfin_read32(DMA16_CURR_ADDR)
-#define bfin_write_DMA16_CURR_ADDR(val) 	bfin_write32(DMA16_CURR_ADDR)
+#define bfin_write_DMA16_CURR_ADDR(val) 	bfin_write32(DMA16_CURR_ADDR, val)
 #define bfin_read_DMA16_IRQ_STATUS()		bfin_read16(DMA16_IRQ_STATUS)
 #define bfin_write_DMA16_IRQ_STATUS(val)	bfin_write16(DMA16_IRQ_STATUS, val)
 #define bfin_read_DMA16_PERIPHERAL_MAP()	bfin_read16(DMA16_PERIPHERAL_MAP)
@@ -1391,23 +1387,23 @@
 /* DMA Channel 17 Registers */
 
 #define bfin_read_DMA17_NEXT_DESC_PTR() 	bfin_read32(DMA17_NEXT_DESC_PTR)
-#define bfin_write_DMA17_NEXT_DESC_PTR(val) 	bfin_write32(DMA17_NEXT_DESC_PTR)
+#define bfin_write_DMA17_NEXT_DESC_PTR(val) 	bfin_write32(DMA17_NEXT_DESC_PTR, val)
 #define bfin_read_DMA17_START_ADDR() 		bfin_read32(DMA17_START_ADDR)
-#define bfin_write_DMA17_START_ADDR(val) 	bfin_write32(DMA17_START_ADDR)
+#define bfin_write_DMA17_START_ADDR(val) 	bfin_write32(DMA17_START_ADDR, val)
 #define bfin_read_DMA17_CONFIG()		bfin_read16(DMA17_CONFIG)
 #define bfin_write_DMA17_CONFIG(val)		bfin_write16(DMA17_CONFIG, val)
 #define bfin_read_DMA17_X_COUNT()		bfin_read16(DMA17_X_COUNT)
 #define bfin_write_DMA17_X_COUNT(val)		bfin_write16(DMA17_X_COUNT, val)
 #define bfin_read_DMA17_X_MODIFY()		bfin_read16(DMA17_X_MODIFY)
-#define bfin_write_DMA17_X_MODIFY(val) 		bfin_write16(DMA17_X_MODIFY)
+#define bfin_write_DMA17_X_MODIFY(val) 		bfin_write16(DMA17_X_MODIFY, val)
 #define bfin_read_DMA17_Y_COUNT()		bfin_read16(DMA17_Y_COUNT)
 #define bfin_write_DMA17_Y_COUNT(val)		bfin_write16(DMA17_Y_COUNT, val)
 #define bfin_read_DMA17_Y_MODIFY()		bfin_read16(DMA17_Y_MODIFY)
-#define bfin_write_DMA17_Y_MODIFY(val) 		bfin_write16(DMA17_Y_MODIFY)
+#define bfin_write_DMA17_Y_MODIFY(val) 		bfin_write16(DMA17_Y_MODIFY, val)
 #define bfin_read_DMA17_CURR_DESC_PTR() 	bfin_read32(DMA17_CURR_DESC_PTR)
-#define bfin_write_DMA17_CURR_DESC_PTR(val) 	bfin_write32(DMA17_CURR_DESC_PTR)
+#define bfin_write_DMA17_CURR_DESC_PTR(val) 	bfin_write32(DMA17_CURR_DESC_PTR, val)
 #define bfin_read_DMA17_CURR_ADDR() 		bfin_read32(DMA17_CURR_ADDR)
-#define bfin_write_DMA17_CURR_ADDR(val) 	bfin_write32(DMA17_CURR_ADDR)
+#define bfin_write_DMA17_CURR_ADDR(val) 	bfin_write32(DMA17_CURR_ADDR, val)
 #define bfin_read_DMA17_IRQ_STATUS()		bfin_read16(DMA17_IRQ_STATUS)
 #define bfin_write_DMA17_IRQ_STATUS(val)	bfin_write16(DMA17_IRQ_STATUS, val)
 #define bfin_read_DMA17_PERIPHERAL_MAP()	bfin_read16(DMA17_PERIPHERAL_MAP)
@@ -1420,23 +1416,23 @@
 /* DMA Channel 18 Registers */
 
 #define bfin_read_DMA18_NEXT_DESC_PTR() 	bfin_read32(DMA18_NEXT_DESC_PTR)
-#define bfin_write_DMA18_NEXT_DESC_PTR(val) 	bfin_write32(DMA18_NEXT_DESC_PTR)
+#define bfin_write_DMA18_NEXT_DESC_PTR(val) 	bfin_write32(DMA18_NEXT_DESC_PTR, val)
 #define bfin_read_DMA18_START_ADDR() 		bfin_read32(DMA18_START_ADDR)
-#define bfin_write_DMA18_START_ADDR(val) 	bfin_write32(DMA18_START_ADDR)
+#define bfin_write_DMA18_START_ADDR(val) 	bfin_write32(DMA18_START_ADDR, val)
 #define bfin_read_DMA18_CONFIG()		bfin_read16(DMA18_CONFIG)
 #define bfin_write_DMA18_CONFIG(val)		bfin_write16(DMA18_CONFIG, val)
 #define bfin_read_DMA18_X_COUNT()		bfin_read16(DMA18_X_COUNT)
 #define bfin_write_DMA18_X_COUNT(val)		bfin_write16(DMA18_X_COUNT, val)
 #define bfin_read_DMA18_X_MODIFY()		bfin_read16(DMA18_X_MODIFY)
-#define bfin_write_DMA18_X_MODIFY(val) 		bfin_write16(DMA18_X_MODIFY)
+#define bfin_write_DMA18_X_MODIFY(val) 		bfin_write16(DMA18_X_MODIFY, val)
 #define bfin_read_DMA18_Y_COUNT()		bfin_read16(DMA18_Y_COUNT)
 #define bfin_write_DMA18_Y_COUNT(val)		bfin_write16(DMA18_Y_COUNT, val)
 #define bfin_read_DMA18_Y_MODIFY()		bfin_read16(DMA18_Y_MODIFY)
-#define bfin_write_DMA18_Y_MODIFY(val) 		bfin_write16(DMA18_Y_MODIFY)
+#define bfin_write_DMA18_Y_MODIFY(val) 		bfin_write16(DMA18_Y_MODIFY, val)
 #define bfin_read_DMA18_CURR_DESC_PTR() 	bfin_read32(DMA18_CURR_DESC_PTR)
-#define bfin_write_DMA18_CURR_DESC_PTR(val) 	bfin_write32(DMA18_CURR_DESC_PTR)
+#define bfin_write_DMA18_CURR_DESC_PTR(val) 	bfin_write32(DMA18_CURR_DESC_PTR, val)
 #define bfin_read_DMA18_CURR_ADDR() 		bfin_read32(DMA18_CURR_ADDR)
-#define bfin_write_DMA18_CURR_ADDR(val) 	bfin_write32(DMA18_CURR_ADDR)
+#define bfin_write_DMA18_CURR_ADDR(val) 	bfin_write32(DMA18_CURR_ADDR, val)
 #define bfin_read_DMA18_IRQ_STATUS()		bfin_read16(DMA18_IRQ_STATUS)
 #define bfin_write_DMA18_IRQ_STATUS(val)	bfin_write16(DMA18_IRQ_STATUS, val)
 #define bfin_read_DMA18_PERIPHERAL_MAP()	bfin_read16(DMA18_PERIPHERAL_MAP)
@@ -1449,23 +1445,23 @@
 /* DMA Channel 19 Registers */
 
 #define bfin_read_DMA19_NEXT_DESC_PTR() 	bfin_read32(DMA19_NEXT_DESC_PTR)
-#define bfin_write_DMA19_NEXT_DESC_PTR(val) 	bfin_write32(DMA19_NEXT_DESC_PTR)
+#define bfin_write_DMA19_NEXT_DESC_PTR(val) 	bfin_write32(DMA19_NEXT_DESC_PTR, val)
 #define bfin_read_DMA19_START_ADDR() 		bfin_read32(DMA19_START_ADDR)
-#define bfin_write_DMA19_START_ADDR(val) 	bfin_write32(DMA19_START_ADDR)
+#define bfin_write_DMA19_START_ADDR(val) 	bfin_write32(DMA19_START_ADDR, val)
 #define bfin_read_DMA19_CONFIG()		bfin_read16(DMA19_CONFIG)
 #define bfin_write_DMA19_CONFIG(val)		bfin_write16(DMA19_CONFIG, val)
 #define bfin_read_DMA19_X_COUNT()		bfin_read16(DMA19_X_COUNT)
 #define bfin_write_DMA19_X_COUNT(val)		bfin_write16(DMA19_X_COUNT, val)
 #define bfin_read_DMA19_X_MODIFY()		bfin_read16(DMA19_X_MODIFY)
-#define bfin_write_DMA19_X_MODIFY(val) 		bfin_write16(DMA19_X_MODIFY)
+#define bfin_write_DMA19_X_MODIFY(val) 		bfin_write16(DMA19_X_MODIFY, val)
 #define bfin_read_DMA19_Y_COUNT()		bfin_read16(DMA19_Y_COUNT)
 #define bfin_write_DMA19_Y_COUNT(val)		bfin_write16(DMA19_Y_COUNT, val)
 #define bfin_read_DMA19_Y_MODIFY()		bfin_read16(DMA19_Y_MODIFY)
-#define bfin_write_DMA19_Y_MODIFY(val) 		bfin_write16(DMA19_Y_MODIFY)
+#define bfin_write_DMA19_Y_MODIFY(val) 		bfin_write16(DMA19_Y_MODIFY, val)
 #define bfin_read_DMA19_CURR_DESC_PTR() 	bfin_read32(DMA19_CURR_DESC_PTR)
-#define bfin_write_DMA19_CURR_DESC_PTR(val) 	bfin_write32(DMA19_CURR_DESC_PTR)
+#define bfin_write_DMA19_CURR_DESC_PTR(val) 	bfin_write32(DMA19_CURR_DESC_PTR, val)
 #define bfin_read_DMA19_CURR_ADDR() 		bfin_read32(DMA19_CURR_ADDR)
-#define bfin_write_DMA19_CURR_ADDR(val) 	bfin_write32(DMA19_CURR_ADDR)
+#define bfin_write_DMA19_CURR_ADDR(val) 	bfin_write32(DMA19_CURR_ADDR, val)
 #define bfin_read_DMA19_IRQ_STATUS()		bfin_read16(DMA19_IRQ_STATUS)
 #define bfin_write_DMA19_IRQ_STATUS(val)	bfin_write16(DMA19_IRQ_STATUS, val)
 #define bfin_read_DMA19_PERIPHERAL_MAP()	bfin_read16(DMA19_PERIPHERAL_MAP)
@@ -1478,23 +1474,23 @@
 /* DMA Channel 20 Registers */
 
 #define bfin_read_DMA20_NEXT_DESC_PTR() 	bfin_read32(DMA20_NEXT_DESC_PTR)
-#define bfin_write_DMA20_NEXT_DESC_PTR(val) 	bfin_write32(DMA20_NEXT_DESC_PTR)
+#define bfin_write_DMA20_NEXT_DESC_PTR(val) 	bfin_write32(DMA20_NEXT_DESC_PTR, val)
 #define bfin_read_DMA20_START_ADDR() 		bfin_read32(DMA20_START_ADDR)
-#define bfin_write_DMA20_START_ADDR(val) 	bfin_write32(DMA20_START_ADDR)
+#define bfin_write_DMA20_START_ADDR(val) 	bfin_write32(DMA20_START_ADDR, val)
 #define bfin_read_DMA20_CONFIG()		bfin_read16(DMA20_CONFIG)
 #define bfin_write_DMA20_CONFIG(val)		bfin_write16(DMA20_CONFIG, val)
 #define bfin_read_DMA20_X_COUNT()		bfin_read16(DMA20_X_COUNT)
 #define bfin_write_DMA20_X_COUNT(val)		bfin_write16(DMA20_X_COUNT, val)
 #define bfin_read_DMA20_X_MODIFY()		bfin_read16(DMA20_X_MODIFY)
-#define bfin_write_DMA20_X_MODIFY(val) 		bfin_write16(DMA20_X_MODIFY)
+#define bfin_write_DMA20_X_MODIFY(val) 		bfin_write16(DMA20_X_MODIFY, val)
 #define bfin_read_DMA20_Y_COUNT()		bfin_read16(DMA20_Y_COUNT)
 #define bfin_write_DMA20_Y_COUNT(val)		bfin_write16(DMA20_Y_COUNT, val)
 #define bfin_read_DMA20_Y_MODIFY()		bfin_read16(DMA20_Y_MODIFY)
-#define bfin_write_DMA20_Y_MODIFY(val) 		bfin_write16(DMA20_Y_MODIFY)
+#define bfin_write_DMA20_Y_MODIFY(val) 		bfin_write16(DMA20_Y_MODIFY, val)
 #define bfin_read_DMA20_CURR_DESC_PTR() 	bfin_read32(DMA20_CURR_DESC_PTR)
-#define bfin_write_DMA20_CURR_DESC_PTR(val) 	bfin_write32(DMA20_CURR_DESC_PTR)
+#define bfin_write_DMA20_CURR_DESC_PTR(val) 	bfin_write32(DMA20_CURR_DESC_PTR, val)
 #define bfin_read_DMA20_CURR_ADDR() 		bfin_read32(DMA20_CURR_ADDR)
-#define bfin_write_DMA20_CURR_ADDR(val) 	bfin_write32(DMA20_CURR_ADDR)
+#define bfin_write_DMA20_CURR_ADDR(val) 	bfin_write32(DMA20_CURR_ADDR, val)
 #define bfin_read_DMA20_IRQ_STATUS()		bfin_read16(DMA20_IRQ_STATUS)
 #define bfin_write_DMA20_IRQ_STATUS(val)	bfin_write16(DMA20_IRQ_STATUS, val)
 #define bfin_read_DMA20_PERIPHERAL_MAP()	bfin_read16(DMA20_PERIPHERAL_MAP)
@@ -1507,23 +1503,23 @@
 /* DMA Channel 21 Registers */
 
 #define bfin_read_DMA21_NEXT_DESC_PTR() 	bfin_read32(DMA21_NEXT_DESC_PTR)
-#define bfin_write_DMA21_NEXT_DESC_PTR(val) 	bfin_write32(DMA21_NEXT_DESC_PTR)
+#define bfin_write_DMA21_NEXT_DESC_PTR(val) 	bfin_write32(DMA21_NEXT_DESC_PTR, val)
 #define bfin_read_DMA21_START_ADDR() 		bfin_read32(DMA21_START_ADDR)
-#define bfin_write_DMA21_START_ADDR(val) 	bfin_write32(DMA21_START_ADDR)
+#define bfin_write_DMA21_START_ADDR(val) 	bfin_write32(DMA21_START_ADDR, val)
 #define bfin_read_DMA21_CONFIG()		bfin_read16(DMA21_CONFIG)
 #define bfin_write_DMA21_CONFIG(val)		bfin_write16(DMA21_CONFIG, val)
 #define bfin_read_DMA21_X_COUNT()		bfin_read16(DMA21_X_COUNT)
 #define bfin_write_DMA21_X_COUNT(val)		bfin_write16(DMA21_X_COUNT, val)
 #define bfin_read_DMA21_X_MODIFY()		bfin_read16(DMA21_X_MODIFY)
-#define bfin_write_DMA21_X_MODIFY(val) 		bfin_write16(DMA21_X_MODIFY)
+#define bfin_write_DMA21_X_MODIFY(val) 		bfin_write16(DMA21_X_MODIFY, val)
 #define bfin_read_DMA21_Y_COUNT()		bfin_read16(DMA21_Y_COUNT)
 #define bfin_write_DMA21_Y_COUNT(val)		bfin_write16(DMA21_Y_COUNT, val)
 #define bfin_read_DMA21_Y_MODIFY()		bfin_read16(DMA21_Y_MODIFY)
-#define bfin_write_DMA21_Y_MODIFY(val) 		bfin_write16(DMA21_Y_MODIFY)
+#define bfin_write_DMA21_Y_MODIFY(val) 		bfin_write16(DMA21_Y_MODIFY, val)
 #define bfin_read_DMA21_CURR_DESC_PTR() 	bfin_read32(DMA21_CURR_DESC_PTR)
-#define bfin_write_DMA21_CURR_DESC_PTR(val) 	bfin_write32(DMA21_CURR_DESC_PTR)
+#define bfin_write_DMA21_CURR_DESC_PTR(val) 	bfin_write32(DMA21_CURR_DESC_PTR, val)
 #define bfin_read_DMA21_CURR_ADDR() 		bfin_read32(DMA21_CURR_ADDR)
-#define bfin_write_DMA21_CURR_ADDR(val) 	bfin_write32(DMA21_CURR_ADDR)
+#define bfin_write_DMA21_CURR_ADDR(val) 	bfin_write32(DMA21_CURR_ADDR, val)
 #define bfin_read_DMA21_IRQ_STATUS()		bfin_read16(DMA21_IRQ_STATUS)
 #define bfin_write_DMA21_IRQ_STATUS(val)	bfin_write16(DMA21_IRQ_STATUS, val)
 #define bfin_read_DMA21_PERIPHERAL_MAP()	bfin_read16(DMA21_PERIPHERAL_MAP)
@@ -1536,23 +1532,23 @@
 /* DMA Channel 22 Registers */
 
 #define bfin_read_DMA22_NEXT_DESC_PTR() 	bfin_read32(DMA22_NEXT_DESC_PTR)
-#define bfin_write_DMA22_NEXT_DESC_PTR(val) 	bfin_write32(DMA22_NEXT_DESC_PTR)
+#define bfin_write_DMA22_NEXT_DESC_PTR(val) 	bfin_write32(DMA22_NEXT_DESC_PTR, val)
 #define bfin_read_DMA22_START_ADDR() 		bfin_read32(DMA22_START_ADDR)
-#define bfin_write_DMA22_START_ADDR(val) 	bfin_write32(DMA22_START_ADDR)
+#define bfin_write_DMA22_START_ADDR(val) 	bfin_write32(DMA22_START_ADDR, val)
 #define bfin_read_DMA22_CONFIG()		bfin_read16(DMA22_CONFIG)
 #define bfin_write_DMA22_CONFIG(val)		bfin_write16(DMA22_CONFIG, val)
 #define bfin_read_DMA22_X_COUNT()		bfin_read16(DMA22_X_COUNT)
 #define bfin_write_DMA22_X_COUNT(val)		bfin_write16(DMA22_X_COUNT, val)
 #define bfin_read_DMA22_X_MODIFY()		bfin_read16(DMA22_X_MODIFY)
-#define bfin_write_DMA22_X_MODIFY(val) 		bfin_write16(DMA22_X_MODIFY)
+#define bfin_write_DMA22_X_MODIFY(val) 		bfin_write16(DMA22_X_MODIFY, val)
 #define bfin_read_DMA22_Y_COUNT()		bfin_read16(DMA22_Y_COUNT)
 #define bfin_write_DMA22_Y_COUNT(val)		bfin_write16(DMA22_Y_COUNT, val)
 #define bfin_read_DMA22_Y_MODIFY()		bfin_read16(DMA22_Y_MODIFY)
-#define bfin_write_DMA22_Y_MODIFY(val) 		bfin_write16(DMA22_Y_MODIFY)
+#define bfin_write_DMA22_Y_MODIFY(val) 		bfin_write16(DMA22_Y_MODIFY, val)
 #define bfin_read_DMA22_CURR_DESC_PTR() 	bfin_read32(DMA22_CURR_DESC_PTR)
-#define bfin_write_DMA22_CURR_DESC_PTR(val) 	bfin_write32(DMA22_CURR_DESC_PTR)
+#define bfin_write_DMA22_CURR_DESC_PTR(val) 	bfin_write32(DMA22_CURR_DESC_PTR, val)
 #define bfin_read_DMA22_CURR_ADDR() 		bfin_read32(DMA22_CURR_ADDR)
-#define bfin_write_DMA22_CURR_ADDR(val) 	bfin_write32(DMA22_CURR_ADDR)
+#define bfin_write_DMA22_CURR_ADDR(val) 	bfin_write32(DMA22_CURR_ADDR, val)
 #define bfin_read_DMA22_IRQ_STATUS()		bfin_read16(DMA22_IRQ_STATUS)
 #define bfin_write_DMA22_IRQ_STATUS(val)	bfin_write16(DMA22_IRQ_STATUS, val)
 #define bfin_read_DMA22_PERIPHERAL_MAP()	bfin_read16(DMA22_PERIPHERAL_MAP)
@@ -1565,23 +1561,23 @@
 /* DMA Channel 23 Registers */
 
 #define bfin_read_DMA23_NEXT_DESC_PTR() 		bfin_read32(DMA23_NEXT_DESC_PTR)
-#define bfin_write_DMA23_NEXT_DESC_PTR(val) 		bfin_write32(DMA23_NEXT_DESC_PTR)
+#define bfin_write_DMA23_NEXT_DESC_PTR(val) 		bfin_write32(DMA23_NEXT_DESC_PTR, val)
 #define bfin_read_DMA23_START_ADDR() 			bfin_read32(DMA23_START_ADDR)
-#define bfin_write_DMA23_START_ADDR(val) 		bfin_write32(DMA23_START_ADDR)
+#define bfin_write_DMA23_START_ADDR(val) 		bfin_write32(DMA23_START_ADDR, val)
 #define bfin_read_DMA23_CONFIG()			bfin_read16(DMA23_CONFIG)
 #define bfin_write_DMA23_CONFIG(val)			bfin_write16(DMA23_CONFIG, val)
 #define bfin_read_DMA23_X_COUNT()			bfin_read16(DMA23_X_COUNT)
 #define bfin_write_DMA23_X_COUNT(val)			bfin_write16(DMA23_X_COUNT, val)
 #define bfin_read_DMA23_X_MODIFY()			bfin_read16(DMA23_X_MODIFY)
-#define bfin_write_DMA23_X_MODIFY(val) 			bfin_write16(DMA23_X_MODIFY)
+#define bfin_write_DMA23_X_MODIFY(val) 			bfin_write16(DMA23_X_MODIFY, val)
 #define bfin_read_DMA23_Y_COUNT()			bfin_read16(DMA23_Y_COUNT)
 #define bfin_write_DMA23_Y_COUNT(val)			bfin_write16(DMA23_Y_COUNT, val)
 #define bfin_read_DMA23_Y_MODIFY()			bfin_read16(DMA23_Y_MODIFY)
-#define bfin_write_DMA23_Y_MODIFY(val) 			bfin_write16(DMA23_Y_MODIFY)
+#define bfin_write_DMA23_Y_MODIFY(val) 			bfin_write16(DMA23_Y_MODIFY, val)
 #define bfin_read_DMA23_CURR_DESC_PTR() 		bfin_read32(DMA23_CURR_DESC_PTR)
-#define bfin_write_DMA23_CURR_DESC_PTR(val) 		bfin_write32(DMA23_CURR_DESC_PTR)
+#define bfin_write_DMA23_CURR_DESC_PTR(val) 		bfin_write32(DMA23_CURR_DESC_PTR, val)
 #define bfin_read_DMA23_CURR_ADDR() 			bfin_read32(DMA23_CURR_ADDR)
-#define bfin_write_DMA23_CURR_ADDR(val) 		bfin_write32(DMA23_CURR_ADDR)
+#define bfin_write_DMA23_CURR_ADDR(val) 		bfin_write32(DMA23_CURR_ADDR, val)
 #define bfin_read_DMA23_IRQ_STATUS()			bfin_read16(DMA23_IRQ_STATUS)
 #define bfin_write_DMA23_IRQ_STATUS(val)		bfin_write16(DMA23_IRQ_STATUS, val)
 #define bfin_read_DMA23_PERIPHERAL_MAP()		bfin_read16(DMA23_PERIPHERAL_MAP)
@@ -1594,23 +1590,23 @@
 /* MDMA Stream 2 Registers */
 
 #define bfin_read_MDMA_D2_NEXT_DESC_PTR() 		bfin_read32(MDMA_D2_NEXT_DESC_PTR)
-#define bfin_write_MDMA_D2_NEXT_DESC_PTR(val) 		bfin_write32(MDMA_D2_NEXT_DESC_PTR)
+#define bfin_write_MDMA_D2_NEXT_DESC_PTR(val) 		bfin_write32(MDMA_D2_NEXT_DESC_PTR, val)
 #define bfin_read_MDMA_D2_START_ADDR() 			bfin_read32(MDMA_D2_START_ADDR)
-#define bfin_write_MDMA_D2_START_ADDR(val) 		bfin_write32(MDMA_D2_START_ADDR)
+#define bfin_write_MDMA_D2_START_ADDR(val) 		bfin_write32(MDMA_D2_START_ADDR, val)
 #define bfin_read_MDMA_D2_CONFIG()			bfin_read16(MDMA_D2_CONFIG)
 #define bfin_write_MDMA_D2_CONFIG(val)			bfin_write16(MDMA_D2_CONFIG, val)
 #define bfin_read_MDMA_D2_X_COUNT()			bfin_read16(MDMA_D2_X_COUNT)
 #define bfin_write_MDMA_D2_X_COUNT(val)			bfin_write16(MDMA_D2_X_COUNT, val)
 #define bfin_read_MDMA_D2_X_MODIFY()			bfin_read16(MDMA_D2_X_MODIFY)
-#define bfin_write_MDMA_D2_X_MODIFY(val) 		bfin_write16(MDMA_D2_X_MODIFY)
+#define bfin_write_MDMA_D2_X_MODIFY(val) 		bfin_write16(MDMA_D2_X_MODIFY, val)
 #define bfin_read_MDMA_D2_Y_COUNT()			bfin_read16(MDMA_D2_Y_COUNT)
 #define bfin_write_MDMA_D2_Y_COUNT(val)			bfin_write16(MDMA_D2_Y_COUNT, val)
 #define bfin_read_MDMA_D2_Y_MODIFY()			bfin_read16(MDMA_D2_Y_MODIFY)
-#define bfin_write_MDMA_D2_Y_MODIFY(val) 		bfin_write16(MDMA_D2_Y_MODIFY)
+#define bfin_write_MDMA_D2_Y_MODIFY(val) 		bfin_write16(MDMA_D2_Y_MODIFY, val)
 #define bfin_read_MDMA_D2_CURR_DESC_PTR() 		bfin_read32(MDMA_D2_CURR_DESC_PTR)
-#define bfin_write_MDMA_D2_CURR_DESC_PTR(val) 		bfin_write32(MDMA_D2_CURR_DESC_PTR)
+#define bfin_write_MDMA_D2_CURR_DESC_PTR(val) 		bfin_write32(MDMA_D2_CURR_DESC_PTR, val)
 #define bfin_read_MDMA_D2_CURR_ADDR() 			bfin_read32(MDMA_D2_CURR_ADDR)
-#define bfin_write_MDMA_D2_CURR_ADDR(val) 		bfin_write32(MDMA_D2_CURR_ADDR)
+#define bfin_write_MDMA_D2_CURR_ADDR(val) 		bfin_write32(MDMA_D2_CURR_ADDR, val)
 #define bfin_read_MDMA_D2_IRQ_STATUS()			bfin_read16(MDMA_D2_IRQ_STATUS)
 #define bfin_write_MDMA_D2_IRQ_STATUS(val)		bfin_write16(MDMA_D2_IRQ_STATUS, val)
 #define bfin_read_MDMA_D2_PERIPHERAL_MAP()		bfin_read16(MDMA_D2_PERIPHERAL_MAP)
@@ -1620,23 +1616,23 @@
 #define bfin_read_MDMA_D2_CURR_Y_COUNT()		bfin_read16(MDMA_D2_CURR_Y_COUNT)
 #define bfin_write_MDMA_D2_CURR_Y_COUNT(val)		bfin_write16(MDMA_D2_CURR_Y_COUNT, val)
 #define bfin_read_MDMA_S2_NEXT_DESC_PTR() 		bfin_read32(MDMA_S2_NEXT_DESC_PTR)
-#define bfin_write_MDMA_S2_NEXT_DESC_PTR(val) 		bfin_write32(MDMA_S2_NEXT_DESC_PTR)
+#define bfin_write_MDMA_S2_NEXT_DESC_PTR(val) 		bfin_write32(MDMA_S2_NEXT_DESC_PTR, val)
 #define bfin_read_MDMA_S2_START_ADDR() 			bfin_read32(MDMA_S2_START_ADDR)
-#define bfin_write_MDMA_S2_START_ADDR(val) 		bfin_write32(MDMA_S2_START_ADDR)
+#define bfin_write_MDMA_S2_START_ADDR(val) 		bfin_write32(MDMA_S2_START_ADDR, val)
 #define bfin_read_MDMA_S2_CONFIG()			bfin_read16(MDMA_S2_CONFIG)
 #define bfin_write_MDMA_S2_CONFIG(val)			bfin_write16(MDMA_S2_CONFIG, val)
 #define bfin_read_MDMA_S2_X_COUNT()			bfin_read16(MDMA_S2_X_COUNT)
 #define bfin_write_MDMA_S2_X_COUNT(val)			bfin_write16(MDMA_S2_X_COUNT, val)
 #define bfin_read_MDMA_S2_X_MODIFY()			bfin_read16(MDMA_S2_X_MODIFY)
-#define bfin_write_MDMA_S2_X_MODIFY(val) 		bfin_write16(MDMA_S2_X_MODIFY)
+#define bfin_write_MDMA_S2_X_MODIFY(val) 		bfin_write16(MDMA_S2_X_MODIFY, val)
 #define bfin_read_MDMA_S2_Y_COUNT()			bfin_read16(MDMA_S2_Y_COUNT)
 #define bfin_write_MDMA_S2_Y_COUNT(val)			bfin_write16(MDMA_S2_Y_COUNT, val)
 #define bfin_read_MDMA_S2_Y_MODIFY()			bfin_read16(MDMA_S2_Y_MODIFY)
-#define bfin_write_MDMA_S2_Y_MODIFY(val) 		bfin_write16(MDMA_S2_Y_MODIFY)
+#define bfin_write_MDMA_S2_Y_MODIFY(val) 		bfin_write16(MDMA_S2_Y_MODIFY, val)
 #define bfin_read_MDMA_S2_CURR_DESC_PTR() 		bfin_read32(MDMA_S2_CURR_DESC_PTR)
-#define bfin_write_MDMA_S2_CURR_DESC_PTR(val) 		bfin_write32(MDMA_S2_CURR_DESC_PTR)
+#define bfin_write_MDMA_S2_CURR_DESC_PTR(val) 		bfin_write32(MDMA_S2_CURR_DESC_PTR, val)
 #define bfin_read_MDMA_S2_CURR_ADDR() 			bfin_read32(MDMA_S2_CURR_ADDR)
-#define bfin_write_MDMA_S2_CURR_ADDR(val) 		bfin_write32(MDMA_S2_CURR_ADDR)
+#define bfin_write_MDMA_S2_CURR_ADDR(val) 		bfin_write32(MDMA_S2_CURR_ADDR, val)
 #define bfin_read_MDMA_S2_IRQ_STATUS()			bfin_read16(MDMA_S2_IRQ_STATUS)
 #define bfin_write_MDMA_S2_IRQ_STATUS(val)		bfin_write16(MDMA_S2_IRQ_STATUS, val)
 #define bfin_read_MDMA_S2_PERIPHERAL_MAP()		bfin_read16(MDMA_S2_PERIPHERAL_MAP)
@@ -1649,23 +1645,23 @@
 /* MDMA Stream 3 Registers */
 
 #define bfin_read_MDMA_D3_NEXT_DESC_PTR() 		bfin_read32(MDMA_D3_NEXT_DESC_PTR)
-#define bfin_write_MDMA_D3_NEXT_DESC_PTR(val) 		bfin_write32(MDMA_D3_NEXT_DESC_PTR)
+#define bfin_write_MDMA_D3_NEXT_DESC_PTR(val) 		bfin_write32(MDMA_D3_NEXT_DESC_PTR, val)
 #define bfin_read_MDMA_D3_START_ADDR() 			bfin_read32(MDMA_D3_START_ADDR)
-#define bfin_write_MDMA_D3_START_ADDR(val) 		bfin_write32(MDMA_D3_START_ADDR)
+#define bfin_write_MDMA_D3_START_ADDR(val) 		bfin_write32(MDMA_D3_START_ADDR, val)
 #define bfin_read_MDMA_D3_CONFIG()			bfin_read16(MDMA_D3_CONFIG)
 #define bfin_write_MDMA_D3_CONFIG(val)			bfin_write16(MDMA_D3_CONFIG, val)
 #define bfin_read_MDMA_D3_X_COUNT()			bfin_read16(MDMA_D3_X_COUNT)
 #define bfin_write_MDMA_D3_X_COUNT(val)			bfin_write16(MDMA_D3_X_COUNT, val)
 #define bfin_read_MDMA_D3_X_MODIFY()			bfin_read16(MDMA_D3_X_MODIFY)
-#define bfin_write_MDMA_D3_X_MODIFY(val) 		bfin_write16(MDMA_D3_X_MODIFY)
+#define bfin_write_MDMA_D3_X_MODIFY(val) 		bfin_write16(MDMA_D3_X_MODIFY, val)
 #define bfin_read_MDMA_D3_Y_COUNT()			bfin_read16(MDMA_D3_Y_COUNT)
 #define bfin_write_MDMA_D3_Y_COUNT(val)			bfin_write16(MDMA_D3_Y_COUNT, val)
 #define bfin_read_MDMA_D3_Y_MODIFY()			bfin_read16(MDMA_D3_Y_MODIFY)
-#define bfin_write_MDMA_D3_Y_MODIFY(val) 		bfin_write16(MDMA_D3_Y_MODIFY)
+#define bfin_write_MDMA_D3_Y_MODIFY(val) 		bfin_write16(MDMA_D3_Y_MODIFY, val)
 #define bfin_read_MDMA_D3_CURR_DESC_PTR() 		bfin_read32(MDMA_D3_CURR_DESC_PTR)
-#define bfin_write_MDMA_D3_CURR_DESC_PTR(val) 		bfin_write32(MDMA_D3_CURR_DESC_PTR)
+#define bfin_write_MDMA_D3_CURR_DESC_PTR(val) 		bfin_write32(MDMA_D3_CURR_DESC_PTR, val)
 #define bfin_read_MDMA_D3_CURR_ADDR() 			bfin_read32(MDMA_D3_CURR_ADDR)
-#define bfin_write_MDMA_D3_CURR_ADDR(val) 		bfin_write32(MDMA_D3_CURR_ADDR)
+#define bfin_write_MDMA_D3_CURR_ADDR(val) 		bfin_write32(MDMA_D3_CURR_ADDR, val)
 #define bfin_read_MDMA_D3_IRQ_STATUS()			bfin_read16(MDMA_D3_IRQ_STATUS)
 #define bfin_write_MDMA_D3_IRQ_STATUS(val)		bfin_write16(MDMA_D3_IRQ_STATUS, val)
 #define bfin_read_MDMA_D3_PERIPHERAL_MAP()		bfin_read16(MDMA_D3_PERIPHERAL_MAP)
@@ -1675,23 +1671,23 @@
 #define bfin_read_MDMA_D3_CURR_Y_COUNT()		bfin_read16(MDMA_D3_CURR_Y_COUNT)
 #define bfin_write_MDMA_D3_CURR_Y_COUNT(val)		bfin_write16(MDMA_D3_CURR_Y_COUNT, val)
 #define bfin_read_MDMA_S3_NEXT_DESC_PTR() 		bfin_read32(MDMA_S3_NEXT_DESC_PTR)
-#define bfin_write_MDMA_S3_NEXT_DESC_PTR(val) 		bfin_write32(MDMA_S3_NEXT_DESC_PTR)
+#define bfin_write_MDMA_S3_NEXT_DESC_PTR(val) 		bfin_write32(MDMA_S3_NEXT_DESC_PTR, val)
 #define bfin_read_MDMA_S3_START_ADDR() 			bfin_read32(MDMA_S3_START_ADDR)
-#define bfin_write_MDMA_S3_START_ADDR(val) 		bfin_write32(MDMA_S3_START_ADDR)
+#define bfin_write_MDMA_S3_START_ADDR(val) 		bfin_write32(MDMA_S3_START_ADDR, val)
 #define bfin_read_MDMA_S3_CONFIG()			bfin_read16(MDMA_S3_CONFIG)
 #define bfin_write_MDMA_S3_CONFIG(val)			bfin_write16(MDMA_S3_CONFIG, val)
 #define bfin_read_MDMA_S3_X_COUNT()			bfin_read16(MDMA_S3_X_COUNT)
 #define bfin_write_MDMA_S3_X_COUNT(val)			bfin_write16(MDMA_S3_X_COUNT, val)
 #define bfin_read_MDMA_S3_X_MODIFY()			bfin_read16(MDMA_S3_X_MODIFY)
-#define bfin_write_MDMA_S3_X_MODIFY(val) 		bfin_write16(MDMA_S3_X_MODIFY)
+#define bfin_write_MDMA_S3_X_MODIFY(val) 		bfin_write16(MDMA_S3_X_MODIFY, val)
 #define bfin_read_MDMA_S3_Y_COUNT()			bfin_read16(MDMA_S3_Y_COUNT)
 #define bfin_write_MDMA_S3_Y_COUNT(val)			bfin_write16(MDMA_S3_Y_COUNT, val)
 #define bfin_read_MDMA_S3_Y_MODIFY()			bfin_read16(MDMA_S3_Y_MODIFY)
-#define bfin_write_MDMA_S3_Y_MODIFY(val) 		bfin_write16(MDMA_S3_Y_MODIFY)
+#define bfin_write_MDMA_S3_Y_MODIFY(val) 		bfin_write16(MDMA_S3_Y_MODIFY, val)
 #define bfin_read_MDMA_S3_CURR_DESC_PTR() 		bfin_read32(MDMA_S3_CURR_DESC_PTR)
-#define bfin_write_MDMA_S3_CURR_DESC_PTR(val) 		bfin_write32(MDMA_S3_CURR_DESC_PTR)
+#define bfin_write_MDMA_S3_CURR_DESC_PTR(val) 		bfin_write32(MDMA_S3_CURR_DESC_PTR, val)
 #define bfin_read_MDMA_S3_CURR_ADDR() 			bfin_read32(MDMA_S3_CURR_ADDR)
-#define bfin_write_MDMA_S3_CURR_ADDR(val) 		bfin_write32(MDMA_S3_CURR_ADDR)
+#define bfin_write_MDMA_S3_CURR_ADDR(val) 		bfin_write32(MDMA_S3_CURR_ADDR, val)
 #define bfin_read_MDMA_S3_IRQ_STATUS()			bfin_read16(MDMA_S3_IRQ_STATUS)
 #define bfin_write_MDMA_S3_IRQ_STATUS(val)		bfin_write16(MDMA_S3_IRQ_STATUS, val)
 #define bfin_read_MDMA_S3_PERIPHERAL_MAP()		bfin_read16(MDMA_S3_PERIPHERAL_MAP)
diff --git a/include/asm-blackfin/mach-bf548/dma.h b/include/asm-blackfin/mach-bf548/dma.h
index 46ff31f..36a2ef7 100644
--- a/include/asm-blackfin/mach-bf548/dma.h
+++ b/include/asm-blackfin/mach-bf548/dma.h
@@ -73,6 +73,4 @@
 
 #define MAX_BLACKFIN_DMA_CHANNEL 32
 
-extern int channel2irq(unsigned int channel);
-extern struct dma_register *base_addr[MAX_BLACKFIN_DMA_CHANNEL];
 #endif
diff --git a/include/asm-blackfin/mach-bf548/mem_init.h b/include/asm-blackfin/mach-bf548/mem_init.h
index befc290..ab0b863 100644
--- a/include/asm-blackfin/mach-bf548/mem_init.h
+++ b/include/asm-blackfin/mach-bf548/mem_init.h
@@ -29,16 +29,19 @@
  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 #define MIN_DDR_SCLK(x)	(x*(CONFIG_SCLK_HZ/1000/1000)/1000 + 1)
+#define MAX_DDR_SCLK(x)	(x*(CONFIG_SCLK_HZ/1000/1000)/1000)
+#define DDR_CLK_HZ(x)	(1000*1000*1000/x)
 
 #if (CONFIG_MEM_MT46V32M16_6T)
 #define DDR_SIZE	DEVSZ_512
 #define DDR_WIDTH	DEVWD_16
+#define DDR_MAX_tCK	13
 
 #define DDR_tRC		DDR_TRC(MIN_DDR_SCLK(60))
 #define DDR_tRAS	DDR_TRAS(MIN_DDR_SCLK(42))
 #define DDR_tRP		DDR_TRP(MIN_DDR_SCLK(15))
 #define DDR_tRFC	DDR_TRFC(MIN_DDR_SCLK(72))
-#define DDR_tREFI	DDR_TREFI(MIN_DDR_SCLK(7800))
+#define DDR_tREFI	DDR_TREFI(MAX_DDR_SCLK(7800))
 
 #define DDR_tRCD	DDR_TRCD(MIN_DDR_SCLK(15))
 #define DDR_tWTR	DDR_TWTR(1)
@@ -49,12 +52,13 @@
 #if (CONFIG_MEM_MT46V32M16_5B)
 #define DDR_SIZE	DEVSZ_512
 #define DDR_WIDTH	DEVWD_16
+#define DDR_MAX_tCK	13
 
 #define DDR_tRC		DDR_TRC(MIN_DDR_SCLK(55))
 #define DDR_tRAS	DDR_TRAS(MIN_DDR_SCLK(40))
 #define DDR_tRP		DDR_TRP(MIN_DDR_SCLK(15))
 #define DDR_tRFC	DDR_TRFC(MIN_DDR_SCLK(70))
-#define DDR_tREFI	DDR_TREFI(MIN_DDR_SCLK(7800))
+#define DDR_tREFI	DDR_TREFI(MAX_DDR_SCLK(7800))
 
 #define DDR_tRCD	DDR_TRCD(MIN_DDR_SCLK(15))
 #define DDR_tWTR	DDR_TWTR(2)
@@ -65,6 +69,7 @@
 #if (CONFIG_MEM_GENERIC_BOARD)
 #define DDR_SIZE	DEVSZ_512
 #define DDR_WIDTH	DEVWD_16
+#define DDR_MAX_tCK	13
 
 #define DDR_tRCD	DDR_TRCD(3)
 #define DDR_tWTR	DDR_TWTR(2)
@@ -77,14 +82,15 @@
 #define DDR_tREFI	DDR_TREFI(1288)
 #endif
 
-#if (CONFIG_SCLK_HZ <= 133333333)
-#define	DDR_CL		CL_2
-#elif (CONFIG_SCLK_HZ <= 166666666)
-#define	DDR_CL		CL_2_5
+#if (CONFIG_SCLK_HZ < DDR_CLK_HZ(DDR_MAX_tCK))
+# error "CONFIG_SCLK_HZ is too small (<DDR_CLK_HZ(DDR_MAX_tCK) Hz)."
+#elif(CONFIG_SCLK_HZ <= 133333333)
+# define	DDR_CL		CL_2
 #else
-#define	DDR_CL		CL_3
+# error "CONFIG_SCLK_HZ is too large (>133333333 Hz)."
 #endif
 
+
 #define mem_DDRCTL0	(DDR_tRP | DDR_tRAS | DDR_tRC | DDR_tRFC | DDR_tREFI)
 #define mem_DDRCTL1	(DDR_DATWIDTH | EXTBANK_1 | DDR_SIZE | DDR_WIDTH | DDR_tWTR \
 			| DDR_tMRD | DDR_tWR | DDR_tRCD)
diff --git a/include/asm-blackfin/mach-bf561/anomaly.h b/include/asm-blackfin/mach-bf561/anomaly.h
index 0c1d461..82157ca 100644
--- a/include/asm-blackfin/mach-bf561/anomaly.h
+++ b/include/asm-blackfin/mach-bf561/anomaly.h
@@ -7,7 +7,7 @@
  */
 
 /* This file shoule be up to date with:
- *  - Revision O, 11/15/2007; ADSP-BF561 Blackfin Processor Anomaly List
+ *  - Revision P, 02/08/2008; ADSP-BF561 Blackfin Processor Anomaly List
  */
 
 #ifndef _MACH_ANOMALY_H_
@@ -256,10 +256,14 @@
 #define ANOMALY_05000357 (1)
 /* Conflicting Column Address Widths Causes SDRAM Errors */
 #define ANOMALY_05000362 (1)
+/* UART Break Signal Issues */
+#define ANOMALY_05000363 (__SILICON_REVISION__ < 5)
 /* PPI Underflow Error Goes Undetected in ITU-R 656 Mode */
 #define ANOMALY_05000366 (1)
 /* Possible RETS Register Corruption when Subroutine Is under 5 Cycles in Duration */
 #define ANOMALY_05000371 (1)
+/* Level-Sensitive External GPIO Wakeups May Cause Indefinite Stall */
+#define ANOMALY_05000403 (1)
 
 /* Anomalies that don't exist on this proc */
 #define ANOMALY_05000158 (0)
diff --git a/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
index b6f513b..8a4e66d 100644
--- a/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
+++ b/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
@@ -1,22 +1,38 @@
+/*
+ * file:        include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
+ * based on:
+ * author:
+ *
+ * created:
+ * description:
+ *	blackfin serial driver head file
+ * rev:
+ *
+ * modified:
+ *
+ *
+ * bugs:         enter bugs at http://blackfin.uclinux.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, 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,
+ * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ */
+
 #include <linux/serial.h>
 #include <asm/dma.h>
 #include <asm/portmux.h>
 
-#define NR_PORTS                1
-
-#define OFFSET_THR              0x00	/* Transmit Holding register            */
-#define OFFSET_RBR              0x00	/* Receive Buffer register              */
-#define OFFSET_DLL              0x00	/* Divisor Latch (Low-Byte)             */
-#define OFFSET_IER              0x04	/* Interrupt Enable Register            */
-#define OFFSET_DLH              0x04	/* Divisor Latch (High-Byte)            */
-#define OFFSET_IIR              0x08	/* Interrupt Identification Register    */
-#define OFFSET_LCR              0x0C	/* Line Control Register                */
-#define OFFSET_MCR              0x10	/* Modem Control Register               */
-#define OFFSET_LSR              0x14	/* Line Status Register                 */
-#define OFFSET_MSR              0x18	/* Modem Status Register                */
-#define OFFSET_SCR              0x1C	/* SCR Scratch Register                 */
-#define OFFSET_GCTL             0x24	/* Global Control Register              */
-
 #define UART_GET_CHAR(uart)     bfin_read16(((uart)->port.membase + OFFSET_RBR))
 #define UART_GET_DLL(uart)	bfin_read16(((uart)->port.membase + OFFSET_DLL))
 #define UART_GET_IER(uart)      bfin_read16(((uart)->port.membase + OFFSET_IER))
@@ -84,7 +100,7 @@
 	bfin_write16(uart->port.membase + OFFSET_LSR, -1);
 }
 
-struct bfin_serial_port bfin_serial_ports[NR_PORTS];
+struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
 struct bfin_serial_res {
 	unsigned long	uart_base_addr;
 	int		uart_irq;
@@ -115,7 +131,7 @@
 
 #define DRIVER_NAME "bfin-uart"
 
-int nr_ports = NR_PORTS;
+int nr_ports = BFIN_UART_NR_PORTS;
 static void bfin_serial_hw_init(struct bfin_serial_port *uart)
 {
 
diff --git a/include/asm-blackfin/mach-bf561/bfin_sir.h b/include/asm-blackfin/mach-bf561/bfin_sir.h
new file mode 100644
index 0000000..cefcf8b
--- /dev/null
+++ b/include/asm-blackfin/mach-bf561/bfin_sir.h
@@ -0,0 +1,120 @@
+/*
+ * Blackfin Infra-red Driver
+ *
+ * Copyright 2006-2008 Analog Devices Inc.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ *
+ */
+
+#include <linux/serial.h>
+#include <asm/dma.h>
+#include <asm/portmux.h>
+
+#define SIR_UART_GET_CHAR(port)   bfin_read16((port)->membase + OFFSET_RBR)
+#define SIR_UART_GET_DLL(port)    bfin_read16((port)->membase + OFFSET_DLL)
+#define SIR_UART_GET_IER(port)    bfin_read16((port)->membase + OFFSET_IER)
+#define SIR_UART_GET_DLH(port)    bfin_read16((port)->membase + OFFSET_DLH)
+#define SIR_UART_GET_IIR(port)    bfin_read16((port)->membase + OFFSET_IIR)
+#define SIR_UART_GET_LCR(port)    bfin_read16((port)->membase + OFFSET_LCR)
+#define SIR_UART_GET_GCTL(port)   bfin_read16((port)->membase + OFFSET_GCTL)
+
+#define SIR_UART_PUT_CHAR(port, v) bfin_write16(((port)->membase + OFFSET_THR), v)
+#define SIR_UART_PUT_DLL(port, v)  bfin_write16(((port)->membase + OFFSET_DLL), v)
+#define SIR_UART_PUT_IER(port, v)  bfin_write16(((port)->membase + OFFSET_IER), v)
+#define SIR_UART_PUT_DLH(port, v)  bfin_write16(((port)->membase + OFFSET_DLH), v)
+#define SIR_UART_PUT_LCR(port, v)  bfin_write16(((port)->membase + OFFSET_LCR), v)
+#define SIR_UART_PUT_GCTL(port, v) bfin_write16(((port)->membase + OFFSET_GCTL), v)
+
+#ifdef CONFIG_SIR_BFIN_DMA
+struct dma_rx_buf {
+	char *buf;
+	int head;
+	int tail;
+	};
+#endif /* CONFIG_SIR_BFIN_DMA */
+
+struct bfin_sir_port {
+	unsigned char __iomem   *membase;
+	unsigned int            irq;
+	unsigned int            lsr;
+	unsigned long           clk;
+	struct net_device       *dev;
+#ifdef CONFIG_SIR_BFIN_DMA
+	int                     tx_done;
+	struct dma_rx_buf       rx_dma_buf;
+	struct timer_list       rx_dma_timer;
+	int                     rx_dma_nrows;
+#endif /* CONFIG_SIR_BFIN_DMA */
+	unsigned int            tx_dma_channel;
+	unsigned int            rx_dma_channel;
+};
+
+struct bfin_sir_port sir_ports[BFIN_UART_NR_PORTS];
+
+struct bfin_sir_port_res {
+	unsigned long   base_addr;
+	int             irq;
+	unsigned int    rx_dma_channel;
+	unsigned int    tx_dma_channel;
+};
+
+struct bfin_sir_port_res bfin_sir_port_resource[] = {
+#ifdef CONFIG_BFIN_SIR0
+	{
+	0xFFC00400,
+	IRQ_UART_RX,
+	CH_UART_RX,
+	CH_UART_TX,
+	},
+#endif
+};
+
+int nr_sirs = ARRAY_SIZE(bfin_sir_port_resource);
+
+struct bfin_sir_self {
+	struct bfin_sir_port    *sir_port;
+	spinlock_t              lock;
+	unsigned int            open;
+	int                     speed;
+	int                     newspeed;
+
+	struct sk_buff          *txskb;
+	struct sk_buff          *rxskb;
+	struct net_device_stats stats;
+	struct device           *dev;
+	struct irlap_cb         *irlap;
+	struct qos_info         qos;
+
+	iobuff_t                tx_buff;
+	iobuff_t                rx_buff;
+
+	struct work_struct      work;
+	int                     mtt;
+};
+
+static inline unsigned int SIR_UART_GET_LSR(struct bfin_sir_port *port)
+{
+	unsigned int lsr = bfin_read16(port->membase + OFFSET_LSR);
+	port->lsr |= (lsr & (BI|FE|PE|OE));
+	return lsr | port->lsr;
+}
+
+static inline void SIR_UART_CLEAR_LSR(struct bfin_sir_port *port)
+{
+	port->lsr = 0;
+	bfin_read16(port->membase + OFFSET_LSR);
+}
+
+#define DRIVER_NAME "bfin_sir"
+
+static void bfin_sir_hw_init(void)
+{
+#ifdef CONFIG_BFIN_SIR0
+	peripheral_request(P_UART0_TX, DRIVER_NAME);
+	peripheral_request(P_UART0_RX, DRIVER_NAME);
+#endif
+	SSYNC();
+}
diff --git a/include/asm-blackfin/mach-bf561/blackfin.h b/include/asm-blackfin/mach-bf561/blackfin.h
index 3a16df2..0ea8666 100644
--- a/include/asm-blackfin/mach-bf561/blackfin.h
+++ b/include/asm-blackfin/mach-bf561/blackfin.h
@@ -69,5 +69,19 @@
 #define bfin_read_SIC_ISR(x)		bfin_read32(SICA_ISR0 + (x << 2))
 #define bfin_write_SIC_ISR(x, val)	bfin_write32((SICA_ISR0 + (x << 2)), val)
 
+#define BFIN_UART_NR_PORTS      1
+
+#define OFFSET_THR              0x00	/* Transmit Holding register            */
+#define OFFSET_RBR              0x00	/* Receive Buffer register              */
+#define OFFSET_DLL              0x00	/* Divisor Latch (Low-Byte)             */
+#define OFFSET_IER              0x04	/* Interrupt Enable Register            */
+#define OFFSET_DLH              0x04	/* Divisor Latch (High-Byte)            */
+#define OFFSET_IIR              0x08	/* Interrupt Identification Register    */
+#define OFFSET_LCR              0x0C	/* Line Control Register                */
+#define OFFSET_MCR              0x10	/* Modem Control Register               */
+#define OFFSET_LSR              0x14	/* Line Status Register                 */
+#define OFFSET_MSR              0x18	/* Modem Status Register                */
+#define OFFSET_SCR              0x1C	/* SCR Scratch Register                 */
+#define OFFSET_GCTL             0x24	/* Global Control Register              */
 
 #endif				/* _MACH_BLACKFIN_H_ */
diff --git a/include/asm-blackfin/mach-bf561/cdefBF561.h b/include/asm-blackfin/mach-bf561/cdefBF561.h
index 1bc8d2f..b07ffcc 100644
--- a/include/asm-blackfin/mach-bf561/cdefBF561.h
+++ b/include/asm-blackfin/mach-bf561/cdefBF561.h
@@ -47,7 +47,30 @@
 
 /* Clock and System Control (0xFFC00000 - 0xFFC000FF) */
 #define bfin_read_PLL_CTL()                  bfin_read16(PLL_CTL)
-#define bfin_write_PLL_CTL(val)              bfin_write16(PLL_CTL,val)
+/* Writing to PLL_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_PLL_CTL(unsigned int val)
+{
+	unsigned long flags, iwr0, iwr1;
+
+	if (val == bfin_read_PLL_CTL())
+		return;
+
+	local_irq_save(flags);
+	/* Enable the PLL Wakeup bit in SIC IWR */
+	iwr0 = bfin_read32(SICA_IWR0);
+	iwr1 = bfin_read32(SICA_IWR1);
+	/* Only allow PPL Wakeup) */
+	bfin_write32(SICA_IWR0, IWR_ENABLE(0));
+	bfin_write32(SICA_IWR1, 0);
+
+	bfin_write16(PLL_CTL, val);
+	SSYNC();
+	asm("IDLE;");
+
+	bfin_write32(SICA_IWR0, iwr0);
+	bfin_write32(SICA_IWR1, iwr1);
+	local_irq_restore(flags);
+}
 #define bfin_read_PLL_DIV()                  bfin_read16(PLL_DIV)
 #define bfin_write_PLL_DIV(val)              bfin_write16(PLL_DIV,val)
 #define bfin_read_VR_CTL()                   bfin_read16(VR_CTL)
@@ -56,6 +79,10 @@
 {
 	unsigned long flags, iwr0, iwr1;
 
+	if (val == bfin_read_VR_CTL())
+		return;
+
+	local_irq_save(flags);
 	/* Enable the PLL Wakeup bit in SIC IWR */
 	iwr0 = bfin_read32(SICA_IWR0);
 	iwr1 = bfin_read32(SICA_IWR1);
@@ -65,12 +92,11 @@
 
 	bfin_write16(VR_CTL, val);
 	SSYNC();
-
-	local_irq_save(flags);
 	asm("IDLE;");
-	local_irq_restore(flags);
+
 	bfin_write32(SICA_IWR0, iwr0);
 	bfin_write32(SICA_IWR1, iwr1);
+	local_irq_restore(flags);
 }
 #define bfin_read_PLL_STAT()                 bfin_read16(PLL_STAT)
 #define bfin_write_PLL_STAT(val)             bfin_write16(PLL_STAT,val)
diff --git a/include/asm-blackfin/mach-bf561/defBF561.h b/include/asm-blackfin/mach-bf561/defBF561.h
index c3c0eb1..366c9b9 100644
--- a/include/asm-blackfin/mach-bf561/defBF561.h
+++ b/include/asm-blackfin/mach-bf561/defBF561.h
@@ -110,18 +110,23 @@
 #define WDOGB_STAT 				0xFFC01208	/* Watchdog Status register */
 
 /* UART Controller (0xFFC00400 - 0xFFC004FF) */
-#define UART_THR             	0xFFC00400	/* Transmit Holding register */
-#define UART_RBR             	0xFFC00400	/* Receive Buffer register */
-#define UART_DLL              	0xFFC00400	/* Divisor Latch (Low-Byte) */
-#define UART_IER              	0xFFC00404	/* Interrupt Enable Register */
-#define UART_DLH              	0xFFC00404	/* Divisor Latch (High-Byte) */
-#define UART_IIR              	0xFFC00408	/* Interrupt Identification Register */
-#define UART_LCR              	0xFFC0040C	/* Line Control Register */
-#define UART_MCR			 	0xFFC00410	/* Modem Control Register */
-#define UART_LSR              	0xFFC00414	/* Line Status Register */
-#define UART_MSR            	0xFFC00418	/* Modem Status Register */
-#define UART_SCR              	0xFFC0041C	/* SCR Scratch Register */
-#define UART_GCTL      	      	0xFFC00424	/* Global Control Register */
+
+/*
+ * Because include/linux/serial_reg.h have defined UART_*,
+ * So we define blackfin uart regs to BFIN_UART0_*.
+ */
+#define BFIN_UART_THR			0xFFC00400  /* Transmit Holding register */
+#define BFIN_UART_RBR			0xFFC00400  /* Receive Buffer register */
+#define BFIN_UART_DLL			0xFFC00400  /* Divisor Latch (Low-Byte) */
+#define BFIN_UART_IER			0xFFC00404  /* Interrupt Enable Register */
+#define BFIN_UART_DLH			0xFFC00404  /* Divisor Latch (High-Byte) */
+#define BFIN_UART_IIR			0xFFC00408  /* Interrupt Identification Register */
+#define BFIN_UART_LCR			0xFFC0040C  /* Line Control Register */
+#define BFIN_UART_MCR			0xFFC00410  /* Modem Control Register */
+#define BFIN_UART_LSR			0xFFC00414  /* Line Status Register */
+#define BFIN_UART_MSR			0xFFC00418  /* Modem Status Register */
+#define BFIN_UART_SCR			0xFFC0041C  /* SCR Scratch Register */
+#define BFIN_UART_GCTL			0xFFC00424  /* Global Control Register */
 
 /* SPI Controller (0xFFC00500 - 0xFFC005FF) */
 #define SPI0_REGBASE          		0xFFC00500
@@ -866,6 +871,8 @@
 /* PLL_DIV Masks */
 #define SCLK_DIV(x)  (x)	/* SCLK = VCO / x */
 
+#define CSEL			0x30		/* Core Select */
+#define SSEL			0xf		/* System Select */
 #define CCLK_DIV1              0x00000000	/* CCLK = VCO / 1 */
 #define CCLK_DIV2              0x00000010	/* CCLK = VCO / 2 */
 #define CCLK_DIV4              0x00000020	/* CCLK = VCO / 4 */
diff --git a/include/asm-blackfin/mach-bf561/dma.h b/include/asm-blackfin/mach-bf561/dma.h
index 766334b..21d9820 100644
--- a/include/asm-blackfin/mach-bf561/dma.h
+++ b/include/asm-blackfin/mach-bf561/dma.h
@@ -32,7 +32,4 @@
 #define CH_IMEM_STREAM1_SRC	34
 #define CH_IMEM_STREAM1_DEST	35
 
-extern int channel2irq(unsigned int channel);
-extern struct dma_register *base_addr[];
-
 #endif
diff --git a/include/asm-blackfin/portmux.h b/include/asm-blackfin/portmux.h
index 0d3f650..0807b28 100644
--- a/include/asm-blackfin/portmux.h
+++ b/include/asm-blackfin/portmux.h
@@ -17,8 +17,8 @@
 
 int peripheral_request(unsigned short per, const char *label);
 void peripheral_free(unsigned short per);
-int peripheral_request_list(unsigned short per[], const char *label);
-void peripheral_free_list(unsigned short per[]);
+int peripheral_request_list(const unsigned short per[], const char *label);
+void peripheral_free_list(const unsigned short per[]);
 
 #include <asm/gpio.h>
 #include <asm/mach/portmux.h>
diff --git a/include/asm-blackfin/processor.h b/include/asm-blackfin/processor.h
index 1033e5c..1c00407 100644
--- a/include/asm-blackfin/processor.h
+++ b/include/asm-blackfin/processor.h
@@ -26,9 +26,10 @@
 
 /*
  * User space process size: 1st byte beyond user address space.
+ * Fairly meaningless on nommu.  Parts of user programs can be scattered
+ * in a lot of places, so just disable this by setting it to 0xFFFFFFFF.
  */
-extern unsigned long memory_end;
-#define TASK_SIZE	(memory_end)
+#define TASK_SIZE	0xFFFFFFFF
 
 #ifdef __KERNEL__
 #define STACK_TOP	TASK_SIZE
diff --git a/include/asm-blackfin/signal.h b/include/asm-blackfin/signal.h
index 0250429..87951d2 100644
--- a/include/asm-blackfin/signal.h
+++ b/include/asm-blackfin/signal.h
@@ -143,7 +143,7 @@
 #endif				/* __KERNEL__ */
 
 typedef struct sigaltstack {
-	void *ss_sp;
+	void __user *ss_sp;
 	int ss_flags;
 	size_t ss_size;
 } stack_t;
diff --git a/include/asm-blackfin/thread_info.h b/include/asm-blackfin/thread_info.h
index 15b99cf..bc2fe5a 100644
--- a/include/asm-blackfin/thread_info.h
+++ b/include/asm-blackfin/thread_info.h
@@ -81,14 +81,11 @@
 #define init_thread_info	(init_thread_union.thread_info)
 #define init_stack		(init_thread_union.stack)
 
-/* How to get the thread information struct from C */
-
-static inline struct thread_info *current_thread_info(void)
-    __attribute__ ((__const__));
-
-/* Given a task stack pointer, you can find it's task structure
- * just by masking it to the 8K boundary.
+/* Given a task stack pointer, you can find its corresponding
+ * thread_info structure just by masking it to the THREAD_SIZE
+ * boundary (currently 8K as you can see above).
  */
+__attribute_const__
 static inline struct thread_info *current_thread_info(void)
 {
 	struct thread_info *ti;
diff --git a/include/asm-blackfin/time.h b/include/asm-blackfin/time.h
new file mode 100644
index 0000000..6e5859b
--- /dev/null
+++ b/include/asm-blackfin/time.h
@@ -0,0 +1,36 @@
+/*
+ * asm-blackfin/time.h:
+ *
+ * Copyright 2004-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _ASM_BLACKFIN_TIME_H
+#define _ASM_BLACKFIN_TIME_H
+
+/*
+ * The way that the Blackfin core timer works is:
+ *  - CCLK is divided by a programmable 8-bit pre-scaler (TSCALE)
+ *  - Every time TSCALE ticks, a 32bit is counted down (TCOUNT)
+ *
+ * If you take the fastest clock (1ns, or 1GHz to make the math work easier)
+ *    10ms is 10,000,000 clock ticks, which fits easy into a 32-bit counter
+ *    (32 bit counter is 4,294,967,296ns or 4.2 seconds) so, we don't need
+ *    to use TSCALE, and program it to zero (which is pass CCLK through).
+ *    If you feel like using it, try to keep HZ * TIMESCALE to some
+ *    value that divides easy (like power of 2).
+ */
+
+#ifndef CONFIG_CPU_FREQ
+#define TIME_SCALE 1
+#else
+/*
+ * Blackfin CPU frequency scaling supports max Core Clock 1, 1/2 and 1/4 .
+ * Whenever we change the Core Clock frequency changes we immediately
+ * adjust the Core Timer Presale Register. This way we don't lose time.
+ */
+#define TIME_SCALE 4
+#endif
+
+#endif
diff --git a/include/asm-blackfin/timex.h b/include/asm-blackfin/timex.h
index 8285901..22b0806 100644
--- a/include/asm-blackfin/timex.h
+++ b/include/asm-blackfin/timex.h
@@ -1,18 +1,23 @@
-/* blackfin architecture timex specifications: Lineo Inc. 2001
+/*
+ * asm-blackfin/timex.h: cpu cycles!
  *
- * Based on: include/asm-m68knommu/timex.h
+ * Copyright 2004-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
  */
 
-#ifndef _ASMBLACKFIN_TIMEX_H
-#define _ASMBLACKFIN_TIMEX_H
+#ifndef _ASM_BLACKFIN_TIMEX_H
+#define _ASM_BLACKFIN_TIMEX_H
 
 #define CLOCK_TICK_RATE	1000000	/* Underlying HZ */
 
-typedef unsigned long cycles_t;
+typedef unsigned long long cycles_t;
 
 static inline cycles_t get_cycles(void)
 {
-	return 0;
+	unsigned long tmp, tmp2;
+	__asm__("%0 = cycles; %1 = cycles2;" : "=d"(tmp), "=d"(tmp2));
+	return tmp | ((cycles_t)tmp2 << 32);
 }
 
 #endif
diff --git a/include/asm-blackfin/trace.h b/include/asm-blackfin/trace.h
index ef18afb..312b596 100644
--- a/include/asm-blackfin/trace.h
+++ b/include/asm-blackfin/trace.h
@@ -62,14 +62,14 @@
 	preg.L = LO(TBUFCTL); \
 	preg.H = HI(TBUFCTL); \
 	dreg = [preg]; \
-	[sp++] = dreg; \
+	[--sp] = dreg; \
 	dreg = 0x1; \
 	[preg] = dreg;
 
 #define trace_buffer_restore(preg, dreg) \
 	preg.L = LO(TBUFCTL); \
 	preg.H = HI(TBUFCTL); \
-	dreg = [sp--]; \
+	dreg = [sp++]; \
 	[preg] = dreg;
 
 #else /* CONFIG_DEBUG_BFIN_HWTRACE_ON */
diff --git a/include/asm-blackfin/uaccess.h b/include/asm-blackfin/uaccess.h
index 22a410b..d928b80 100644
--- a/include/asm-blackfin/uaccess.h
+++ b/include/asm-blackfin/uaccess.h
@@ -133,7 +133,7 @@
 }
 
 #define __put_user_bad() (printk(KERN_INFO "put_user_bad %s:%d %s\n",\
-                           __FILE__, __LINE__, __FUNCTION__),\
+                           __FILE__, __LINE__, __func__),\
                            bad_user_access_length(), (-EFAULT))
 
 /*
@@ -177,7 +177,7 @@
 		default:						\
 			x = 0;						\
 			printk(KERN_INFO "get_user_bad: %s:%d %s\n",    \
-			       __FILE__, __LINE__, __FUNCTION__);	\
+			       __FILE__, __LINE__, __func__);	\
 			_err = __get_user_bad();			\
 			break;						\
 		}							\
diff --git a/include/asm-blackfin/unistd.h b/include/asm-blackfin/unistd.h
index c18a399..42955d0 100644
--- a/include/asm-blackfin/unistd.h
+++ b/include/asm-blackfin/unistd.h
@@ -265,14 +265,14 @@
 				/* 258 __NR_remap_file_pages */
 #define __NR_set_tid_address	259
 #define __NR_timer_create	260
-#define __NR_timer_settime	(__NR_timer_create+1)
-#define __NR_timer_gettime	(__NR_timer_create+2)
-#define __NR_timer_getoverrun	(__NR_timer_create+3)
-#define __NR_timer_delete	(__NR_timer_create+4)
-#define __NR_clock_settime	(__NR_timer_create+5)
-#define __NR_clock_gettime	(__NR_timer_create+6)
-#define __NR_clock_getres	(__NR_timer_create+7)
-#define __NR_clock_nanosleep	(__NR_timer_create+8)
+#define __NR_timer_settime	261
+#define __NR_timer_gettime	262
+#define __NR_timer_getoverrun	263
+#define __NR_timer_delete	264
+#define __NR_clock_settime	265
+#define __NR_clock_gettime	266
+#define __NR_clock_getres	267
+#define __NR_clock_nanosleep	268
 #define __NR_statfs64		269
 #define __NR_fstatfs64		270
 #define __NR_tgkill		271
@@ -283,11 +283,11 @@
 				/* 276 __NR_get_mempolicy */
 				/* 277 __NR_set_mempolicy */
 #define __NR_mq_open 		278
-#define __NR_mq_unlink		(__NR_mq_open+1)
-#define __NR_mq_timedsend	(__NR_mq_open+2)
-#define __NR_mq_timedreceive	(__NR_mq_open+3)
-#define __NR_mq_notify		(__NR_mq_open+4)
-#define __NR_mq_getsetattr	(__NR_mq_open+5)
+#define __NR_mq_unlink		279
+#define __NR_mq_timedsend	280
+#define __NR_mq_timedreceive	281
+#define __NR_mq_notify		282
+#define __NR_mq_getsetattr	283
 #define __NR_kexec_load		284
 #define __NR_waitid		285
 #define __NR_add_key		286
diff --git a/include/asm-sparc/device.h b/include/asm-sparc/device.h
index 680e51d..19790eb 100644
--- a/include/asm-sparc/device.h
+++ b/include/asm-sparc/device.h
@@ -16,6 +16,8 @@
 
 	struct device_node	*prom_node;
 	struct of_device	*op;
+
+	int			numa_node;
 };
 
 #endif /* _ASM_SPARC_DEVICE_H */
diff --git a/include/asm-sparc/prom.h b/include/asm-sparc/prom.h
index df5dc44..fd55522 100644
--- a/include/asm-sparc/prom.h
+++ b/include/asm-sparc/prom.h
@@ -77,6 +77,11 @@
 				 const char *name,
 				 int def);
 extern int of_find_in_proplist(const char *list, const char *match, int len);
+#ifdef CONFIG_NUMA
+extern int of_node_to_nid(struct device_node *dp);
+#else
+#define of_node_to_nid(dp)	(-1)
+#endif
 
 extern void prom_build_devicetree(void);
 
diff --git a/include/asm-sparc64/iommu.h b/include/asm-sparc64/iommu.h
index 46325dd..d7b9afc 100644
--- a/include/asm-sparc64/iommu.h
+++ b/include/asm-sparc64/iommu.h
@@ -56,6 +56,7 @@
 };
 
 extern int iommu_table_init(struct iommu *iommu, int tsbsize,
-			    u32 dma_offset, u32 dma_addr_mask);
+			    u32 dma_offset, u32 dma_addr_mask,
+			    int numa_node);
 
 #endif /* !(_SPARC64_IOMMU_H) */
diff --git a/include/asm-sparc64/mmzone.h b/include/asm-sparc64/mmzone.h
new file mode 100644
index 0000000..ebf5986
--- /dev/null
+++ b/include/asm-sparc64/mmzone.h
@@ -0,0 +1,17 @@
+#ifndef _SPARC64_MMZONE_H
+#define _SPARC64_MMZONE_H
+
+#ifdef CONFIG_NEED_MULTIPLE_NODES
+
+extern struct pglist_data *node_data[];
+
+#define NODE_DATA(nid)		(node_data[nid])
+#define node_start_pfn(nid)	(NODE_DATA(nid)->node_start_pfn)
+#define node_end_pfn(nid)	(NODE_DATA(nid)->node_end_pfn)
+
+extern int numa_cpu_lookup_table[];
+extern cpumask_t numa_cpumask_lookup_table[];
+
+#endif /* CONFIG_NEED_MULTIPLE_NODES */
+
+#endif /* _SPARC64_MMZONE_H */
diff --git a/include/asm-sparc64/numnodes.h b/include/asm-sparc64/numnodes.h
deleted file mode 100644
index 017e7e7..0000000
--- a/include/asm-sparc64/numnodes.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _SPARC64_NUMNODES_H
-#define _SPARC64_NUMNODES_H
-
-#define NODES_SHIFT	0
-
-#endif /* !(_SPARC64_NUMNODES_H) */
diff --git a/include/asm-sparc64/ptrace.h b/include/asm-sparc64/ptrace.h
index 6da1978..b4b951d 100644
--- a/include/asm-sparc64/ptrace.h
+++ b/include/asm-sparc64/ptrace.h
@@ -8,6 +8,8 @@
  * stack during a system call and basically all traps.
  */
 
+#define PT_REGS_MAGIC 0x57ac6c00
+
 #ifndef __ASSEMBLY__
 
 struct pt_regs {
@@ -16,7 +18,19 @@
 	unsigned long tpc;
 	unsigned long tnpc;
 	unsigned int y;
-	unsigned int fprs;
+
+	/* We encode a magic number, PT_REGS_MAGIC, along
+	 * with the %tt (trap type) register value at trap
+	 * entry time.  The magic number allows us to identify
+	 * accurately a trap stack frame in the stack
+	 * unwinder, and the %tt value allows us to test
+	 * things like "in a system call" etc. for an arbitray
+	 * process.
+	 *
+	 * The PT_REGS_MAGIC is choosen such that it can be
+	 * loaded completely using just a sethi instruction.
+	 */
+	unsigned int magic;
 };
 
 struct pt_regs32 {
@@ -147,7 +161,7 @@
 #define PT_V9_TPC    0x88
 #define PT_V9_TNPC   0x90
 #define PT_V9_Y      0x98
-#define PT_V9_FPRS   0x9c
+#define PT_V9_MAGIC  0x9c
 #define PT_TSTATE	PT_V9_TSTATE
 #define PT_TPC		PT_V9_TPC
 #define PT_TNPC		PT_V9_TNPC
diff --git a/include/asm-sparc64/sparsemem.h b/include/asm-sparc64/sparsemem.h
index 77bcd2b..b99d4e4 100644
--- a/include/asm-sparc64/sparsemem.h
+++ b/include/asm-sparc64/sparsemem.h
@@ -3,7 +3,7 @@
 
 #ifdef __KERNEL__
 
-#define SECTION_SIZE_BITS       31
+#define SECTION_SIZE_BITS       30
 #define MAX_PHYSADDR_BITS       42
 #define MAX_PHYSMEM_BITS        42
 
diff --git a/include/asm-sparc64/topology.h b/include/asm-sparc64/topology.h
index c6b5570..001c040 100644
--- a/include/asm-sparc64/topology.h
+++ b/include/asm-sparc64/topology.h
@@ -1,6 +1,77 @@
 #ifndef _ASM_SPARC64_TOPOLOGY_H
 #define _ASM_SPARC64_TOPOLOGY_H
 
+#ifdef CONFIG_NUMA
+
+#include <asm/mmzone.h>
+
+static inline int cpu_to_node(int cpu)
+{
+	return numa_cpu_lookup_table[cpu];
+}
+
+#define parent_node(node)	(node)
+
+static inline cpumask_t node_to_cpumask(int node)
+{
+	return numa_cpumask_lookup_table[node];
+}
+
+/* Returns a pointer to the cpumask of CPUs on Node 'node'. */
+#define node_to_cpumask_ptr(v, node)		\
+		cpumask_t *v = &(numa_cpumask_lookup_table[node])
+
+#define node_to_cpumask_ptr_next(v, node)	\
+			   v = &(numa_cpumask_lookup_table[node])
+
+static inline int node_to_first_cpu(int node)
+{
+	cpumask_t tmp;
+	tmp = node_to_cpumask(node);
+	return first_cpu(tmp);
+}
+
+struct pci_bus;
+#ifdef CONFIG_PCI
+extern int pcibus_to_node(struct pci_bus *pbus);
+#else
+static inline int pcibus_to_node(struct pci_bus *pbus)
+{
+	return -1;
+}
+#endif
+
+#define pcibus_to_cpumask(bus)	\
+	(pcibus_to_node(bus) == -1 ? \
+	 CPU_MASK_ALL : \
+	 node_to_cpumask(pcibus_to_node(bus)))
+
+#define SD_NODE_INIT (struct sched_domain) {		\
+	.min_interval		= 8,			\
+	.max_interval		= 32,			\
+	.busy_factor		= 32,			\
+	.imbalance_pct		= 125,			\
+	.cache_nice_tries	= 2,			\
+	.busy_idx		= 3,			\
+	.idle_idx		= 2,			\
+	.newidle_idx		= 0, 			\
+	.wake_idx		= 1,			\
+	.forkexec_idx		= 1,			\
+	.flags			= SD_LOAD_BALANCE	\
+				| SD_BALANCE_FORK	\
+				| SD_BALANCE_EXEC	\
+				| SD_SERIALIZE		\
+				| SD_WAKE_BALANCE,	\
+	.last_balance		= jiffies,		\
+	.balance_interval	= 1,			\
+}
+
+#else /* CONFIG_NUMA */
+
+#include <asm-generic/topology.h>
+
+#endif /* !(CONFIG_NUMA) */
+
 #ifdef CONFIG_SMP
 #define topology_physical_package_id(cpu)	(cpu_data(cpu).proc_id)
 #define topology_core_id(cpu)			(cpu_data(cpu).core_id)
@@ -10,8 +81,6 @@
 #define smt_capable()				(sparc64_multi_core)
 #endif /* CONFIG_SMP */
 
-#include <asm-generic/topology.h>
-
 #define cpu_coregroup_map(cpu)			(cpu_core_map[cpu])
 
 #endif /* _ASM_SPARC64_TOPOLOGY_H */
diff --git a/include/asm-sparc64/ttable.h b/include/asm-sparc64/ttable.h
index 7208a77..d3cc4ef 100644
--- a/include/asm-sparc64/ttable.h
+++ b/include/asm-sparc64/ttable.h
@@ -28,7 +28,7 @@
 	call	routine;				\
 	 add	%sp, PTREGS_OFF, %o0;			\
 	ba,pt	%xcc, rtrap;				\
-	 clr	%l6;					\
+	 nop;						\
 	nop;
 
 #define TRAP_7INSNS(routine)				\
@@ -38,7 +38,7 @@
 	call	routine;				\
 	 add	%sp, PTREGS_OFF, %o0;			\
 	ba,pt	%xcc, rtrap;				\
-	 clr	%l6;
+	 nop;
 
 #define TRAP_SAVEFPU(routine)				\
 	sethi	%hi(109f), %g7;				\
@@ -47,7 +47,7 @@
 	call	routine;				\
 	 add	%sp, PTREGS_OFF, %o0;			\
 	ba,pt	%xcc, rtrap;				\
-	 clr	%l6;					\
+	 nop;						\
 	nop;
 
 #define TRAP_NOSAVE(routine)				\
@@ -67,7 +67,7 @@
 	call	routine;				\
 	 add	%sp, PTREGS_OFF, %o0;			\
 	ba,pt	%xcc, rtrap;				\
-	 clr	%l6;					\
+	 nop;						\
 	nop;
 	
 #define TRAP_ARG(routine, arg)				\
@@ -78,7 +78,7 @@
 	call	routine;				\
 	 mov	arg, %o1;				\
 	ba,pt	%xcc, rtrap;				\
-	 clr	%l6;
+	 nop;
 	
 #define TRAPTL1_ARG(routine, arg)			\
 	sethi	%hi(109f), %g7;				\
@@ -88,7 +88,7 @@
 	call	routine;				\
 	 mov	arg, %o1;				\
 	ba,pt	%xcc, rtrap;				\
-	 clr	%l6;
+	 nop;
 	
 #define SYSCALL_TRAP(routine, systbl)			\
 	sethi	%hi(109f), %g7;				\
@@ -166,7 +166,7 @@
 	ldx	[%sp + PTREGS_OFF + PT_V9_TNPC], %l1;			\
 	add	%l1, 4, %l2;						\
 	stx	%l1, [%sp + PTREGS_OFF + PT_V9_TPC];			\
-	ba,pt	%xcc, rtrap_clr_l6;					\
+	ba,pt	%xcc, rtrap;						\
 	 stx	%l2, [%sp + PTREGS_OFF + PT_V9_TNPC];
 	        
 #ifdef CONFIG_KPROBES
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
index c6a2353..402fb7a 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -39,9 +39,10 @@
 	DMX_OUT_DECODER, /* Streaming directly to decoder. */
 	DMX_OUT_TAP,     /* Output going to a memory buffer */
 			 /* (to be retrieved via the read command).*/
-	DMX_OUT_TS_TAP   /* Output multiplexed into a new TS  */
+	DMX_OUT_TS_TAP,  /* Output multiplexed into a new TS  */
 			 /* (to be retrieved by reading from the */
 			 /* logical DVR device).                 */
+	DMX_OUT_TSDEMUX_TAP /* Like TS_TAP but retrieved from the DMX device */
 } dmx_output_t;
 
 
diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
index adcbb05..de8387b 100644
--- a/include/linux/exportfs.h
+++ b/include/linux/exportfs.h
@@ -43,7 +43,7 @@
 			u32 parent_ino;
 			u32 parent_gen;
 		} i32;
-		__u32 raw[6];
+		__u32 raw[0];
 	};
 };
 
diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h
index b979112..32eb8bb 100644
--- a/include/linux/i2c-id.h
+++ b/include/linux/i2c-id.h
@@ -125,6 +125,7 @@
 #define I2C_HW_B_CX2341X	0x010020 /* Conexant CX2341X MPEG encoder cards */
 #define I2C_HW_B_INTELFB	0x010021 /* intel framebuffer driver */
 #define I2C_HW_B_CX23885	0x010022 /* conexant 23885 based tv cards (bus1) */
+#define I2C_HW_B_AU0828		0x010023 /* auvitek au0828 usb bridge */
 
 /* --- PCF 8584 based algorithms					*/
 #define I2C_HW_P_ELEK		0x020002 /* Elektor ISA Bus inteface card */
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index f27d11a..529f301 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -465,13 +465,19 @@
 	WLAN_EID_TS_DELAY = 43,
 	WLAN_EID_TCLAS_PROCESSING = 44,
 	WLAN_EID_QOS_CAPA = 46,
-	/* 802.11s */
-	WLAN_EID_MESH_CONFIG = 36,      /* Pending IEEE 802.11 ANA approval */
-	WLAN_EID_MESH_ID = 37,          /* Pending IEEE 802.11 ANA approval */
-	WLAN_EID_PEER_LINK = 40,	/* Pending IEEE 802.11 ANA approval */
-	WLAN_EID_PREQ = 53,		/* Pending IEEE 802.11 ANA approval */
-	WLAN_EID_PREP = 54,		/* Pending IEEE 802.11 ANA approval */
-	WLAN_EID_PERR = 55,		/* Pending IEEE 802.11 ANA approval */
+	/* 802.11s
+	 *
+	 * All mesh EID numbers are pending IEEE 802.11 ANA approval.
+	 * The numbers have been incremented from those suggested in
+	 * 802.11s/D2.0 so that MESH_CONFIG does not conflict with
+	 * EXT_SUPP_RATES.
+	 */
+	WLAN_EID_MESH_CONFIG = 51,
+	WLAN_EID_MESH_ID = 52,
+	WLAN_EID_PEER_LINK = 55,
+	WLAN_EID_PREQ = 68,
+	WLAN_EID_PREP = 69,
+	WLAN_EID_PERR = 70,
 	/* 802.11h */
 	WLAN_EID_PWR_CONSTRAINT = 32,
 	WLAN_EID_PWR_CAPABILITY = 33,
diff --git a/include/linux/meye.h b/include/linux/meye.h
index 39fd9c8..12010ac 100644
--- a/include/linux/meye.h
+++ b/include/linux/meye.h
@@ -58,7 +58,7 @@
 
 /* V4L2 private controls */
 #define V4L2_CID_AGC		V4L2_CID_PRIVATE_BASE
-#define V4L2_CID_SHARPNESS	(V4L2_CID_PRIVATE_BASE + 1)
+#define V4L2_CID_MEYE_SHARPNESS	(V4L2_CID_PRIVATE_BASE + 1)
 #define V4L2_CID_PICTURE	(V4L2_CID_PRIVATE_BASE + 2)
 #define V4L2_CID_JPEGQUAL	(V4L2_CID_PRIVATE_BASE + 3)
 #define V4L2_CID_FRAMERATE	(V4L2_CID_PRIVATE_BASE + 4)
diff --git a/include/linux/nfs3.h b/include/linux/nfs3.h
index 7f11fa5..539f3b5 100644
--- a/include/linux/nfs3.h
+++ b/include/linux/nfs3.h
@@ -96,7 +96,7 @@
 #define MOUNTPROC3_UMNTALL	4
  
 
-#if defined(__KERNEL__) || defined(NFS_NEED_KERNEL_TYPES)
+#if defined(__KERNEL__)
 
 /* Number of 32bit words in post_op_attr */
 #define NFS3_POST_OP_ATTR_WORDS		22
diff --git a/include/linux/nfsd/Kbuild b/include/linux/nfsd/Kbuild
index e726fc3..fc97204 100644
--- a/include/linux/nfsd/Kbuild
+++ b/include/linux/nfsd/Kbuild
@@ -1,6 +1,6 @@
 unifdef-y += const.h
+unifdef-y += debug.h
 unifdef-y += export.h
+unifdef-y += nfsfh.h
 unifdef-y += stats.h
 unifdef-y += syscall.h
-unifdef-y += nfsfh.h
-unifdef-y += debug.h
diff --git a/include/linux/nfsd/cache.h b/include/linux/nfsd/cache.h
index 7b5d784..04b355c 100644
--- a/include/linux/nfsd/cache.h
+++ b/include/linux/nfsd/cache.h
@@ -10,7 +10,6 @@
 #ifndef NFSCACHE_H
 #define NFSCACHE_H
 
-#ifdef __KERNEL__
 #include <linux/in.h>
 #include <linux/uio.h>
 
@@ -77,5 +76,4 @@
 int	nfsd_cache_lookup(struct svc_rqst *, int);
 void	nfsd_cache_update(struct svc_rqst *, int, __be32 *);
 
-#endif /* __KERNEL__ */
 #endif /* NFSCACHE_H */
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
index 8caf4c4..21ee440 100644
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -27,7 +27,6 @@
 #define NFSD_VERSION		"0.5"
 #define NFSD_SUPPORTED_MINOR_VERSION	0
 
-#ifdef __KERNEL__
 /*
  * Special flags for nfsd_permission. These must be different from MAY_READ,
  * MAY_WRITE, and MAY_EXEC.
@@ -56,12 +55,20 @@
 extern struct svc_version	nfsd_version2, nfsd_version3,
 				nfsd_version4;
 extern struct svc_serv		*nfsd_serv;
+
+extern struct seq_operations nfs_exports_op;
+
 /*
  * Function prototypes.
  */
 int		nfsd_svc(unsigned short port, int nrservs);
 int		nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp);
 
+int		nfsd_nrthreads(void);
+int		nfsd_nrpools(void);
+int		nfsd_get_nrthreads(int n, int *);
+int		nfsd_set_nrthreads(int n, int *);
+
 /* nfsd/vfs.c */
 int		fh_lock_parent(struct svc_fh *, struct dentry *);
 int		nfsd_racache_init(int);
@@ -326,6 +333,4 @@
 
 #endif /* CONFIG_NFSD_V4 */
 
-#endif /* __KERNEL__ */
-
 #endif /* LINUX_NFSD_NFSD_H */
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index b9e1740..44c81c7 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -740,13 +740,13 @@
 extern void rtnl_lock(void);
 extern void rtnl_unlock(void);
 extern int rtnl_trylock(void);
+extern int rtnl_is_locked(void);
 
 extern void rtnetlink_init(void);
 extern void __rtnl_unlock(void);
 
 #define ASSERT_RTNL() do { \
-	if (unlikely(rtnl_trylock())) { \
-		rtnl_unlock(); \
+	if (unlikely(!rtnl_is_locked())) { \
 		printk(KERN_ERR "RTNL: assertion failed at %s (%d)\n", \
 		       __FILE__,  __LINE__); \
 		dump_stack(); \
diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h
index 03547d6..2d8b211 100644
--- a/include/linux/sunrpc/cache.h
+++ b/include/linux/sunrpc/cache.h
@@ -120,7 +120,6 @@
 	struct list_head	hash;	/* on hash chain */
 	struct list_head	recent; /* on fifo */
 	struct cache_head	*item;  /* cache item we wait on */
-	time_t			recv_time;
 	void			*owner; /* we might need to discard all defered requests
 					 * owned by someone */
 	void			(*revisit)(struct cache_deferred_req *req,
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h
index 5a4b1e0..a10f1fb 100644
--- a/include/linux/sunrpc/gss_krb5.h
+++ b/include/linux/sunrpc/gss_krb5.h
@@ -70,8 +70,6 @@
 	SEAL_ALG_DES3KD = 0x0002
 };
 
-#define KRB5_CKSUM_LENGTH 8
-
 #define CKSUMTYPE_CRC32			0x0001
 #define CKSUMTYPE_RSA_MD4		0x0002
 #define CKSUMTYPE_RSA_MD4_DES		0x0003
@@ -150,9 +148,9 @@
 s32
 krb5_make_seq_num(struct crypto_blkcipher *key,
 		int direction,
-		s32 seqnum, unsigned char *cksum, unsigned char *buf);
+		u32 seqnum, unsigned char *cksum, unsigned char *buf);
 
 s32
 krb5_get_seq_num(struct crypto_blkcipher *key,
 	       unsigned char *cksum,
-	       unsigned char *buf, int *direction, s32 * seqnum);
+	       unsigned char *buf, int *direction, u32 *seqnum);
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 64c9755..4b54c5f 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -386,7 +386,6 @@
 			      void (*shutdown)(struct svc_serv*));
 struct svc_rqst *svc_prepare_thread(struct svc_serv *serv,
 					struct svc_pool *pool);
-int		   svc_create_thread(svc_thread_fn, struct svc_serv *);
 void		   svc_exit_thread(struct svc_rqst *);
 struct svc_serv *  svc_create_pooled(struct svc_program *, unsigned int,
 			void (*shutdown)(struct svc_serv*),
diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h
index 22e1ef8..d39dbdc 100644
--- a/include/linux/sunrpc/svcauth.h
+++ b/include/linux/sunrpc/svcauth.h
@@ -24,6 +24,7 @@
 };
 
 struct svc_rqst;		/* forward decl */
+struct in6_addr;
 
 /* Authentication is done in the context of a domain.
  *
@@ -120,10 +121,10 @@
 
 extern struct auth_domain *unix_domain_find(char *name);
 extern void auth_domain_put(struct auth_domain *item);
-extern int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom);
+extern int auth_unix_add_addr(struct in6_addr *addr, struct auth_domain *dom);
 extern struct auth_domain *auth_domain_lookup(char *name, struct auth_domain *new);
 extern struct auth_domain *auth_domain_find(char *name);
-extern struct auth_domain *auth_unix_lookup(struct in_addr addr);
+extern struct auth_domain *auth_unix_lookup(struct in6_addr *addr);
 extern int auth_unix_forget_old(struct auth_domain *dom);
 extern void svcauth_unix_purge(void);
 extern void svcauth_unix_info_release(void *);
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
index 206f092..8cff696 100644
--- a/include/linux/sunrpc/svcsock.h
+++ b/include/linux/sunrpc/svcsock.h
@@ -26,8 +26,8 @@
 	void			(*sk_owspace)(struct sock *);
 
 	/* private TCP part */
-	int			sk_reclen;	/* length of record */
-	int			sk_tcplen;	/* current read length */
+	u32			sk_reclen;	/* length of record */
+	u32			sk_tcplen;	/* current read length */
 };
 
 /*
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 17a8017..c141118 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -282,6 +282,7 @@
 #define V4L2_PIX_FMT_BGR32   v4l2_fourcc('B','G','R','4') /* 32  BGR-8-8-8-8   */
 #define V4L2_PIX_FMT_RGB32   v4l2_fourcc('R','G','B','4') /* 32  RGB-8-8-8-8   */
 #define V4L2_PIX_FMT_GREY    v4l2_fourcc('G','R','E','Y') /*  8  Greyscale     */
+#define V4L2_PIX_FMT_Y16     v4l2_fourcc('Y','1','6',' ') /* 16  Greyscale     */
 #define V4L2_PIX_FMT_PAL8    v4l2_fourcc('P','A','L','8') /*  8  8-bit palette */
 #define V4L2_PIX_FMT_YVU410  v4l2_fourcc('Y','V','U','9') /*  9  YVU 4:1:0     */
 #define V4L2_PIX_FMT_YVU420  v4l2_fourcc('Y','V','1','2') /* 12  YVU 4:2:0     */
@@ -308,6 +309,7 @@
 
 /* see http://www.siliconimaging.com/RGB%20Bayer.htm */
 #define V4L2_PIX_FMT_SBGGR8  v4l2_fourcc('B','A','8','1') /*  8  BGBG.. GRGR.. */
+#define V4L2_PIX_FMT_SBGGR16 v4l2_fourcc('B','Y','R','2') /* 16  BGBG.. GRGR.. */
 
 /* compressed formats */
 #define V4L2_PIX_FMT_MJPEG    v4l2_fourcc('M','J','P','G') /* Motion-JPEG   */
@@ -793,6 +795,7 @@
 /*  Values for ctrl_class field */
 #define V4L2_CTRL_CLASS_USER 0x00980000	/* Old-style 'user' controls */
 #define V4L2_CTRL_CLASS_MPEG 0x00990000	/* MPEG-compression controls */
+#define V4L2_CTRL_CLASS_CAMERA 0x009a0000	/* Camera class controls */
 
 #define V4L2_CTRL_ID_MASK      	  (0x0fffffff)
 #define V4L2_CTRL_ID2CLASS(id)    ((id) & 0x0fff0000UL)
@@ -849,21 +852,37 @@
 #define V4L2_CID_AUDIO_TREBLE		(V4L2_CID_BASE+8)
 #define V4L2_CID_AUDIO_MUTE		(V4L2_CID_BASE+9)
 #define V4L2_CID_AUDIO_LOUDNESS		(V4L2_CID_BASE+10)
-#define V4L2_CID_BLACK_LEVEL		(V4L2_CID_BASE+11)
+#define V4L2_CID_BLACK_LEVEL		(V4L2_CID_BASE+11) /* Deprecated */
 #define V4L2_CID_AUTO_WHITE_BALANCE	(V4L2_CID_BASE+12)
 #define V4L2_CID_DO_WHITE_BALANCE	(V4L2_CID_BASE+13)
 #define V4L2_CID_RED_BALANCE		(V4L2_CID_BASE+14)
 #define V4L2_CID_BLUE_BALANCE		(V4L2_CID_BASE+15)
 #define V4L2_CID_GAMMA			(V4L2_CID_BASE+16)
-#define V4L2_CID_WHITENESS		(V4L2_CID_GAMMA) /* ? Not sure */
+#define V4L2_CID_WHITENESS		(V4L2_CID_GAMMA) /* Deprecated */
 #define V4L2_CID_EXPOSURE		(V4L2_CID_BASE+17)
 #define V4L2_CID_AUTOGAIN		(V4L2_CID_BASE+18)
 #define V4L2_CID_GAIN			(V4L2_CID_BASE+19)
 #define V4L2_CID_HFLIP			(V4L2_CID_BASE+20)
 #define V4L2_CID_VFLIP			(V4L2_CID_BASE+21)
-#define V4L2_CID_HCENTER		(V4L2_CID_BASE+22)
-#define V4L2_CID_VCENTER		(V4L2_CID_BASE+23)
-#define V4L2_CID_LASTP1			(V4L2_CID_BASE+24) /* last CID + 1 */
+
+/* Deprecated, use V4L2_CID_PAN_RESET and V4L2_CID_TILT_RESET */
+#define V4L2_CID_HCENTER_DEPRECATED	(V4L2_CID_BASE+22)
+#define V4L2_CID_VCENTER_DEPRECATED	(V4L2_CID_BASE+23)
+
+#define V4L2_CID_POWER_LINE_FREQUENCY	(V4L2_CID_BASE+24)
+enum v4l2_power_line_frequency {
+	V4L2_CID_POWER_LINE_FREQUENCY_DISABLED	= 0,
+	V4L2_CID_POWER_LINE_FREQUENCY_50HZ	= 1,
+	V4L2_CID_POWER_LINE_FREQUENCY_60HZ	= 2,
+};
+#define V4L2_CID_HUE_AUTO			(V4L2_CID_BASE+25)
+#define V4L2_CID_WHITE_BALANCE_TEMPERATURE	(V4L2_CID_BASE+26)
+#define V4L2_CID_SHARPNESS			(V4L2_CID_BASE+27)
+#define V4L2_CID_BACKLIGHT_COMPENSATION 	(V4L2_CID_BASE+28)
+#define V4L2_CID_CHROMA_AGC                     (V4L2_CID_BASE+29)
+#define V4L2_CID_COLOR_KILLER                   (V4L2_CID_BASE+30)
+/* last CID + 1 */
+#define V4L2_CID_LASTP1                         (V4L2_CID_BASE+31)
 
 /*  MPEG-class control IDs defined by V4L2 */
 #define V4L2_CID_MPEG_BASE 			(V4L2_CTRL_CLASS_MPEG | 0x900)
@@ -1051,6 +1070,32 @@
 #define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP 	(V4L2_CID_MPEG_CX2341X_BASE+10)
 #define V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS 	(V4L2_CID_MPEG_CX2341X_BASE+11)
 
+/*  Camera class control IDs */
+#define V4L2_CID_CAMERA_CLASS_BASE 	(V4L2_CTRL_CLASS_CAMERA | 0x900)
+#define V4L2_CID_CAMERA_CLASS 		(V4L2_CTRL_CLASS_CAMERA | 1)
+
+#define V4L2_CID_EXPOSURE_AUTO			(V4L2_CID_CAMERA_CLASS_BASE+1)
+enum  v4l2_exposure_auto_type {
+	V4L2_EXPOSURE_AUTO = 0,
+	V4L2_EXPOSURE_MANUAL = 1,
+	V4L2_EXPOSURE_SHUTTER_PRIORITY = 2,
+	V4L2_EXPOSURE_APERTURE_PRIORITY = 3
+};
+#define V4L2_CID_EXPOSURE_ABSOLUTE		(V4L2_CID_CAMERA_CLASS_BASE+2)
+#define V4L2_CID_EXPOSURE_AUTO_PRIORITY		(V4L2_CID_CAMERA_CLASS_BASE+3)
+
+#define V4L2_CID_PAN_RELATIVE			(V4L2_CID_CAMERA_CLASS_BASE+4)
+#define V4L2_CID_TILT_RELATIVE			(V4L2_CID_CAMERA_CLASS_BASE+5)
+#define V4L2_CID_PAN_RESET			(V4L2_CID_CAMERA_CLASS_BASE+6)
+#define V4L2_CID_TILT_RESET			(V4L2_CID_CAMERA_CLASS_BASE+7)
+
+#define V4L2_CID_PAN_ABSOLUTE			(V4L2_CID_CAMERA_CLASS_BASE+8)
+#define V4L2_CID_TILT_ABSOLUTE			(V4L2_CID_CAMERA_CLASS_BASE+9)
+
+#define V4L2_CID_FOCUS_ABSOLUTE			(V4L2_CID_CAMERA_CLASS_BASE+10)
+#define V4L2_CID_FOCUS_RELATIVE			(V4L2_CID_CAMERA_CLASS_BASE+11)
+#define V4L2_CID_FOCUS_AUTO			(V4L2_CID_CAMERA_CLASS_BASE+12)
+
 /*
  *	T U N I N G
  */
diff --git a/include/media/ir-common.h b/include/media/ir-common.h
index a427420..bfee8be 100644
--- a/include/media/ir-common.h
+++ b/include/media/ir-common.h
@@ -107,6 +107,7 @@
 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_pixelview_new[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];
@@ -141,8 +142,10 @@
 extern IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_behold[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_behold_columbus[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_pinnacle_pctv_hd[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_genius_tvgo_a11mce[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_powercolor_real_angel[IR_KEYTAB_SIZE];
 
 #endif
 
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
new file mode 100644
index 0000000..6a8c8be7
--- /dev/null
+++ b/include/media/soc_camera.h
@@ -0,0 +1,179 @@
+/*
+ * camera image capture (abstract) bus driver header
+ *
+ * Copyright (C) 2006, Sascha Hauer, Pengutronix
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef SOC_CAMERA_H
+#define SOC_CAMERA_H
+
+#include <linux/videodev2.h>
+#include <media/videobuf-dma-sg.h>
+
+struct soc_camera_device {
+	struct list_head list;
+	struct device dev;
+	struct device *control;
+	unsigned short width;		/* Current window */
+	unsigned short height;		/* sizes */
+	unsigned short x_min;		/* Camera capabilities */
+	unsigned short y_min;
+	unsigned short x_current;	/* Current window location */
+	unsigned short y_current;
+	unsigned short width_min;
+	unsigned short width_max;
+	unsigned short height_min;
+	unsigned short height_max;
+	unsigned short y_skip_top;	/* Lines to skip at the top */
+	unsigned short gain;
+	unsigned short exposure;
+	unsigned char iface;		/* Host number */
+	unsigned char devnum;		/* Device number per host */
+	unsigned char buswidth;		/* See comment in .c */
+	struct soc_camera_ops *ops;
+	struct video_device *vdev;
+	const struct soc_camera_data_format *current_fmt;
+	const struct soc_camera_data_format *formats;
+	int num_formats;
+	struct module *owner;
+	/* soc_camera.c private count. Only accessed with video_lock held */
+	int use_count;
+};
+
+struct soc_camera_file {
+	struct soc_camera_device *icd;
+	struct videobuf_queue vb_vidq;
+	spinlock_t *lock;
+};
+
+struct soc_camera_host {
+	struct list_head list;
+	struct device dev;
+	unsigned char nr;				/* Host number */
+	size_t msize;
+	struct videobuf_queue_ops *vbq_ops;
+	void *priv;
+	char *drv_name;
+	struct soc_camera_host_ops *ops;
+};
+
+struct soc_camera_host_ops {
+	struct module *owner;
+	int (*add)(struct soc_camera_device *);
+	void (*remove)(struct soc_camera_device *);
+	int (*set_fmt_cap)(struct soc_camera_device *, __u32,
+			   struct v4l2_rect *);
+	int (*try_fmt_cap)(struct soc_camera_device *, struct v4l2_format *);
+	int (*reqbufs)(struct soc_camera_file *, struct v4l2_requestbuffers *);
+	int (*querycap)(struct soc_camera_host *, struct v4l2_capability *);
+	int (*try_bus_param)(struct soc_camera_device *, __u32);
+	int (*set_bus_param)(struct soc_camera_device *, __u32);
+	unsigned int (*poll)(struct file *, poll_table *);
+	spinlock_t* (*spinlock_alloc)(struct soc_camera_file *);
+	void (*spinlock_free)(spinlock_t *);
+};
+
+struct soc_camera_link {
+	/* Camera bus id, used to match a camera and a bus */
+	int bus_id;
+	/* GPIO number to switch between 8 and 10 bit modes */
+	unsigned int gpio;
+};
+
+static inline struct soc_camera_device *to_soc_camera_dev(struct device *dev)
+{
+	return container_of(dev, struct soc_camera_device, dev);
+}
+
+static inline struct soc_camera_host *to_soc_camera_host(struct device *dev)
+{
+	return container_of(dev, struct soc_camera_host, dev);
+}
+
+extern int soc_camera_host_register(struct soc_camera_host *ici);
+extern void soc_camera_host_unregister(struct soc_camera_host *ici);
+extern int soc_camera_device_register(struct soc_camera_device *icd);
+extern void soc_camera_device_unregister(struct soc_camera_device *icd);
+
+extern int soc_camera_video_start(struct soc_camera_device *icd);
+extern void soc_camera_video_stop(struct soc_camera_device *icd);
+
+struct soc_camera_data_format {
+	char *name;
+	unsigned int depth;
+	__u32 fourcc;
+	enum v4l2_colorspace colorspace;
+};
+
+struct soc_camera_ops {
+	struct module *owner;
+	int (*probe)(struct soc_camera_device *);
+	void (*remove)(struct soc_camera_device *);
+	int (*init)(struct soc_camera_device *);
+	int (*release)(struct soc_camera_device *);
+	int (*start_capture)(struct soc_camera_device *);
+	int (*stop_capture)(struct soc_camera_device *);
+	int (*set_fmt_cap)(struct soc_camera_device *, __u32,
+			   struct v4l2_rect *);
+	int (*try_fmt_cap)(struct soc_camera_device *, struct v4l2_format *);
+	unsigned long (*query_bus_param)(struct soc_camera_device *);
+	int (*set_bus_param)(struct soc_camera_device *, unsigned long);
+	int (*get_chip_id)(struct soc_camera_device *,
+			   struct v4l2_chip_ident *);
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	int (*get_register)(struct soc_camera_device *, struct v4l2_register *);
+	int (*set_register)(struct soc_camera_device *, struct v4l2_register *);
+#endif
+	int (*get_control)(struct soc_camera_device *, struct v4l2_control *);
+	int (*set_control)(struct soc_camera_device *, struct v4l2_control *);
+	const struct v4l2_queryctrl *controls;
+	int num_controls;
+};
+
+static inline struct v4l2_queryctrl const *soc_camera_find_qctrl(
+	struct soc_camera_ops *ops, int id)
+{
+	int i;
+
+	for (i = 0; i < ops->num_controls; i++)
+		if (ops->controls[i].id == id)
+			return &ops->controls[i];
+
+	return NULL;
+}
+
+#define SOCAM_MASTER			(1 << 0)
+#define SOCAM_SLAVE			(1 << 1)
+#define SOCAM_HSYNC_ACTIVE_HIGH		(1 << 2)
+#define SOCAM_HSYNC_ACTIVE_LOW		(1 << 3)
+#define SOCAM_VSYNC_ACTIVE_HIGH		(1 << 4)
+#define SOCAM_VSYNC_ACTIVE_LOW		(1 << 5)
+#define SOCAM_DATAWIDTH_8		(1 << 6)
+#define SOCAM_DATAWIDTH_9		(1 << 7)
+#define SOCAM_DATAWIDTH_10		(1 << 8)
+#define SOCAM_PCLK_SAMPLE_RISING	(1 << 9)
+#define SOCAM_PCLK_SAMPLE_FALLING	(1 << 10)
+
+#define SOCAM_DATAWIDTH_MASK (SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_9 | \
+			      SOCAM_DATAWIDTH_10)
+
+static inline unsigned long soc_camera_bus_param_compatible(
+			unsigned long camera_flags, unsigned long bus_flags)
+{
+	unsigned long common_flags, hsync, vsync, pclk;
+
+	common_flags = camera_flags & bus_flags;
+
+	hsync = common_flags & (SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW);
+	vsync = common_flags & (SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW);
+	pclk = common_flags & (SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING);
+
+	return (!hsync || !vsync || !pclk) ? 0 : common_flags;
+}
+
+#endif
diff --git a/include/media/tuner-types.h b/include/media/tuner-types.h
index b201371..ab03c53 100644
--- a/include/media/tuner-types.h
+++ b/include/media/tuner-types.h
@@ -6,10 +6,11 @@
 #define __TUNER_TYPES_H__
 
 enum param_type {
-	TUNER_PARAM_TYPE_RADIO, \
-	TUNER_PARAM_TYPE_PAL, \
-	TUNER_PARAM_TYPE_SECAM, \
-	TUNER_PARAM_TYPE_NTSC
+	TUNER_PARAM_TYPE_RADIO,
+	TUNER_PARAM_TYPE_PAL,
+	TUNER_PARAM_TYPE_SECAM,
+	TUNER_PARAM_TYPE_NTSC,
+	TUNER_PARAM_TYPE_DIGITAL,
 };
 
 struct tuner_range {
@@ -105,6 +106,7 @@
 	   the SECAM-L/L' standards. Range: -16:+15 */
 	signed int default_top_secam_high:5;
 
+	u16 iffreq;
 
 	unsigned int count;
 	struct tuner_range *ranges;
@@ -114,6 +116,13 @@
 	char *name;
 	unsigned int count;
 	struct tuner_params *params;
+
+	u16 min;
+	u16 max;
+	u32 stepsize;
+
+	u8 *initdata;
+	u8 *sleepdata;
 };
 
 extern struct tunertype tuners[];
diff --git a/include/media/tuner.h b/include/media/tuner.h
index 1bf24a6..77068fc 100644
--- a/include/media/tuner.h
+++ b/include/media/tuner.h
@@ -78,7 +78,7 @@
 
 #define TUNER_HITACHI_NTSC		40
 #define TUNER_PHILIPS_PAL_MK		41
-#define TUNER_PHILIPS_ATSC		42
+#define TUNER_PHILIPS_FCV1236D		42
 #define TUNER_PHILIPS_FM1236_MK3	43
 
 #define TUNER_PHILIPS_4IN1		44	/* ATI TV Wonder Pro - Conexant */
diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h
index 032bb75..0ea0bd8 100644
--- a/include/media/v4l2-chip-ident.h
+++ b/include/media/v4l2-chip-ident.h
@@ -153,6 +153,12 @@
 	V4L2_IDENT_MSP4428G = 44287,
 	V4L2_IDENT_MSP4448G = 44487,
 	V4L2_IDENT_MSP4458G = 44587,
+
+	/* Micron CMOS sensor chips: 45000-45099 */
+	V4L2_IDENT_MT9M001C12ST		= 45000,
+	V4L2_IDENT_MT9M001C12STM	= 45005,
+	V4L2_IDENT_MT9V022IX7ATC	= 45010, /* No way to detect "normal" I77ATx */
+	V4L2_IDENT_MT9V022IX7ATM	= 45015, /* and "lead free" IA7ATx chips */
 };
 
 #endif
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index f211445..a807d2f 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -318,6 +318,10 @@
 	int (*vidioc_g_chip_ident)     (struct file *file, void *fh,
 					struct v4l2_chip_ident *chip);
 
+	/* For other private ioctls */
+	int (*vidioc_default)	       (struct file *file, void *fh,
+					int cmd, void *arg);
+
 
 #ifdef OBSOLETE_OWNER /* to be removed soon */
 /* obsolete -- fops->owner is used instead */
diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h
index 9903394..5b39a22 100644
--- a/include/media/videobuf-core.h
+++ b/include/media/videobuf-core.h
@@ -13,6 +13,9 @@
  * the Free Software Foundation; either version 2
  */
 
+#ifndef _VIDEOBUF_CORE_H
+#define _VIDEOBUF_CORE_H
+
 #include <linux/poll.h>
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
 #include <linux/videodev.h>
@@ -123,7 +126,8 @@
 struct videobuf_qtype_ops {
 	u32                     magic;
 
-	void* (*alloc)		(size_t size);
+	void *(*alloc)		(size_t size);
+	void *(*vmalloc)	(struct videobuf_buffer *buf);
 	int (*iolock)		(struct videobuf_queue* q,
 				 struct videobuf_buffer *vb,
 				 struct v4l2_framebuffer *fbuf);
@@ -151,7 +155,9 @@
 struct videobuf_queue {
 	struct mutex               vb_lock;
 	spinlock_t                 *irqlock;
-	void			   *dev; /* on pci, points to struct pci_dev */
+	struct device		   *dev;
+
+	wait_queue_head_t	   wait; /* wait if queue is empty */
 
 	enum v4l2_buf_type         type;
 	unsigned int               inputs; /* for V4L2_BUF_FLAG_INPUT */
@@ -183,9 +189,13 @@
 
 void *videobuf_alloc(struct videobuf_queue* q);
 
+/* Used on videobuf-dvb */
+void *videobuf_queue_to_vmalloc (struct videobuf_queue* q,
+				 struct videobuf_buffer *buf);
+
 void videobuf_queue_core_init(struct videobuf_queue *q,
 			 struct videobuf_queue_ops *ops,
-			 void *dev,
+			 struct device *dev,
 			 spinlock_t *irqlock,
 			 enum v4l2_buf_type type,
 			 enum v4l2_field field,
@@ -231,10 +241,4 @@
 int videobuf_mmap_mapper(struct videobuf_queue *q,
 			 struct vm_area_struct *vma);
 
-/* --------------------------------------------------------------------- */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
+#endif
diff --git a/include/media/videobuf-dma-sg.h b/include/media/videobuf-dma-sg.h
index 38105031..be8da26 100644
--- a/include/media/videobuf-dma-sg.h
+++ b/include/media/videobuf-dma-sg.h
@@ -1,5 +1,5 @@
 /*
- * helper functions for PCI DMA video4linux capture buffers
+ * helper functions for SG DMA video4linux capture buffers
  *
  * The functions expect the hardware being able to scatter gatter
  * (i.e. the buffers are not linear in physical memory, but fragmented
@@ -68,9 +68,6 @@
 	/* for kernel buffers */
 	void                *vmalloc;
 
-	/* Stores the userspace pointer to vmalloc area */
-	void                *varea;
-
 	/* for overlay buffers (pci-pci dma) */
 	dma_addr_t          bus_addr;
 
@@ -81,7 +78,7 @@
 	int                 direction;
 };
 
-struct videbuf_pci_sg_memory
+struct videobuf_dma_sg_memory
 {
 	u32                 magic;
 
@@ -103,11 +100,11 @@
 int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma);
 struct videobuf_dmabuf *videobuf_to_dma (struct videobuf_buffer *buf);
 
-void *videobuf_pci_alloc (size_t size);
+void *videobuf_sg_alloc(size_t size);
 
-void videobuf_queue_pci_init(struct videobuf_queue* q,
+void videobuf_queue_sg_init(struct videobuf_queue* q,
 			 struct videobuf_queue_ops *ops,
-			 void *dev,
+			 struct device *dev,
 			 spinlock_t *irqlock,
 			 enum v4l2_buf_type type,
 			 enum v4l2_field field,
@@ -117,6 +114,6 @@
 	/*FIXME: these variants are used only on *-alsa code, where videobuf is
 	 * used without queue
 	 */
-int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma);
-int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma);
+int videobuf_sg_dma_map(struct device *dev, struct videobuf_dmabuf *dma);
+int videobuf_sg_dma_unmap(struct device *dev, struct videobuf_dmabuf *dma);
 
diff --git a/include/media/videobuf-dvb.h b/include/media/videobuf-dvb.h
index 8233caf..b777486 100644
--- a/include/media/videobuf-dvb.h
+++ b/include/media/videobuf-dvb.h
@@ -27,7 +27,8 @@
 int videobuf_dvb_register(struct videobuf_dvb *dvb,
 			  struct module *module,
 			  void *adapter_priv,
-			  struct device *device);
+			  struct device *device,
+			  short *adapter_nr);
 void videobuf_dvb_unregister(struct videobuf_dvb *dvb);
 
 /*
diff --git a/include/media/videobuf-vmalloc.h b/include/media/videobuf-vmalloc.h
index ec63ab0..aed3946 100644
--- a/include/media/videobuf-vmalloc.h
+++ b/include/media/videobuf-vmalloc.h
@@ -12,6 +12,8 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2
  */
+#ifndef _VIDEOBUF_VMALLOC_H
+#define _VIDEOBUF_VMALLOC_H
 
 #include <media/videobuf-core.h>
 
@@ -39,3 +41,5 @@
 void *videobuf_to_vmalloc (struct videobuf_buffer *buf);
 
 void videobuf_vmalloc_free (struct videobuf_buffer *buf);
+
+#endif
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 49c4898..e0a612b 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -383,6 +383,15 @@
 		== htonl(0x20010010));
 }
 
+static inline void ipv6_addr_set_v4mapped(const __be32 addr,
+					  struct in6_addr *v4mapped)
+{
+	ipv6_addr_set(v4mapped,
+			0, 0,
+			htonl(0x0000FFFF),
+			addr);
+}
+
 /*
  * find the first different bit between two addresses
  * length of address must be a multiple of 32bits
diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h
index 0148058..049edc5 100644
--- a/include/sound/ac97_codec.h
+++ b/include/sound/ac97_codec.h
@@ -397,6 +397,7 @@
 #define AC97_HAS_NO_TONE	(1<<16) /* no Tone volume */
 #define AC97_HAS_NO_STD_PCM	(1<<17)	/* no standard AC97 PCM volume and mute */
 #define AC97_HAS_NO_AUX		(1<<18) /* no standard AC97 AUX volume and mute */
+#define AC97_HAS_8CH		(1<<19) /* supports 8-channel output */
 
 /* rates indexes */
 #define AC97_RATES_FRONT_DAC	0
diff --git a/include/sound/ak4114.h b/include/sound/ak4114.h
index 4e80d3f..d293d36 100644
--- a/include/sound/ak4114.h
+++ b/include/sound/ak4114.h
@@ -182,6 +182,7 @@
 	unsigned char rcs0;
 	unsigned char rcs1;
 	struct delayed_work work;
+	unsigned int check_flags;
 	void *change_callback_private;
 	void (*change_callback)(struct ak4114 *ak4114, unsigned char c0, unsigned char c1);
 };
diff --git a/include/sound/ak4xxx-adda.h b/include/sound/ak4xxx-adda.h
index 6153b91..891cf1a 100644
--- a/include/sound/ak4xxx-adda.h
+++ b/include/sound/ak4xxx-adda.h
@@ -68,7 +68,7 @@
 	enum {
 		SND_AK4524, SND_AK4528, SND_AK4529,
 		SND_AK4355, SND_AK4358, SND_AK4381,
-		SND_AK5365, NON_AKM
+		SND_AK5365
 	} type;
 
 	/* (array) information of combined codecs */
diff --git a/include/sound/asoundef.h b/include/sound/asoundef.h
index 024ce62..a6e0fac 100644
--- a/include/sound/asoundef.h
+++ b/include/sound/asoundef.h
@@ -112,6 +112,14 @@
 #define IEC958_AES3_CON_CLOCK_1000PPM	(0<<4)	/* 1000 ppm */
 #define IEC958_AES3_CON_CLOCK_50PPM	(1<<4)	/* 50 ppm */
 #define IEC958_AES3_CON_CLOCK_VARIABLE	(2<<4)	/* variable pitch */
+#define IEC958_AES4_CON_MAX_WORDLEN_24	(1<<0)	/* 0 = 20-bit, 1 = 24-bit */
+#define IEC958_AES4_CON_WORDLEN		(7<<1)	/* mask - sample word length */
+#define IEC958_AES4_CON_WORDLEN_NOTID	(0<<1)	/* not indicated */
+#define IEC958_AES4_CON_WORDLEN_20_16	(1<<1)	/* 20-bit or 16-bit */
+#define IEC958_AES4_CON_WORDLEN_22_18	(2<<1)	/* 22-bit or 18-bit */
+#define IEC958_AES4_CON_WORDLEN_23_19	(4<<1)	/* 23-bit or 19-bit */
+#define IEC958_AES4_CON_WORDLEN_24_20	(5<<1)	/* 24-bit or 20-bit */
+#define IEC958_AES4_CON_WORDLEN_21_17	(6<<1)	/* 21-bit or 17-bit */
 
 /*****************************************************************************
  *                                                                           *
diff --git a/include/sound/control.h b/include/sound/control.h
index e79baa6..3dc1291 100644
--- a/include/sound/control.h
+++ b/include/sound/control.h
@@ -169,4 +169,11 @@
 int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_info *uinfo);
 
+/*
+ * virtual master control
+ */
+struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
+						 const unsigned int *tlv);
+int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave);
+		      
 #endif	/* __SOUND_CONTROL_H */
diff --git a/include/sound/core.h b/include/sound/core.h
index 4fc0235..695ee53 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -277,8 +277,8 @@
 int snd_minor_info_oss_init(void);
 int snd_minor_info_oss_done(void);
 #else
-#define snd_minor_info_oss_init() /*NOP*/
-#define snd_minor_info_oss_done() /*NOP*/
+static inline int snd_minor_info_oss_init(void) { return 0; }
+static inline int snd_minor_info_oss_done(void) { return 0; }
 #endif
 
 /* memory.c */
@@ -310,7 +310,7 @@
 int snd_card_file_remove(struct snd_card *card, struct file *file);
 
 #ifndef snd_card_set_dev
-#define snd_card_set_dev(card,devptr) ((card)->dev = (devptr))
+#define snd_card_set_dev(card, devptr) ((card)->dev = (devptr))
 #endif
 
 /* device.c */
@@ -373,7 +373,7 @@
  * snd_printd - debug printk
  * @fmt: format string
  *
- * Compiled only when Works like snd_printk() for debugging purpose.
+ * Works like snd_printk() for debugging purposes.
  * Ignored when CONFIG_SND_DEBUG is not set.
  */
 #define snd_printd(fmt, args...) \
@@ -417,7 +417,7 @@
  * snd_printdd - debug printk
  * @format: format string
  *
- * Compiled only when Works like snd_printk() for debugging purpose.
+ * Works like snd_printk() for debugging purposes.
  * Ignored when CONFIG_SND_DEBUG_DETECT is not set.
  */
 #define snd_printdd(format, args...) snd_printk(format, ##args)
diff --git a/include/sound/mpu401.h b/include/sound/mpu401.h
index d45218b..68b634b 100644
--- a/include/sound/mpu401.h
+++ b/include/sound/mpu401.h
@@ -103,6 +103,21 @@
 #define MPU401D(mpu) (mpu)->port
 
 /*
+ * control register bits
+ */
+/* read MPU401C() */
+#define MPU401_RX_EMPTY		0x80
+#define MPU401_TX_FULL		0x40
+
+/* write MPU401C() */
+#define MPU401_RESET		0xff
+#define MPU401_ENTER_UART	0x3f
+
+/* read MPU401D() */
+#define MPU401_ACK		0xfe
+
+
+/*
 
  */
 
diff --git a/include/sound/version.h b/include/sound/version.h
index fac66c4..ed6fb2e 100644
--- a/include/sound/version.h
+++ b/include/sound/version.h
@@ -1,3 +1,3 @@
 /* include/version.h.  Generated by alsa/ksync script.  */
-#define CONFIG_SND_VERSION "1.0.16rc2"
-#define CONFIG_SND_DATE " (Thu Jan 31 16:40:16 2008 UTC)"
+#define CONFIG_SND_VERSION "1.0.16"
+#define CONFIG_SND_DATE ""
diff --git a/lib/lmb.c b/lib/lmb.c
index 896e283..207147a 100644
--- a/lib/lmb.c
+++ b/lib/lmb.c
@@ -346,7 +346,7 @@
 			if (j < 0) {
 				/* this area isn't reserved, take it */
 				if (lmb_add_region(&lmb.reserved, base,
-						   size) < 0)
+						   lmb_align_up(size, align)) < 0)
 					return 0;
 				return base;
 			}
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index bc39e41..cf857c4 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -82,6 +82,11 @@
 	return mutex_trylock(&rtnl_mutex);
 }
 
+int rtnl_is_locked(void)
+{
+	return mutex_is_locked(&rtnl_mutex);
+}
+
 static struct rtnl_link *rtnl_msg_handlers[NPROTO];
 
 static inline int rtm_msgindex(int msgtype)
@@ -1402,6 +1407,7 @@
 EXPORT_SYMBOL(rtnl_lock);
 EXPORT_SYMBOL(rtnl_trylock);
 EXPORT_SYMBOL(rtnl_unlock);
+EXPORT_SYMBOL(rtnl_is_locked);
 EXPORT_SYMBOL(rtnl_unicast);
 EXPORT_SYMBOL(rtnl_notify);
 EXPORT_SYMBOL(rtnl_set_sk_err);
diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c
index 02088de..2e2fc33 100644
--- a/net/ipv4/fib_hash.c
+++ b/net/ipv4/fib_hash.c
@@ -1003,7 +1003,7 @@
 static int fib_seq_show(struct seq_file *seq, void *v)
 {
 	struct fib_iter_state *iter;
-	char bf[128];
+	int len;
 	__be32 prefix, mask;
 	unsigned flags;
 	struct fib_node *f;
@@ -1025,18 +1025,19 @@
 	mask	= FZ_MASK(iter->zone);
 	flags	= fib_flag_trans(fa->fa_type, mask, fi);
 	if (fi)
-		snprintf(bf, sizeof(bf),
-			 "%s\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u",
+		seq_printf(seq,
+			 "%s\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u%n",
 			 fi->fib_dev ? fi->fib_dev->name : "*", prefix,
 			 fi->fib_nh->nh_gw, flags, 0, 0, fi->fib_priority,
 			 mask, (fi->fib_advmss ? fi->fib_advmss + 40 : 0),
 			 fi->fib_window,
-			 fi->fib_rtt >> 3);
+			 fi->fib_rtt >> 3, &len);
 	else
-		snprintf(bf, sizeof(bf),
-			 "*\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u",
-			 prefix, 0, flags, 0, 0, 0, mask, 0, 0, 0);
-	seq_printf(seq, "%-127s\n", bf);
+		seq_printf(seq,
+			 "*\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u%n",
+			 prefix, 0, flags, 0, 0, 0, mask, 0, 0, 0, &len);
+
+	seq_printf(seq, "%*s\n", 127 - len, "");
 out:
 	return 0;
 }
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index ea294ff..4b02d14 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -2602,15 +2602,16 @@
 		list_for_each_entry_rcu(fa, &li->falh, fa_list) {
 			const struct fib_info *fi = fa->fa_info;
 			unsigned flags = fib_flag_trans(fa->fa_type, mask, fi);
-			char bf[128];
+			int len;
 
 			if (fa->fa_type == RTN_BROADCAST
 			    || fa->fa_type == RTN_MULTICAST)
 				continue;
 
 			if (fi)
-				snprintf(bf, sizeof(bf),
-					 "%s\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u",
+				seq_printf(seq,
+					 "%s\t%08X\t%08X\t%04X\t%d\t%u\t"
+					 "%d\t%08X\t%d\t%u\t%u%n",
 					 fi->fib_dev ? fi->fib_dev->name : "*",
 					 prefix,
 					 fi->fib_nh->nh_gw, flags, 0, 0,
@@ -2619,14 +2620,15 @@
 					 (fi->fib_advmss ?
 					  fi->fib_advmss + 40 : 0),
 					 fi->fib_window,
-					 fi->fib_rtt >> 3);
+					 fi->fib_rtt >> 3, &len);
 			else
-				snprintf(bf, sizeof(bf),
-					 "*\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u",
+				seq_printf(seq,
+					 "*\t%08X\t%08X\t%04X\t%d\t%u\t"
+					 "%d\t%08X\t%d\t%u\t%u%n",
 					 prefix, 0, flags, 0, 0, 0,
-					 mask, 0, 0, 0);
+					 mask, 0, 0, 0, &len);
 
-			seq_printf(seq, "%-127s\n", bf);
+			seq_printf(seq, "%*s\n", 127 - len, "");
 		}
 	}
 
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 780e948..ce25a13 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -367,10 +367,10 @@
 			   "HHUptod\tSpecDst");
 	else {
 		struct rtable *r = v;
-		char temp[256];
+		int len;
 
-		sprintf(temp, "%s\t%08lX\t%08lX\t%8X\t%d\t%u\t%d\t"
-			      "%08lX\t%d\t%u\t%u\t%02X\t%d\t%1d\t%08X",
+		seq_printf(seq, "%s\t%08lX\t%08lX\t%8X\t%d\t%u\t%d\t"
+			      "%08lX\t%d\t%u\t%u\t%02X\t%d\t%1d\t%08X%n",
 			r->u.dst.dev ? r->u.dst.dev->name : "*",
 			(unsigned long)r->rt_dst, (unsigned long)r->rt_gateway,
 			r->rt_flags, atomic_read(&r->u.dst.__refcnt),
@@ -384,8 +384,9 @@
 			r->u.dst.hh ? atomic_read(&r->u.dst.hh->hh_refcnt) : -1,
 			r->u.dst.hh ? (r->u.dst.hh->hh_output ==
 				       dev_queue_xmit) : 0,
-			r->rt_spec_dst);
-		seq_printf(seq, "%-127s\n", temp);
+			r->rt_spec_dst, &len);
+
+		seq_printf(seq, "%*s\n", 127 - len, "");
 	}
 	return 0;
 }
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 7766151..0e9bc12 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -2255,13 +2255,13 @@
 }
 
 static void get_openreq4(struct sock *sk, struct request_sock *req,
-			 char *tmpbuf, int i, int uid)
+			 struct seq_file *f, int i, int uid, int *len)
 {
 	const struct inet_request_sock *ireq = inet_rsk(req);
 	int ttd = req->expires - jiffies;
 
-	sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X"
-		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %u %d %p",
+	seq_printf(f, "%4d: %08X:%04X %08X:%04X"
+		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %u %d %p%n",
 		i,
 		ireq->loc_addr,
 		ntohs(inet_sk(sk)->sport),
@@ -2276,10 +2276,11 @@
 		0,  /* non standard timer */
 		0, /* open_requests have no inode */
 		atomic_read(&sk->sk_refcnt),
-		req);
+		req,
+		len);
 }
 
-static void get_tcp4_sock(struct sock *sk, char *tmpbuf, int i)
+static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
 {
 	int timer_active;
 	unsigned long timer_expires;
@@ -2305,8 +2306,8 @@
 		timer_expires = jiffies;
 	}
 
-	sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX "
-			"%08X %5d %8d %lu %d %p %u %u %u %u %d",
+	seq_printf(f, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX "
+			"%08X %5d %8d %lu %d %p %u %u %u %u %d%n",
 		i, src, srcp, dest, destp, sk->sk_state,
 		tp->write_seq - tp->snd_una,
 		sk->sk_state == TCP_LISTEN ? sk->sk_ack_backlog :
@@ -2322,11 +2323,12 @@
 		icsk->icsk_ack.ato,
 		(icsk->icsk_ack.quick << 1) | icsk->icsk_ack.pingpong,
 		tp->snd_cwnd,
-		tp->snd_ssthresh >= 0xFFFF ? -1 : tp->snd_ssthresh);
+		tp->snd_ssthresh >= 0xFFFF ? -1 : tp->snd_ssthresh,
+		len);
 }
 
 static void get_timewait4_sock(struct inet_timewait_sock *tw,
-			       char *tmpbuf, int i)
+			       struct seq_file *f, int i, int *len)
 {
 	__be32 dest, src;
 	__u16 destp, srcp;
@@ -2340,11 +2342,11 @@
 	destp = ntohs(tw->tw_dport);
 	srcp  = ntohs(tw->tw_sport);
 
-	sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X"
-		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p",
+	seq_printf(f, "%4d: %08X:%04X %08X:%04X"
+		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p%n",
 		i, src, srcp, dest, destp, tw->tw_substate, 0, 0,
 		3, jiffies_to_clock_t(ttd), 0, 0, 0, 0,
-		atomic_read(&tw->tw_refcnt), tw);
+		atomic_read(&tw->tw_refcnt), tw, len);
 }
 
 #define TMPSZ 150
@@ -2352,7 +2354,7 @@
 static int tcp4_seq_show(struct seq_file *seq, void *v)
 {
 	struct tcp_iter_state* st;
-	char tmpbuf[TMPSZ + 1];
+	int len;
 
 	if (v == SEQ_START_TOKEN) {
 		seq_printf(seq, "%-*s\n", TMPSZ - 1,
@@ -2366,16 +2368,16 @@
 	switch (st->state) {
 	case TCP_SEQ_STATE_LISTENING:
 	case TCP_SEQ_STATE_ESTABLISHED:
-		get_tcp4_sock(v, tmpbuf, st->num);
+		get_tcp4_sock(v, seq, st->num, &len);
 		break;
 	case TCP_SEQ_STATE_OPENREQ:
-		get_openreq4(st->syn_wait_sk, v, tmpbuf, st->num, st->uid);
+		get_openreq4(st->syn_wait_sk, v, seq, st->num, st->uid, &len);
 		break;
 	case TCP_SEQ_STATE_TIME_WAIT:
-		get_timewait4_sock(v, tmpbuf, st->num);
+		get_timewait4_sock(v, seq, st->num, &len);
 		break;
 	}
-	seq_printf(seq, "%-*s\n", TMPSZ - 1, tmpbuf);
+	seq_printf(seq, "%*s\n", TMPSZ - 1 - len, "");
 out:
 	return 0;
 }
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index b053ac7..1f535e31 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1619,7 +1619,8 @@
 }
 
 /* ------------------------------------------------------------------------ */
-static void udp4_format_sock(struct sock *sp, char *tmpbuf, int bucket)
+static void udp4_format_sock(struct sock *sp, struct seq_file *f,
+		int bucket, int *len)
 {
 	struct inet_sock *inet = inet_sk(sp);
 	__be32 dest = inet->daddr;
@@ -1627,13 +1628,13 @@
 	__u16 destp	  = ntohs(inet->dport);
 	__u16 srcp	  = ntohs(inet->sport);
 
-	sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X"
-		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p",
+	seq_printf(f, "%4d: %08X:%04X %08X:%04X"
+		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p%n",
 		bucket, src, srcp, dest, destp, sp->sk_state,
 		atomic_read(&sp->sk_wmem_alloc),
 		atomic_read(&sp->sk_rmem_alloc),
 		0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp),
-		atomic_read(&sp->sk_refcnt), sp);
+		atomic_read(&sp->sk_refcnt), sp, len);
 }
 
 int udp4_seq_show(struct seq_file *seq, void *v)
@@ -1644,11 +1645,11 @@
 			   "rx_queue tr tm->when retrnsmt   uid  timeout "
 			   "inode");
 	else {
-		char tmpbuf[129];
 		struct udp_iter_state *state = seq->private;
+		int len;
 
-		udp4_format_sock(v, tmpbuf, state->bucket);
-		seq_printf(seq, "%-127s\n", tmpbuf);
+		udp4_format_sock(v, seq, state->bucket, &len);
+		seq_printf(seq, "%*s\n", 127 - len ,"");
 	}
 	return 0;
 }
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 6b75cb6..a5e5c31 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2248,10 +2248,13 @@
 				 struct ieee80211_sta_bss *bss)
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	if (!atomic_dec_and_test(&bss->users))
-		return;
 
-	spin_lock_bh(&local->sta_bss_lock);
+	local_bh_disable();
+	if (!atomic_dec_and_lock(&bss->users, &local->sta_bss_lock)) {
+		local_bh_enable();
+		return;
+	}
+
 	__ieee80211_rx_bss_hash_del(dev, bss);
 	list_del(&bss->list);
 	spin_unlock_bh(&local->sta_bss_lock);
@@ -2709,7 +2712,26 @@
 			bss->wmm_ie_len = elems.wmm_param_len + 2;
 		} else
 			bss->wmm_ie_len = 0;
-	} else if (!elems.wmm_param && bss->wmm_ie) {
+	} else if (elems.wmm_info &&
+		    (!bss->wmm_ie || bss->wmm_ie_len != elems.wmm_info_len ||
+		     memcmp(bss->wmm_ie, elems.wmm_info, elems.wmm_info_len))) {
+		 /* As for certain AP's Fifth bit is not set in WMM IE in
+		  * beacon frames.So while parsing the beacon frame the
+		  * wmm_info structure is used instead of wmm_param.
+		  * wmm_info structure was never used to set bss->wmm_ie.
+		  * This code fixes this problem by copying the WME
+		  * information from wmm_info to bss->wmm_ie and enabling
+		  * n-band association.
+		  */
+		kfree(bss->wmm_ie);
+		bss->wmm_ie = kmalloc(elems.wmm_info_len + 2, GFP_ATOMIC);
+		if (bss->wmm_ie) {
+			memcpy(bss->wmm_ie, elems.wmm_info - 2,
+			       elems.wmm_info_len + 2);
+			bss->wmm_ie_len = elems.wmm_info_len + 2;
+		} else
+			bss->wmm_ie_len = 0;
+	} else if (!elems.wmm_param && !elems.wmm_info && bss->wmm_ie) {
 		kfree(bss->wmm_ie);
 		bss->wmm_ie = NULL;
 		bss->wmm_ie_len = 0;
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 52e4554..02f436a 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2170,7 +2170,7 @@
 	struct ieee80211_supported_band *sband;
 
 	if (status->band < 0 ||
-	    status->band > IEEE80211_NUM_BANDS) {
+	    status->band >= IEEE80211_NUM_BANDS) {
 		WARN_ON(1);
 		return;
 	}
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 4e94e40..64faa3d 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -709,7 +709,7 @@
 	struct ieee80211_sched_data *q = qdisc_priv(root_qd);
 	struct Qdisc *qdisc = q->queues[queue];
 	struct sk_buff *skb = NULL;
-	u32 len = qdisc->q.qlen;
+	u32 len;
 
 	if (!qdisc || !qdisc->dequeue)
 		return;
diff --git a/net/sctp/objcnt.c b/net/sctp/objcnt.c
index cfeb07e..f73ec0e 100644
--- a/net/sctp/objcnt.c
+++ b/net/sctp/objcnt.c
@@ -83,13 +83,12 @@
  */
 static int sctp_objcnt_seq_show(struct seq_file *seq, void *v)
 {
-	int i;
-	char temp[128];
+	int i, len;
 
 	i = (int)*(loff_t *)v;
-	sprintf(temp, "%s: %d", sctp_dbg_objcnt[i].label,
-				atomic_read(sctp_dbg_objcnt[i].counter));
-	seq_printf(seq, "%-127s\n", temp);
+	seq_printf(seq, "%s: %d%n", sctp_dbg_objcnt[i].label,
+				atomic_read(sctp_dbg_objcnt[i].counter), &len);
+	seq_printf(seq, "%*s\n", 127 - len, "");
 	return 0;
 }
 
diff --git a/net/sunrpc/auth_gss/gss_generic_token.c b/net/sunrpc/auth_gss/gss_generic_token.c
index ea8c92e..d83b881 100644
--- a/net/sunrpc/auth_gss/gss_generic_token.c
+++ b/net/sunrpc/auth_gss/gss_generic_token.c
@@ -148,7 +148,7 @@
 g_token_size(struct xdr_netobj *mech, unsigned int body_size)
 {
 	/* set body_size to sequence contents size */
-	body_size += 4 + (int) mech->len;         /* NEED overflow check */
+	body_size += 2 + (int) mech->len;         /* NEED overflow check */
 	return(1 + der_length_size(body_size) + body_size);
 }
 
@@ -161,7 +161,7 @@
 g_make_token_header(struct xdr_netobj *mech, int body_size, unsigned char **buf)
 {
 	*(*buf)++ = 0x60;
-	der_write_length(buf, 4 + mech->len + body_size);
+	der_write_length(buf, 2 + mech->len + body_size);
 	*(*buf)++ = 0x06;
 	*(*buf)++ = (unsigned char) mech->len;
 	TWRITE_STR(*buf, mech->data, ((int) mech->len));
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c
index 0dd7923..1d52308 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -66,8 +66,8 @@
 		goto out;
 
 	if (crypto_blkcipher_ivsize(tfm) > 16) {
-		dprintk("RPC:       gss_k5encrypt: tfm iv size to large %d\n",
-			 crypto_blkcipher_ivsize(tfm));
+		dprintk("RPC:       gss_k5encrypt: tfm iv size too large %d\n",
+			crypto_blkcipher_ivsize(tfm));
 		goto out;
 	}
 
@@ -102,7 +102,7 @@
 		goto out;
 
 	if (crypto_blkcipher_ivsize(tfm) > 16) {
-		dprintk("RPC:       gss_k5decrypt: tfm iv size to large %d\n",
+		dprintk("RPC:       gss_k5decrypt: tfm iv size too large %d\n",
 			crypto_blkcipher_ivsize(tfm));
 		goto out;
 	}
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c
index dedcbd61..5f1d36d 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seal.c
@@ -87,10 +87,10 @@
 
 	now = get_seconds();
 
-	token->len = g_token_size(&ctx->mech_used, 22);
+	token->len = g_token_size(&ctx->mech_used, 24);
 
 	ptr = token->data;
-	g_make_token_header(&ctx->mech_used, 22, &ptr);
+	g_make_token_header(&ctx->mech_used, 24, &ptr);
 
 	*ptr++ = (unsigned char) ((KG_TOK_MIC_MSG>>8)&0xff);
 	*ptr++ = (unsigned char) (KG_TOK_MIC_MSG&0xff);
@@ -109,15 +109,14 @@
 			  md5cksum.data, md5cksum.len))
 		return GSS_S_FAILURE;
 
-	memcpy(krb5_hdr + 16, md5cksum.data + md5cksum.len - KRB5_CKSUM_LENGTH,
-	       KRB5_CKSUM_LENGTH);
+	memcpy(krb5_hdr + 16, md5cksum.data + md5cksum.len - 8, 8);
 
 	spin_lock(&krb5_seq_lock);
 	seq_send = ctx->seq_send++;
 	spin_unlock(&krb5_seq_lock);
 
 	if (krb5_make_seq_num(ctx->seq, ctx->initiate ? 0 : 0xff,
-			       ctx->seq_send, krb5_hdr + 16, krb5_hdr + 8))
+			      seq_send, krb5_hdr + 16, krb5_hdr + 8))
 		return GSS_S_FAILURE;
 
 	return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
diff --git a/net/sunrpc/auth_gss/gss_krb5_seqnum.c b/net/sunrpc/auth_gss/gss_krb5_seqnum.c
index 43f3421..f160be6 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seqnum.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seqnum.c
@@ -43,7 +43,7 @@
 s32
 krb5_make_seq_num(struct crypto_blkcipher *key,
 		int direction,
-		s32 seqnum,
+		u32 seqnum,
 		unsigned char *cksum, unsigned char *buf)
 {
 	unsigned char plain[8];
@@ -65,7 +65,7 @@
 krb5_get_seq_num(struct crypto_blkcipher *key,
 	       unsigned char *cksum,
 	       unsigned char *buf,
-	       int *direction, s32 * seqnum)
+	       int *direction, u32 *seqnum)
 {
 	s32 code;
 	unsigned char plain[8];
diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c
index e30a993..d91a5d0 100644
--- a/net/sunrpc/auth_gss/gss_krb5_unseal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c
@@ -82,7 +82,7 @@
 	struct xdr_netobj	md5cksum = {.len = 0, .data = cksumdata};
 	s32			now;
 	int			direction;
-	s32			seqnum;
+	u32			seqnum;
 	unsigned char		*ptr = (unsigned char *)read_token->data;
 	int			bodysize;
 
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index 3bdc527..b00b1b4 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -137,7 +137,7 @@
 	BUG_ON((buf->len - offset) % blocksize);
 	plainlen = blocksize + buf->len - offset;
 
-	headlen = g_token_size(&kctx->mech_used, 22 + plainlen) -
+	headlen = g_token_size(&kctx->mech_used, 24 + plainlen) -
 						(buf->len - offset);
 
 	ptr = buf->head[0].iov_base + offset;
@@ -149,7 +149,7 @@
 	buf->len += headlen;
 	BUG_ON((buf->len - offset - headlen) % blocksize);
 
-	g_make_token_header(&kctx->mech_used, 22 + plainlen, &ptr);
+	g_make_token_header(&kctx->mech_used, 24 + plainlen, &ptr);
 
 
 	*ptr++ = (unsigned char) ((KG_TOK_WRAP_MSG>>8)&0xff);
@@ -176,9 +176,7 @@
 	if (krb5_encrypt(kctx->seq, NULL, md5cksum.data,
 			  md5cksum.data, md5cksum.len))
 		return GSS_S_FAILURE;
-	memcpy(krb5_hdr + 16,
-	       md5cksum.data + md5cksum.len - KRB5_CKSUM_LENGTH,
-	       KRB5_CKSUM_LENGTH);
+	memcpy(krb5_hdr + 16, md5cksum.data + md5cksum.len - 8, 8);
 
 	spin_lock(&krb5_seq_lock);
 	seq_send = kctx->seq_send++;
diff --git a/net/sunrpc/auth_gss/gss_spkm3_seal.c b/net/sunrpc/auth_gss/gss_spkm3_seal.c
index abf17ce..c832712 100644
--- a/net/sunrpc/auth_gss/gss_spkm3_seal.c
+++ b/net/sunrpc/auth_gss/gss_spkm3_seal.c
@@ -107,10 +107,10 @@
 		tokenlen = 10 + ctxelen + 1 + md5elen + 1;
 
 		/* Create token header using generic routines */
-		token->len = g_token_size(&ctx->mech_used, tokenlen);
+		token->len = g_token_size(&ctx->mech_used, tokenlen + 2);
 
 		ptr = token->data;
-		g_make_token_header(&ctx->mech_used, tokenlen, &ptr);
+		g_make_token_header(&ctx->mech_used, tokenlen + 2, &ptr);
 
 		spkm3_make_mic_token(&ptr, tokenlen, &mic_hdr, &md5cksum, md5elen, md5zbit);
 	} else if (toktype == SPKM_WRAP_TOK) { /* Not Supported */
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index 481f984..5905d567 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -1146,7 +1146,7 @@
 		case RPC_GSS_SVC_INTEGRITY:
 			if (unwrap_integ_data(&rqstp->rq_arg,
 					gc->gc_seq, rsci->mechctx))
-				goto auth_err;
+				goto garbage_args;
 			/* placeholders for length and seq. number: */
 			svc_putnl(resv, 0);
 			svc_putnl(resv, 0);
@@ -1154,7 +1154,7 @@
 		case RPC_GSS_SVC_PRIVACY:
 			if (unwrap_priv_data(rqstp, &rqstp->rq_arg,
 					gc->gc_seq, rsci->mechctx))
-				goto auth_err;
+				goto garbage_args;
 			/* placeholders for length and seq. number: */
 			svc_putnl(resv, 0);
 			svc_putnl(resv, 0);
@@ -1169,6 +1169,11 @@
 		ret = SVC_OK;
 		goto out;
 	}
+garbage_args:
+	/* Restore write pointer to its original value: */
+	xdr_ressize_check(rqstp, reject_stat);
+	ret = SVC_GARBAGE;
+	goto out;
 auth_err:
 	/* Restore write pointer to its original value: */
 	xdr_ressize_check(rqstp, reject_stat);
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index b5f2786..d75530f 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -571,7 +571,6 @@
 		return -ETIMEDOUT;
 
 	dreq->item = item;
-	dreq->recv_time = get_seconds();
 
 	spin_lock(&cache_defer_lock);
 
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 090af78..d74c2d2 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -510,8 +510,7 @@
 static int
 svc_init_buffer(struct svc_rqst *rqstp, unsigned int size)
 {
-	int pages;
-	int arghi;
+	unsigned int pages, arghi;
 
 	pages = size / PAGE_SIZE + 1; /* extra page as we hold both request and reply.
 				       * We assume one is at most one page
@@ -525,7 +524,7 @@
 		rqstp->rq_pages[arghi++] = p;
 		pages--;
 	}
-	return ! pages;
+	return pages == 0;
 }
 
 /*
@@ -534,8 +533,9 @@
 static void
 svc_release_buffer(struct svc_rqst *rqstp)
 {
-	int i;
-	for (i=0; i<ARRAY_SIZE(rqstp->rq_pages); i++)
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(rqstp->rq_pages); i++)
 		if (rqstp->rq_pages[i])
 			put_page(rqstp->rq_pages[i]);
 }
@@ -590,7 +590,7 @@
 	struct svc_rqst	*rqstp;
 	int		error = -ENOMEM;
 	int		have_oldmask = 0;
-	cpumask_t	oldmask;
+	cpumask_t	uninitialized_var(oldmask);
 
 	rqstp = svc_prepare_thread(serv, pool);
 	if (IS_ERR(rqstp)) {
@@ -619,16 +619,6 @@
 }
 
 /*
- * Create a thread in the default pool.  Caller must hold BKL.
- */
-int
-svc_create_thread(svc_thread_fn func, struct svc_serv *serv)
-{
-	return __svc_create_thread(func, serv, &serv->sv_pools[0]);
-}
-EXPORT_SYMBOL(svc_create_thread);
-
-/*
  * Choose a pool in which to create a new thread, for svc_set_num_threads
  */
 static inline struct svc_pool *
@@ -921,8 +911,7 @@
 	case SVC_OK:
 		break;
 	case SVC_GARBAGE:
-		rpc_stat = rpc_garbage_args;
-		goto err_bad;
+		goto err_garbage;
 	case SVC_SYSERR:
 		rpc_stat = rpc_system_err;
 		goto err_bad;
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index 332eb47..d8e8d79 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -18,6 +18,7 @@
 #include <linux/skbuff.h>
 #include <linux/file.h>
 #include <linux/freezer.h>
+#include <linux/kthread.h>
 #include <net/sock.h>
 #include <net/checksum.h>
 #include <net/ip.h>
@@ -586,8 +587,12 @@
 		while (rqstp->rq_pages[i] == NULL) {
 			struct page *p = alloc_page(GFP_KERNEL);
 			if (!p) {
-				int j = msecs_to_jiffies(500);
-				schedule_timeout_uninterruptible(j);
+				set_current_state(TASK_INTERRUPTIBLE);
+				if (signalled() || kthread_should_stop()) {
+					set_current_state(TASK_RUNNING);
+					return -EINTR;
+				}
+				schedule_timeout(msecs_to_jiffies(500));
 			}
 			rqstp->rq_pages[i] = p;
 		}
@@ -607,7 +612,7 @@
 
 	try_to_freeze();
 	cond_resched();
-	if (signalled())
+	if (signalled() || kthread_should_stop())
 		return -EINTR;
 
 	spin_lock_bh(&pool->sp_lock);
@@ -626,6 +631,20 @@
 		 * to bring down the daemons ...
 		 */
 		set_current_state(TASK_INTERRUPTIBLE);
+
+		/*
+		 * checking kthread_should_stop() here allows us to avoid
+		 * locking and signalling when stopping kthreads that call
+		 * svc_recv. If the thread has already been woken up, then
+		 * we can exit here without sleeping. If not, then it
+		 * it'll be woken up quickly during the schedule_timeout
+		 */
+		if (kthread_should_stop()) {
+			set_current_state(TASK_RUNNING);
+			spin_unlock_bh(&pool->sp_lock);
+			return -EINTR;
+		}
+
 		add_wait_queue(&rqstp->rq_wait, &wait);
 		spin_unlock_bh(&pool->sp_lock);
 
@@ -641,7 +660,10 @@
 			svc_thread_dequeue(pool, rqstp);
 			spin_unlock_bh(&pool->sp_lock);
 			dprintk("svc: server %p, no data yet\n", rqstp);
-			return signalled()? -EINTR : -EAGAIN;
+			if (signalled() || kthread_should_stop())
+				return -EINTR;
+			else
+				return -EAGAIN;
 		}
 	}
 	spin_unlock_bh(&pool->sp_lock);
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 3c64051..3f30ee6 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -11,7 +11,8 @@
 #include <linux/hash.h>
 #include <linux/string.h>
 #include <net/sock.h>
-
+#include <net/ipv6.h>
+#include <linux/kernel.h>
 #define RPCDBG_FACILITY	RPCDBG_AUTH
 
 
@@ -85,7 +86,7 @@
 struct ip_map {
 	struct cache_head	h;
 	char			m_class[8]; /* e.g. "nfsd" */
-	struct in_addr		m_addr;
+	struct in6_addr		m_addr;
 	struct unix_domain	*m_client;
 	int			m_add_change;
 };
@@ -113,12 +114,19 @@
 	return (hash ^ (hash>>8)) & 0xff;
 }
 #endif
+static inline int hash_ip6(struct in6_addr ip)
+{
+	return (hash_ip(ip.s6_addr32[0]) ^
+		hash_ip(ip.s6_addr32[1]) ^
+		hash_ip(ip.s6_addr32[2]) ^
+		hash_ip(ip.s6_addr32[3]));
+}
 static int ip_map_match(struct cache_head *corig, struct cache_head *cnew)
 {
 	struct ip_map *orig = container_of(corig, struct ip_map, h);
 	struct ip_map *new = container_of(cnew, struct ip_map, h);
 	return strcmp(orig->m_class, new->m_class) == 0
-		&& orig->m_addr.s_addr == new->m_addr.s_addr;
+		&& ipv6_addr_equal(&orig->m_addr, &new->m_addr);
 }
 static void ip_map_init(struct cache_head *cnew, struct cache_head *citem)
 {
@@ -126,7 +134,7 @@
 	struct ip_map *item = container_of(citem, struct ip_map, h);
 
 	strcpy(new->m_class, item->m_class);
-	new->m_addr.s_addr = item->m_addr.s_addr;
+	ipv6_addr_copy(&new->m_addr, &item->m_addr);
 }
 static void update(struct cache_head *cnew, struct cache_head *citem)
 {
@@ -150,22 +158,24 @@
 				  struct cache_head *h,
 				  char **bpp, int *blen)
 {
-	char text_addr[20];
+	char text_addr[40];
 	struct ip_map *im = container_of(h, struct ip_map, h);
-	__be32 addr = im->m_addr.s_addr;
 
-	snprintf(text_addr, 20, "%u.%u.%u.%u",
-		 ntohl(addr) >> 24 & 0xff,
-		 ntohl(addr) >> 16 & 0xff,
-		 ntohl(addr) >>  8 & 0xff,
-		 ntohl(addr) >>  0 & 0xff);
-
+	if (ipv6_addr_v4mapped(&(im->m_addr))) {
+		snprintf(text_addr, 20, NIPQUAD_FMT,
+				ntohl(im->m_addr.s6_addr32[3]) >> 24 & 0xff,
+				ntohl(im->m_addr.s6_addr32[3]) >> 16 & 0xff,
+				ntohl(im->m_addr.s6_addr32[3]) >>  8 & 0xff,
+				ntohl(im->m_addr.s6_addr32[3]) >>  0 & 0xff);
+	} else {
+		snprintf(text_addr, 40, NIP6_FMT, NIP6(im->m_addr));
+	}
 	qword_add(bpp, blen, im->m_class);
 	qword_add(bpp, blen, text_addr);
 	(*bpp)[-1] = '\n';
 }
 
-static struct ip_map *ip_map_lookup(char *class, struct in_addr addr);
+static struct ip_map *ip_map_lookup(char *class, struct in6_addr *addr);
 static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t expiry);
 
 static int ip_map_parse(struct cache_detail *cd,
@@ -176,10 +186,10 @@
 	 * for scratch: */
 	char *buf = mesg;
 	int len;
-	int b1,b2,b3,b4;
+	int b1, b2, b3, b4, b5, b6, b7, b8;
 	char c;
 	char class[8];
-	struct in_addr addr;
+	struct in6_addr addr;
 	int err;
 
 	struct ip_map *ipmp;
@@ -198,7 +208,23 @@
 	len = qword_get(&mesg, buf, mlen);
 	if (len <= 0) return -EINVAL;
 
-	if (sscanf(buf, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4)
+	if (sscanf(buf, NIPQUAD_FMT "%c", &b1, &b2, &b3, &b4, &c) == 4) {
+		addr.s6_addr32[0] = 0;
+		addr.s6_addr32[1] = 0;
+		addr.s6_addr32[2] = htonl(0xffff);
+		addr.s6_addr32[3] =
+			htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
+       } else if (sscanf(buf, NIP6_FMT "%c",
+			&b1, &b2, &b3, &b4, &b5, &b6, &b7, &b8, &c) == 8) {
+		addr.s6_addr16[0] = htons(b1);
+		addr.s6_addr16[1] = htons(b2);
+		addr.s6_addr16[2] = htons(b3);
+		addr.s6_addr16[3] = htons(b4);
+		addr.s6_addr16[4] = htons(b5);
+		addr.s6_addr16[5] = htons(b6);
+		addr.s6_addr16[6] = htons(b7);
+		addr.s6_addr16[7] = htons(b8);
+       } else
 		return -EINVAL;
 
 	expiry = get_expiry(&mesg);
@@ -216,10 +242,7 @@
 	} else
 		dom = NULL;
 
-	addr.s_addr =
-		htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
-
-	ipmp = ip_map_lookup(class,addr);
+	ipmp = ip_map_lookup(class, &addr);
 	if (ipmp) {
 		err = ip_map_update(ipmp,
 			     container_of(dom, struct unix_domain, h),
@@ -239,7 +262,7 @@
 		       struct cache_head *h)
 {
 	struct ip_map *im;
-	struct in_addr addr;
+	struct in6_addr addr;
 	char *dom = "-no-domain-";
 
 	if (h == NULL) {
@@ -248,20 +271,24 @@
 	}
 	im = container_of(h, struct ip_map, h);
 	/* class addr domain */
-	addr = im->m_addr;
+	ipv6_addr_copy(&addr, &im->m_addr);
 
 	if (test_bit(CACHE_VALID, &h->flags) &&
 	    !test_bit(CACHE_NEGATIVE, &h->flags))
 		dom = im->m_client->h.name;
 
-	seq_printf(m, "%s %d.%d.%d.%d %s\n",
-		   im->m_class,
-		   ntohl(addr.s_addr) >> 24 & 0xff,
-		   ntohl(addr.s_addr) >> 16 & 0xff,
-		   ntohl(addr.s_addr) >>  8 & 0xff,
-		   ntohl(addr.s_addr) >>  0 & 0xff,
-		   dom
-		   );
+	if (ipv6_addr_v4mapped(&addr)) {
+		seq_printf(m, "%s" NIPQUAD_FMT "%s\n",
+			im->m_class,
+			ntohl(addr.s6_addr32[3]) >> 24 & 0xff,
+			ntohl(addr.s6_addr32[3]) >> 16 & 0xff,
+			ntohl(addr.s6_addr32[3]) >>  8 & 0xff,
+			ntohl(addr.s6_addr32[3]) >>  0 & 0xff,
+			dom);
+	} else {
+		seq_printf(m, "%s" NIP6_FMT "%s\n",
+			im->m_class, NIP6(addr), dom);
+	}
 	return 0;
 }
 
@@ -281,16 +308,16 @@
 	.alloc		= ip_map_alloc,
 };
 
-static struct ip_map *ip_map_lookup(char *class, struct in_addr addr)
+static struct ip_map *ip_map_lookup(char *class, struct in6_addr *addr)
 {
 	struct ip_map ip;
 	struct cache_head *ch;
 
 	strcpy(ip.m_class, class);
-	ip.m_addr = addr;
+	ipv6_addr_copy(&ip.m_addr, addr);
 	ch = sunrpc_cache_lookup(&ip_map_cache, &ip.h,
 				 hash_str(class, IP_HASHBITS) ^
-				 hash_ip(addr.s_addr));
+				 hash_ip6(*addr));
 
 	if (ch)
 		return container_of(ch, struct ip_map, h);
@@ -319,14 +346,14 @@
 	ch = sunrpc_cache_update(&ip_map_cache,
 				 &ip.h, &ipm->h,
 				 hash_str(ipm->m_class, IP_HASHBITS) ^
-				 hash_ip(ipm->m_addr.s_addr));
+				 hash_ip6(ipm->m_addr));
 	if (!ch)
 		return -ENOMEM;
 	cache_put(ch, &ip_map_cache);
 	return 0;
 }
 
-int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom)
+int auth_unix_add_addr(struct in6_addr *addr, struct auth_domain *dom)
 {
 	struct unix_domain *udom;
 	struct ip_map *ipmp;
@@ -355,7 +382,7 @@
 }
 EXPORT_SYMBOL(auth_unix_forget_old);
 
-struct auth_domain *auth_unix_lookup(struct in_addr addr)
+struct auth_domain *auth_unix_lookup(struct in6_addr *addr)
 {
 	struct ip_map *ipm;
 	struct auth_domain *rv;
@@ -650,9 +677,24 @@
 int
 svcauth_unix_set_client(struct svc_rqst *rqstp)
 {
-	struct sockaddr_in *sin = svc_addr_in(rqstp);
+	struct sockaddr_in *sin;
+	struct sockaddr_in6 *sin6, sin6_storage;
 	struct ip_map *ipm;
 
+	switch (rqstp->rq_addr.ss_family) {
+	case AF_INET:
+		sin = svc_addr_in(rqstp);
+		sin6 = &sin6_storage;
+		ipv6_addr_set(&sin6->sin6_addr, 0, 0,
+				htonl(0x0000FFFF), sin->sin_addr.s_addr);
+		break;
+	case AF_INET6:
+		sin6 = svc_addr_in6(rqstp);
+		break;
+	default:
+		BUG();
+	}
+
 	rqstp->rq_client = NULL;
 	if (rqstp->rq_proc == 0)
 		return SVC_OK;
@@ -660,7 +702,7 @@
 	ipm = ip_map_cached_get(rqstp);
 	if (ipm == NULL)
 		ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class,
-				    sin->sin_addr);
+				    &sin6->sin6_addr);
 
 	if (ipm == NULL)
 		return SVC_DENIED;
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index c475977..3e65719 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -38,6 +38,7 @@
 #include <net/checksum.h>
 #include <net/ip.h>
 #include <net/ipv6.h>
+#include <net/tcp.h>
 #include <net/tcp_states.h>
 #include <asm/uaccess.h>
 #include <asm/ioctls.h>
@@ -45,6 +46,7 @@
 #include <linux/sunrpc/types.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/xdr.h>
+#include <linux/sunrpc/msg_prot.h>
 #include <linux/sunrpc/svcsock.h>
 #include <linux/sunrpc/stats.h>
 
@@ -822,8 +824,8 @@
 	 * the next four bytes. Otherwise try to gobble up as much as
 	 * possible up to the complete record length.
 	 */
-	if (svsk->sk_tcplen < 4) {
-		unsigned long	want = 4 - svsk->sk_tcplen;
+	if (svsk->sk_tcplen < sizeof(rpc_fraghdr)) {
+		int		want = sizeof(rpc_fraghdr) - svsk->sk_tcplen;
 		struct kvec	iov;
 
 		iov.iov_base = ((char *) &svsk->sk_reclen) + svsk->sk_tcplen;
@@ -833,32 +835,31 @@
 		svsk->sk_tcplen += len;
 
 		if (len < want) {
-			dprintk("svc: short recvfrom while reading record length (%d of %lu)\n",
-				len, want);
+			dprintk("svc: short recvfrom while reading record "
+				"length (%d of %d)\n", len, want);
 			svc_xprt_received(&svsk->sk_xprt);
 			return -EAGAIN; /* record header not complete */
 		}
 
 		svsk->sk_reclen = ntohl(svsk->sk_reclen);
-		if (!(svsk->sk_reclen & 0x80000000)) {
+		if (!(svsk->sk_reclen & RPC_LAST_STREAM_FRAGMENT)) {
 			/* FIXME: technically, a record can be fragmented,
 			 *  and non-terminal fragments will not have the top
 			 *  bit set in the fragment length header.
 			 *  But apparently no known nfs clients send fragmented
 			 *  records. */
 			if (net_ratelimit())
-				printk(KERN_NOTICE "RPC: bad TCP reclen 0x%08lx"
-				       " (non-terminal)\n",
-				       (unsigned long) svsk->sk_reclen);
+				printk(KERN_NOTICE "RPC: multiple fragments "
+					"per record not supported\n");
 			goto err_delete;
 		}
-		svsk->sk_reclen &= 0x7fffffff;
+		svsk->sk_reclen &= RPC_FRAGMENT_SIZE_MASK;
 		dprintk("svc: TCP record, %d bytes\n", svsk->sk_reclen);
 		if (svsk->sk_reclen > serv->sv_max_mesg) {
 			if (net_ratelimit())
-				printk(KERN_NOTICE "RPC: bad TCP reclen 0x%08lx"
-				       " (large)\n",
-				       (unsigned long) svsk->sk_reclen);
+				printk(KERN_NOTICE "RPC: "
+					"fragment too large: 0x%08lx\n",
+					(unsigned long)svsk->sk_reclen);
 			goto err_delete;
 		}
 	}
@@ -1045,7 +1046,6 @@
 static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv)
 {
 	struct sock	*sk = svsk->sk_sk;
-	struct tcp_sock *tp = tcp_sk(sk);
 
 	svc_xprt_init(&svc_tcp_class, &svsk->sk_xprt, serv);
 	set_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags);
@@ -1063,7 +1063,7 @@
 		svsk->sk_reclen = 0;
 		svsk->sk_tcplen = 0;
 
-		tp->nonagle = 1;        /* disable Nagle's algorithm */
+		tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF;
 
 		/* initialise setting must have enough space to
 		 * receive and respond to one request.
@@ -1101,6 +1101,7 @@
 	}
 	spin_unlock_bh(&serv->sv_lock);
 }
+EXPORT_SYMBOL(svc_sock_update_bufs);
 
 /*
  * Initialize socket for RPC use and create svc_sock struct
diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
index 16fd3f6..af408fc 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
@@ -1036,6 +1036,8 @@
 			wait_event(xprt->sc_send_wait,
 				   atomic_read(&xprt->sc_sq_count) <
 				   xprt->sc_sq_depth);
+			if (test_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags))
+				return 0;
 			continue;
 		}
 		/* Bumped used SQ WR count and post */
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 1454afc..e18cd36 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -2197,7 +2197,11 @@
 	unregister_pernet_subsys(&unix_net_ops);
 }
 
-module_init(af_unix_init);
+/* Earlier than device_initcall() so that other drivers invoking
+   request_module() don't end up in a loop when modprobe tries
+   to use a UNIX socket. But later than subsys_initcall() because
+   we depend on stuff initialised there */
+fs_initcall(af_unix_init);
 module_exit(af_unix_exit);
 
 MODULE_LICENSE("GPL");
diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c
index 8704e28..5b3274b 100644
--- a/sound/arm/pxa2xx-ac97.c
+++ b/sound/arm/pxa2xx-ac97.c
@@ -72,7 +72,7 @@
 	if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1) <= 0 &&
 	    !((GSR | gsr_bits) & GSR_SDONE)) {
 		printk(KERN_ERR "%s: read error (ac97_reg=%d GSR=%#lx)\n",
-				__FUNCTION__, reg, GSR | gsr_bits);
+				__func__, reg, GSR | gsr_bits);
 		val = -1;
 		goto out;
 	}
@@ -104,7 +104,7 @@
 	if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_CDONE, 1) <= 0 &&
 	    !((GSR | gsr_bits) & GSR_CDONE))
 		printk(KERN_ERR "%s: write error (ac97_reg=%d GSR=%#lx)\n",
-				__FUNCTION__, reg, GSR | gsr_bits);
+				__func__, reg, GSR | gsr_bits);
 
 	mutex_unlock(&car_mutex);
 }
@@ -112,6 +112,16 @@
 static void pxa2xx_ac97_reset(struct snd_ac97 *ac97)
 {
 	/* First, try cold reset */
+#ifdef CONFIG_PXA3xx
+	int timeout;
+
+	/* Hold CLKBPB for 100us */
+	GCR = 0;
+	GCR = GCR_CLKBPB;
+	udelay(100);
+	GCR = 0;
+#endif
+
 	GCR &=  GCR_COLD_RST;  /* clear everything but nCRST */
 	GCR &= ~GCR_COLD_RST;  /* then assert nCRST */
 
@@ -123,6 +133,14 @@
 	clk_disable(ac97conf_clk);
 	GCR = GCR_COLD_RST;
 	udelay(50);
+#elif defined(CONFIG_PXA3xx)
+	timeout = 1000;
+	/* Can't use interrupts on PXA3xx */
+	GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
+
+	GCR = GCR_WARM_RST | GCR_COLD_RST;
+	while (!(GSR & (GSR_PCR | GSR_SCR)) && timeout--)
+		mdelay(10);
 #else
 	GCR = GCR_COLD_RST;
 	GCR |= GCR_CDONE_IE|GCR_SDONE_IE;
@@ -131,7 +149,7 @@
 
 	if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR))) {
 		printk(KERN_INFO "%s: cold reset timeout (GSR=%#lx)\n",
-				 __FUNCTION__, gsr_bits);
+				 __func__, gsr_bits);
 
 		/* let's try warm reset */
 		gsr_bits = 0;
@@ -143,6 +161,12 @@
 		GCR |= GCR_WARM_RST;
 		pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
 		udelay(500);
+#elif defined(CONFIG_PXA3xx)
+		timeout = 100;
+		/* Can't use interrupts */
+		GCR |= GCR_WARM_RST;
+		while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--)
+			mdelay(1);
 #else
 		GCR |= GCR_WARM_RST|GCR_PRIRDY_IEN|GCR_SECRDY_IEN;
 		wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
@@ -150,7 +174,7 @@
 
 		if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)))
 			printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n",
-					 __FUNCTION__, gsr_bits);
+					 __func__, gsr_bits);
 	}
 
 	GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
@@ -424,6 +448,7 @@
 	.resume		= pxa2xx_ac97_resume,
 	.driver		= {
 		.name	= "pxa2xx-ac97",
+		.owner	= THIS_MODULE,
 	},
 };
 
@@ -443,3 +468,4 @@
 MODULE_AUTHOR("Nicolas Pitre");
 MODULE_DESCRIPTION("AC97 driver for the Intel PXA2xx chip");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-ac97");
diff --git a/sound/core/Kconfig b/sound/core/Kconfig
index 829ca38..a8d71c6 100644
--- a/sound/core/Kconfig
+++ b/sound/core/Kconfig
@@ -181,3 +181,7 @@
 	  It is usually not required, but if you have trouble with
 	  sound clicking when system is loaded, it may help to determine
 	  the process or driver which causes the scheduling gaps.
+
+config SND_VMASTER
+	bool
+	depends on SND
diff --git a/sound/core/Makefile b/sound/core/Makefile
index 267039a9..da8e685 100644
--- a/sound/core/Makefile
+++ b/sound/core/Makefile
@@ -6,6 +6,7 @@
 snd-y     := sound.o init.o memory.o info.o control.o misc.o device.o
 snd-$(CONFIG_ISA_DMA_API) += isadma.o
 snd-$(CONFIG_SND_OSSEMUL) += sound_oss.o info_oss.o
+snd-$(CONFIG_SND_VMASTER) += vmaster.o
 
 snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \
 		pcm_memory.o
diff --git a/sound/core/init.c b/sound/core/init.c
index e3338d6..ac05734 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -254,7 +254,7 @@
 	if (likely(df))
 		return df->disconnected_f_op->release(inode, file);
 
-	panic("%s(%p, %p) failed!", __FUNCTION__, inode, file);
+	panic("%s(%p, %p) failed!", __func__, inode, file);
 }
 
 static unsigned int snd_disconnect_poll(struct file * file, poll_table * wait)
@@ -311,6 +311,9 @@
 	struct file *file;
 	int err;
 
+	if (!card)
+		return -EINVAL;
+
 	spin_lock(&card->files_lock);
 	if (card->shutdown) {
 		spin_unlock(&card->files_lock);
@@ -322,6 +325,7 @@
 	/* phase 1: disable fops (user space) operations for ALSA API */
 	mutex_lock(&snd_card_mutex);
 	snd_cards[card->number] = NULL;
+	snd_cards_lock &= ~(1 << card->number);
 	mutex_unlock(&snd_card_mutex);
 	
 	/* phase 2: replace file->f_op with special dummy operations */
@@ -360,6 +364,15 @@
 		snd_printk(KERN_ERR "not all devices for card %i can be disconnected\n", card->number);
 
 	snd_info_card_disconnect(card);
+#ifndef CONFIG_SYSFS_DEPRECATED
+	if (card->card_dev) {
+		device_unregister(card->card_dev);
+		card->card_dev = NULL;
+	}
+#endif
+#ifdef CONFIG_PM
+	wake_up(&card->power_sleep);
+#endif
 	return 0;	
 }
 
@@ -401,33 +414,14 @@
 		snd_printk(KERN_WARNING "unable to free card info\n");
 		/* Not fatal error */
 	}
-#ifndef CONFIG_SYSFS_DEPRECATED
-	if (card->card_dev)
-		device_unregister(card->card_dev);
-#endif
 	kfree(card);
 	return 0;
 }
 
-static int snd_card_free_prepare(struct snd_card *card)
-{
-	if (card == NULL)
-		return -EINVAL;
-	(void) snd_card_disconnect(card);
-	mutex_lock(&snd_card_mutex);
-	snd_cards[card->number] = NULL;
-	snd_cards_lock &= ~(1 << card->number);
-	mutex_unlock(&snd_card_mutex);
-#ifdef CONFIG_PM
-	wake_up(&card->power_sleep);
-#endif
-	return 0;
-}
-
 int snd_card_free_when_closed(struct snd_card *card)
 {
 	int free_now = 0;
-	int ret = snd_card_free_prepare(card);
+	int ret = snd_card_disconnect(card);
 	if (ret)
 		return ret;
 
@@ -447,7 +441,7 @@
 
 int snd_card_free(struct snd_card *card)
 {
-	int ret = snd_card_free_prepare(card);
+	int ret = snd_card_disconnect(card);
 	if (ret)
 		return ret;
 
diff --git a/sound/core/misc.c b/sound/core/misc.c
index 102d1c3..38524f6 100644
--- a/sound/core/misc.c
+++ b/sound/core/misc.c
@@ -39,7 +39,7 @@
 {
 	va_list args;
 	
-	if (format[0] == '<' && format[1] >= '0' && format[1] <= '9' && format[2] == '>') {
+	if (format[0] == '<' && format[1] >= '0' && format[1] <= '7' && format[2] == '>') {
 		char tmp[] = "<0>";
 		tmp[1] = format[1];
 		printk("%sALSA %s:%d: ", tmp, file, line);
@@ -60,7 +60,7 @@
 {
 	va_list args;
 	
-	if (format[0] == '<' && format[1] >= '0' && format[1] <= '9' && format[2] == '>') {
+	if (format[0] == '<' && format[1] >= '0' && format[1] <= '7' && format[2] == '>') {
 		char tmp[] = "<0>";
 		tmp[1] = format[1];
 		printk("%sALSA %s:%d: ", tmp, file, line);
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index 75daed2..581aa2c 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -1257,6 +1257,8 @@
 		{ SOUND_MIXER_DIGITAL3,	"Digital",		2 },
 		{ SOUND_MIXER_PHONEIN,	"Phone",		0 },
 		{ SOUND_MIXER_PHONEOUT,	"Master Mono",		0 },
+		{ SOUND_MIXER_PHONEOUT,	"Speaker",		0 }, /*fallback*/
+		{ SOUND_MIXER_PHONEOUT,	"Mono",			0 }, /*fallback*/
 		{ SOUND_MIXER_PHONEOUT,	"Phone",		0 }, /* fallback */
 		{ SOUND_MIXER_VIDEO,	"Video",		0 },
 		{ SOUND_MIXER_RADIO,	"Radio",		0 },
diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c
index ab570a0..558dadb 100644
--- a/sound/core/seq/oss/seq_oss_synth.c
+++ b/sound/core/seq/oss/seq_oss_synth.c
@@ -245,8 +245,13 @@
 		info->nr_voices = rec->nr_voices;
 		if (info->nr_voices > 0) {
 			info->ch = kcalloc(info->nr_voices, sizeof(struct seq_oss_chinfo), GFP_KERNEL);
-			if (!info->ch)
-				BUG();
+			if (!info->ch) {
+				snd_printk(KERN_ERR "Cannot malloc\n");
+				rec->oper.close(&info->arg);
+				module_put(rec->oper.owner);
+				snd_use_lock_free(&rec->use_lock);
+				continue;
+			}
 			reset_channels(info);
 		}
 		debug_printk(("synth %d assigned\n", i));
diff --git a/sound/pci/hda/vmaster.c b/sound/core/vmaster.c
similarity index 96%
rename from sound/pci/hda/vmaster.c
rename to sound/core/vmaster.c
index 2da49d2..4cc57f9 100644
--- a/sound/pci/hda/vmaster.c
+++ b/sound/core/vmaster.c
@@ -12,6 +12,7 @@
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/control.h>
+#include <sound/tlv.h>
 
 /*
  * a subset of information returned via ctl info callback
@@ -34,6 +35,7 @@
 	struct list_head slaves;
 	struct link_ctl_info info;
 	int val;		/* the master value */
+	unsigned int tlv[4];
 };
 
 /*
@@ -253,6 +255,8 @@
 	return 0;
 }
 
+EXPORT_SYMBOL(snd_ctl_add_slave);
+
 /*
  * ctl callbacks for master controls
  */
@@ -355,10 +359,13 @@
 	kctl->private_free = master_free;
 
 	/* additional (constant) TLV read */
-	if (tlv) {
-		/* FIXME: this assumes that the max volume is 0 dB */
+	if (tlv && tlv[0] == SNDRV_CTL_TLVT_DB_SCALE) {
 		kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
-		kctl->tlv.p = tlv;
+		memcpy(master->tlv, tlv, sizeof(master->tlv));
+		kctl->tlv.p = master->tlv;
 	}
+
 	return kctl;
 }
+
+EXPORT_SYMBOL(snd_ctl_make_virtual_master);
diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig
index 75d4fe0..fe85af1 100644
--- a/sound/drivers/Kconfig
+++ b/sound/drivers/Kconfig
@@ -4,6 +4,24 @@
 	depends on SND!=n
 
 
+config SND_PCSP
+	tristate "Internal PC speaker support"
+	depends on X86_PC && HIGH_RES_TIMERS
+	depends on INPUT
+	help
+	  If you don't have a sound card in your computer, you can include a
+	  driver for the PC speaker which allows it to act like a primitive
+	  sound card.
+	  This driver also replaces the pcspkr driver for beeps.
+
+	  You can compile this as a module which will be called snd-pcsp.
+
+	  You don't need this driver if you only want your pc-speaker to beep.
+	  You don't need this driver if you have a tablet piezo beeper
+	  in your PC instead of the real speaker.
+
+	  It should not hurt to say Y or M here in all other cases.
+
 config SND_MPU401_UART
         tristate
         select SND_RAWMIDI
diff --git a/sound/drivers/Makefile b/sound/drivers/Makefile
index 8e55300..d4a07f9 100644
--- a/sound/drivers/Makefile
+++ b/sound/drivers/Makefile
@@ -20,4 +20,4 @@
 obj-$(CONFIG_SND_PORTMAN2X4) += snd-portman2x4.o
 obj-$(CONFIG_SND_ML403_AC97CR) += snd-ml403-ac97cr.o
 
-obj-$(CONFIG_SND) += opl3/ opl4/ mpu401/ vx/
+obj-$(CONFIG_SND) += opl3/ opl4/ mpu401/ vx/ pcsp/
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c
index a240eae..4e4c69e 100644
--- a/sound/drivers/dummy.c
+++ b/sound/drivers/dummy.c
@@ -181,10 +181,10 @@
 	struct snd_dummy *dummy;
 	spinlock_t lock;
 	struct timer_list timer;
-	unsigned int pcm_size;
-	unsigned int pcm_count;
+	unsigned int pcm_buffer_size;
+	unsigned int pcm_period_size;
 	unsigned int pcm_bps;		/* bytes per second */
-	unsigned int pcm_jiffie;	/* bytes per one jiffie */
+	unsigned int pcm_hz;		/* HZ */
 	unsigned int pcm_irq_pos;	/* IRQ position */
 	unsigned int pcm_buf_pos;	/* position in buffer */
 	struct snd_pcm_substream *substream;
@@ -230,19 +230,24 @@
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_dummy_pcm *dpcm = runtime->private_data;
-	unsigned int bps;
+	int bps;
 
-	bps = runtime->rate * runtime->channels;
-	bps *= snd_pcm_format_width(runtime->format);
-	bps /= 8;
+	bps = snd_pcm_format_width(runtime->format) * runtime->rate *
+		runtime->channels / 8;
+
 	if (bps <= 0)
 		return -EINVAL;
+
 	dpcm->pcm_bps = bps;
-	dpcm->pcm_jiffie = bps / HZ;
-	dpcm->pcm_size = snd_pcm_lib_buffer_bytes(substream);
-	dpcm->pcm_count = snd_pcm_lib_period_bytes(substream);
+	dpcm->pcm_hz = HZ;
+	dpcm->pcm_buffer_size = snd_pcm_lib_buffer_bytes(substream);
+	dpcm->pcm_period_size = snd_pcm_lib_period_bytes(substream);
 	dpcm->pcm_irq_pos = 0;
 	dpcm->pcm_buf_pos = 0;
+
+	snd_pcm_format_set_silence(runtime->format, runtime->dma_area,
+			bytes_to_samples(runtime, runtime->dma_bytes));
+
 	return 0;
 }
 
@@ -254,11 +259,11 @@
 	spin_lock_irqsave(&dpcm->lock, flags);
 	dpcm->timer.expires = 1 + jiffies;
 	add_timer(&dpcm->timer);
-	dpcm->pcm_irq_pos += dpcm->pcm_jiffie;
-	dpcm->pcm_buf_pos += dpcm->pcm_jiffie;
-	dpcm->pcm_buf_pos %= dpcm->pcm_size;
-	if (dpcm->pcm_irq_pos >= dpcm->pcm_count) {
-		dpcm->pcm_irq_pos %= dpcm->pcm_count;
+	dpcm->pcm_irq_pos += dpcm->pcm_bps;
+	dpcm->pcm_buf_pos += dpcm->pcm_bps;
+	dpcm->pcm_buf_pos %= dpcm->pcm_buffer_size * dpcm->pcm_hz;
+	if (dpcm->pcm_irq_pos >= dpcm->pcm_period_size * dpcm->pcm_hz) {
+		dpcm->pcm_irq_pos %= dpcm->pcm_period_size * dpcm->pcm_hz;
 		spin_unlock_irqrestore(&dpcm->lock, flags);
 		snd_pcm_period_elapsed(dpcm->substream);
 	} else
@@ -270,7 +275,7 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_dummy_pcm *dpcm = runtime->private_data;
 
-	return bytes_to_frames(runtime, dpcm->pcm_buf_pos);
+	return bytes_to_frames(runtime, dpcm->pcm_buf_pos / dpcm->pcm_hz);
 }
 
 static struct snd_pcm_hardware snd_card_dummy_playback =
diff --git a/sound/drivers/ml403-ac97cr.c b/sound/drivers/ml403-ac97cr.c
index 05a871a..ecdbeb6 100644
--- a/sound/drivers/ml403-ac97cr.c
+++ b/sound/drivers/ml403-ac97cr.c
@@ -1191,8 +1191,6 @@
 		return err;
 	}
 
-	snd_card_set_dev(card, &pfdev->dev);
-
 	*rml403_ac97cr = ml403_ac97cr;
 	return 0;
 }
@@ -1330,11 +1328,15 @@
 	return 0;
 }
 
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:" SND_ML403_AC97CR_DRIVER);
+
 static struct platform_driver snd_ml403_ac97cr_driver = {
 	.probe = snd_ml403_ac97cr_probe,
 	.remove = snd_ml403_ac97cr_remove,
 	.driver = {
 		.name = SND_ML403_AC97CR_DRIVER,
+		.owner = THIS_MODULE,
 	},
 };
 
diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c
index 5993864a..18cca24 100644
--- a/sound/drivers/mpu401/mpu401_uart.c
+++ b/sound/drivers/mpu401/mpu401_uart.c
@@ -49,12 +49,10 @@
 
  */
 
-#define snd_mpu401_input_avail(mpu)	(!(mpu->read(mpu, MPU401C(mpu)) & 0x80))
-#define snd_mpu401_output_ready(mpu)	(!(mpu->read(mpu, MPU401C(mpu)) & 0x40))
-
-#define MPU401_RESET		0xff
-#define MPU401_ENTER_UART	0x3f
-#define MPU401_ACK		0xfe
+#define snd_mpu401_input_avail(mpu) \
+	(!(mpu->read(mpu, MPU401C(mpu)) & MPU401_RX_EMPTY))
+#define snd_mpu401_output_ready(mpu) \
+	(!(mpu->read(mpu, MPU401C(mpu)) & MPU401_TX_FULL))
 
 /* Build in lowlevel io */
 static void mpu401_write_port(struct snd_mpu401 *mpu, unsigned char data,
@@ -425,16 +423,17 @@
 static void snd_mpu401_uart_output_write(struct snd_mpu401 * mpu)
 {
 	unsigned char byte;
-	int max = 256, timeout;
+	int max = 256;
 
 	do {
 		if (snd_rawmidi_transmit_peek(mpu->substream_output,
 					      &byte, 1) == 1) {
-			for (timeout = 100; timeout > 0; timeout--) {
-				if (snd_mpu401_output_ready(mpu))
-					break;
-			}
-			if (timeout == 0)
+			/*
+			 * Try twice because there is hardware that insists on
+			 * setting the output busy bit after each write.
+			 */
+			if (!snd_mpu401_output_ready(mpu) &&
+			    !snd_mpu401_output_ready(mpu))
 				break;	/* Tx FIFO full - try again later */
 			mpu->write(mpu, byte, MPU401D(mpu));
 			snd_rawmidi_transmit_ack(mpu->substream_output, 1);
diff --git a/sound/drivers/pcsp/Makefile b/sound/drivers/pcsp/Makefile
new file mode 100644
index 0000000..b19555b
--- /dev/null
+++ b/sound/drivers/pcsp/Makefile
@@ -0,0 +1,2 @@
+snd-pcsp-objs := pcsp.o pcsp_lib.o pcsp_mixer.o pcsp_input.o
+obj-$(CONFIG_SND_PCSP) += snd-pcsp.o
diff --git a/sound/drivers/pcsp/pcsp.c b/sound/drivers/pcsp/pcsp.c
new file mode 100644
index 0000000..5920351
--- /dev/null
+++ b/sound/drivers/pcsp/pcsp.c
@@ -0,0 +1,235 @@
+/*
+ * PC-Speaker driver for Linux
+ *
+ * Copyright (C) 1997-2001  David Woodhouse
+ * Copyright (C) 2001-2008  Stas Sergeev
+ */
+
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <asm/bitops.h>
+#include "pcsp_input.h"
+#include "pcsp.h"
+
+MODULE_AUTHOR("Stas Sergeev <stsp@users.sourceforge.net>");
+MODULE_DESCRIPTION("PC-Speaker driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{PC-Speaker, pcsp}}");
+MODULE_ALIAS("platform:pcspkr");
+
+static int index = SNDRV_DEFAULT_IDX1;	/* Index 0-MAX */
+static char *id = SNDRV_DEFAULT_STR1;	/* ID for this card */
+static int enable = SNDRV_DEFAULT_ENABLE1;	/* Enable this card */
+
+module_param(index, int, 0444);
+MODULE_PARM_DESC(index, "Index value for pcsp soundcard.");
+module_param(id, charp, 0444);
+MODULE_PARM_DESC(id, "ID string for pcsp soundcard.");
+module_param(enable, bool, 0444);
+MODULE_PARM_DESC(enable, "Enable PC-Speaker sound.");
+
+struct snd_pcsp pcsp_chip;
+
+static int __devinit snd_pcsp_create(struct snd_card *card)
+{
+	static struct snd_device_ops ops = { };
+	struct timespec tp;
+	int err;
+	int div, min_div, order;
+
+	hrtimer_get_res(CLOCK_MONOTONIC, &tp);
+	if (tp.tv_sec || tp.tv_nsec > PCSP_MAX_PERIOD_NS) {
+		printk(KERN_ERR "PCSP: Timer resolution is not sufficient "
+		       "(%linS)\n", tp.tv_nsec);
+		printk(KERN_ERR "PCSP: Make sure you have HPET and ACPI "
+		       "enabled.\n");
+		return -EIO;
+	}
+
+	if (loops_per_jiffy >= PCSP_MIN_LPJ && tp.tv_nsec <= PCSP_MIN_PERIOD_NS)
+		min_div = MIN_DIV;
+	else
+		min_div = MAX_DIV;
+#if PCSP_DEBUG
+	printk("PCSP: lpj=%li, min_div=%i, res=%li\n",
+	       loops_per_jiffy, min_div, tp.tv_nsec);
+#endif
+
+	div = MAX_DIV / min_div;
+	order = fls(div) - 1;
+
+	pcsp_chip.max_treble = min(order, PCSP_MAX_TREBLE);
+	pcsp_chip.treble = min(pcsp_chip.max_treble, PCSP_DEFAULT_TREBLE);
+	pcsp_chip.playback_ptr = 0;
+	pcsp_chip.period_ptr = 0;
+	atomic_set(&pcsp_chip.timer_active, 0);
+	pcsp_chip.enable = 1;
+	pcsp_chip.pcspkr = 1;
+
+	spin_lock_init(&pcsp_chip.substream_lock);
+
+	pcsp_chip.card = card;
+	pcsp_chip.port = 0x61;
+	pcsp_chip.irq = -1;
+	pcsp_chip.dma = -1;
+
+	/* Register device */
+	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, &pcsp_chip, &ops);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int __devinit snd_card_pcsp_probe(int devnum, struct device *dev)
+{
+	struct snd_card *card;
+	int err;
+
+	if (devnum != 0)
+		return -EINVAL;
+
+	hrtimer_init(&pcsp_chip.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	pcsp_chip.timer.cb_mode = HRTIMER_CB_IRQSAFE;
+	pcsp_chip.timer.function = pcsp_do_timer;
+
+	card = snd_card_new(index, id, THIS_MODULE, 0);
+	if (!card)
+		return -ENOMEM;
+
+	err = snd_pcsp_create(card);
+	if (err < 0) {
+		snd_card_free(card);
+		return err;
+	}
+	err = snd_pcsp_new_pcm(&pcsp_chip);
+	if (err < 0) {
+		snd_card_free(card);
+		return err;
+	}
+	err = snd_pcsp_new_mixer(&pcsp_chip);
+	if (err < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+	snd_card_set_dev(pcsp_chip.card, dev);
+
+	strcpy(card->driver, "PC-Speaker");
+	strcpy(card->shortname, "pcsp");
+	sprintf(card->longname, "Internal PC-Speaker at port 0x%x",
+		pcsp_chip.port);
+
+	err = snd_card_register(card);
+	if (err < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+	return 0;
+}
+
+static int __devinit alsa_card_pcsp_init(struct device *dev)
+{
+	int err;
+
+	err = snd_card_pcsp_probe(0, dev);
+	if (err) {
+		printk(KERN_ERR "PC-Speaker initialization failed.\n");
+		return err;
+	}
+
+#ifdef CONFIG_DEBUG_PAGEALLOC
+	/* Well, CONFIG_DEBUG_PAGEALLOC makes the sound horrible. Lets alert */
+	printk(KERN_WARNING "PCSP: CONFIG_DEBUG_PAGEALLOC is enabled, "
+	       "which may make the sound noisy.\n");
+#endif
+
+	return 0;
+}
+
+static void __devexit alsa_card_pcsp_exit(struct snd_pcsp *chip)
+{
+	snd_card_free(chip->card);
+}
+
+static int __devinit pcsp_probe(struct platform_device *dev)
+{
+	int err;
+
+	err = pcspkr_input_init(&pcsp_chip.input_dev, &dev->dev);
+	if (err < 0)
+		return err;
+
+	err = alsa_card_pcsp_init(&dev->dev);
+	if (err < 0) {
+		pcspkr_input_remove(pcsp_chip.input_dev);
+		return err;
+	}
+
+	platform_set_drvdata(dev, &pcsp_chip);
+	return 0;
+}
+
+static int __devexit pcsp_remove(struct platform_device *dev)
+{
+	struct snd_pcsp *chip = platform_get_drvdata(dev);
+	alsa_card_pcsp_exit(chip);
+	pcspkr_input_remove(chip->input_dev);
+	platform_set_drvdata(dev, NULL);
+	return 0;
+}
+
+static void pcsp_stop_beep(struct snd_pcsp *chip)
+{
+	spin_lock_irq(&chip->substream_lock);
+	if (!chip->playback_substream)
+		pcspkr_stop_sound();
+	spin_unlock_irq(&chip->substream_lock);
+}
+
+static int pcsp_suspend(struct platform_device *dev, pm_message_t state)
+{
+	struct snd_pcsp *chip = platform_get_drvdata(dev);
+	pcsp_stop_beep(chip);
+	snd_pcm_suspend_all(chip->pcm);
+	return 0;
+}
+
+static void pcsp_shutdown(struct platform_device *dev)
+{
+	struct snd_pcsp *chip = platform_get_drvdata(dev);
+	pcsp_stop_beep(chip);
+}
+
+static struct platform_driver pcsp_platform_driver = {
+	.driver		= {
+		.name	= "pcspkr",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= pcsp_probe,
+	.remove		= __devexit_p(pcsp_remove),
+	.suspend	= pcsp_suspend,
+	.shutdown	= pcsp_shutdown,
+};
+
+static int __init pcsp_init(void)
+{
+	if (!enable)
+		return -ENODEV;
+	return platform_driver_register(&pcsp_platform_driver);
+}
+
+static void __exit pcsp_exit(void)
+{
+	platform_driver_unregister(&pcsp_platform_driver);
+}
+
+module_init(pcsp_init);
+module_exit(pcsp_exit);
diff --git a/sound/drivers/pcsp/pcsp.h b/sound/drivers/pcsp/pcsp.h
new file mode 100644
index 0000000..f07cc1e
--- /dev/null
+++ b/sound/drivers/pcsp/pcsp.h
@@ -0,0 +1,82 @@
+/*
+ * PC-Speaker driver for Linux
+ *
+ * Copyright (C) 1993-1997  Michael Beck
+ * Copyright (C) 1997-2001  David Woodhouse
+ * Copyright (C) 2001-2008  Stas Sergeev
+ */
+
+#ifndef __PCSP_H__
+#define __PCSP_H__
+
+#include <linux/hrtimer.h>
+#if defined(CONFIG_MIPS) || defined(CONFIG_X86)
+/* Use the global PIT lock ! */
+#include <asm/i8253.h>
+#else
+#include <asm/8253pit.h>
+static DEFINE_SPINLOCK(i8253_lock);
+#endif
+
+#define PCSP_SOUND_VERSION 0x400	/* read 4.00 */
+#define PCSP_DEBUG 0
+
+/* default timer freq for PC-Speaker: 18643 Hz */
+#define DIV_18KHZ 64
+#define MAX_DIV DIV_18KHZ
+#define CUR_DIV() (MAX_DIV >> chip->treble)
+#define PCSP_MAX_TREBLE 1
+
+/* unfortunately, with hrtimers 37KHz does not work very well :( */
+#define PCSP_DEFAULT_TREBLE 0
+#define MIN_DIV (MAX_DIV >> PCSP_MAX_TREBLE)
+
+/* wild guess */
+#define PCSP_MIN_LPJ 1000000
+#define PCSP_DEFAULT_SDIV (DIV_18KHZ >> 1)
+#define PCSP_DEFAULT_SRATE (PIT_TICK_RATE / PCSP_DEFAULT_SDIV)
+#define PCSP_INDEX_INC() (1 << (PCSP_MAX_TREBLE - chip->treble))
+#define PCSP_RATE() (PIT_TICK_RATE / CUR_DIV())
+#define PCSP_MIN_RATE__1 MAX_DIV/PIT_TICK_RATE
+#define PCSP_MAX_RATE__1 MIN_DIV/PIT_TICK_RATE
+#define PCSP_MAX_PERIOD_NS (1000000000ULL * PCSP_MIN_RATE__1)
+#define PCSP_MIN_PERIOD_NS (1000000000ULL * PCSP_MAX_RATE__1)
+#define PCSP_CALC_NS(div) ({ \
+	u64 __val = 1000000000ULL * (div); \
+	do_div(__val, PIT_TICK_RATE); \
+	__val; \
+})
+#define PCSP_PERIOD_NS() PCSP_CALC_NS(CUR_DIV())
+
+#define PCSP_MAX_PERIOD_SIZE	(64*1024)
+#define PCSP_MAX_PERIODS	512
+#define PCSP_BUFFER_SIZE	(128*1024)
+
+struct snd_pcsp {
+	struct snd_card *card;
+	struct snd_pcm *pcm;
+	struct input_dev *input_dev;
+	struct hrtimer timer;
+	unsigned short port, irq, dma;
+	spinlock_t substream_lock;
+	struct snd_pcm_substream *playback_substream;
+	size_t playback_ptr;
+	size_t period_ptr;
+	atomic_t timer_active;
+	int thalf;
+	u64 ns_rem;
+	unsigned char val61;
+	int enable;
+	int max_treble;
+	int treble;
+	int pcspkr;
+};
+
+extern struct snd_pcsp pcsp_chip;
+
+extern enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle);
+
+extern int snd_pcsp_new_pcm(struct snd_pcsp *chip);
+extern int snd_pcsp_new_mixer(struct snd_pcsp *chip);
+
+#endif
diff --git a/sound/drivers/pcsp/pcsp_input.c b/sound/drivers/pcsp/pcsp_input.c
new file mode 100644
index 0000000..cd9b83e
--- /dev/null
+++ b/sound/drivers/pcsp/pcsp_input.c
@@ -0,0 +1,116 @@
+/*
+ *  PC Speaker beeper driver for Linux
+ *
+ *  Copyright (c) 2002 Vojtech Pavlik
+ *  Copyright (c) 1992 Orest Zborowski
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation
+ */
+
+#include <linux/init.h>
+#include <linux/input.h>
+#include <asm/io.h>
+#include "pcsp.h"
+
+static void pcspkr_do_sound(unsigned int count)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&i8253_lock, flags);
+
+	if (count) {
+		/* enable counter 2 */
+		outb_p(inb_p(0x61) | 3, 0x61);
+		/* set command for counter 2, 2 byte write */
+		outb_p(0xB6, 0x43);
+		/* select desired HZ */
+		outb_p(count & 0xff, 0x42);
+		outb((count >> 8) & 0xff, 0x42);
+	} else {
+		/* disable counter 2 */
+		outb(inb_p(0x61) & 0xFC, 0x61);
+	}
+
+	spin_unlock_irqrestore(&i8253_lock, flags);
+}
+
+void pcspkr_stop_sound(void)
+{
+	pcspkr_do_sound(0);
+}
+
+static int pcspkr_input_event(struct input_dev *dev, unsigned int type,
+			      unsigned int code, int value)
+{
+	unsigned int count = 0;
+
+	if (atomic_read(&pcsp_chip.timer_active) || !pcsp_chip.pcspkr)
+		return 0;
+
+	switch (type) {
+	case EV_SND:
+		switch (code) {
+		case SND_BELL:
+			if (value)
+				value = 1000;
+		case SND_TONE:
+			break;
+		default:
+			return -1;
+		}
+		break;
+
+	default:
+		return -1;
+	}
+
+	if (value > 20 && value < 32767)
+		count = PIT_TICK_RATE / value;
+
+	pcspkr_do_sound(count);
+
+	return 0;
+}
+
+int __devinit pcspkr_input_init(struct input_dev **rdev, struct device *dev)
+{
+	int err;
+
+	struct input_dev *input_dev = input_allocate_device();
+	if (!input_dev)
+		return -ENOMEM;
+
+	input_dev->name = "PC Speaker";
+	input_dev->phys = "isa0061/input0";
+	input_dev->id.bustype = BUS_ISA;
+	input_dev->id.vendor = 0x001f;
+	input_dev->id.product = 0x0001;
+	input_dev->id.version = 0x0100;
+	input_dev->dev.parent = dev;
+
+	input_dev->evbit[0] = BIT(EV_SND);
+	input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
+	input_dev->event = pcspkr_input_event;
+
+	err = input_register_device(input_dev);
+	if (err) {
+		input_free_device(input_dev);
+		return err;
+	}
+
+	*rdev = input_dev;
+	return 0;
+}
+
+int pcspkr_input_remove(struct input_dev *dev)
+{
+	pcspkr_stop_sound();
+	input_unregister_device(dev);	/* this also does kfree() */
+
+	return 0;
+}
diff --git a/sound/drivers/pcsp/pcsp_input.h b/sound/drivers/pcsp/pcsp_input.h
new file mode 100644
index 0000000..e66738c
--- /dev/null
+++ b/sound/drivers/pcsp/pcsp_input.h
@@ -0,0 +1,14 @@
+/*
+ * PC-Speaker driver for Linux
+ *
+ * Copyright (C) 2001-2008  Stas Sergeev
+ */
+
+#ifndef __PCSP_INPUT_H__
+#define __PCSP_INPUT_H__
+
+int __devinit pcspkr_input_init(struct input_dev **rdev, struct device *dev);
+int pcspkr_input_remove(struct input_dev *dev);
+void pcspkr_stop_sound(void);
+
+#endif
diff --git a/sound/drivers/pcsp/pcsp_lib.c b/sound/drivers/pcsp/pcsp_lib.c
new file mode 100644
index 0000000..ac6238e
--- /dev/null
+++ b/sound/drivers/pcsp/pcsp_lib.c
@@ -0,0 +1,338 @@
+/*
+ * PC-Speaker driver for Linux
+ *
+ * Copyright (C) 1993-1997  Michael Beck
+ * Copyright (C) 1997-2001  David Woodhouse
+ * Copyright (C) 2001-2008  Stas Sergeev
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <sound/pcm.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#include "pcsp.h"
+
+static int nforce_wa;
+module_param(nforce_wa, bool, 0444);
+MODULE_PARM_DESC(nforce_wa, "Apply NForce chipset workaround "
+		"(expect bad sound)");
+
+static void pcsp_start_timer(unsigned long dummy)
+{
+	hrtimer_start(&pcsp_chip.timer, ktime_set(0, 0), HRTIMER_MODE_REL);
+}
+
+/*
+ * We need the hrtimer_start as a tasklet to avoid
+ * the nasty locking problem. :(
+ * The problem:
+ * - The timer handler is called with the cpu_base->lock
+ *   already held by hrtimer code.
+ * - snd_pcm_period_elapsed() takes the
+ *   substream->self_group.lock.
+ * So far so good.
+ * But the snd_pcsp_trigger() is called with the
+ * substream->self_group.lock held, and it calls
+ * hrtimer_start(), which takes the cpu_base->lock.
+ * You see the problem. We have the code pathes
+ * which take two locks in a reverse order. This
+ * can deadlock and the lock validator complains.
+ * The only solution I could find was to move the
+ * hrtimer_start() into a tasklet. -stsp
+ */
+static DECLARE_TASKLET(pcsp_start_timer_tasklet, pcsp_start_timer, 0);
+
+enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)
+{
+	unsigned long flags;
+	unsigned char timer_cnt, val;
+	int periods_elapsed;
+	u64 ns;
+	size_t period_bytes, buffer_bytes;
+	struct snd_pcm_substream *substream;
+	struct snd_pcm_runtime *runtime;
+	struct snd_pcsp *chip = container_of(handle, struct snd_pcsp, timer);
+
+	if (chip->thalf) {
+		outb(chip->val61, 0x61);
+		chip->thalf = 0;
+		if (!atomic_read(&chip->timer_active))
+			return HRTIMER_NORESTART;
+		hrtimer_forward(&chip->timer, chip->timer.expires,
+				ktime_set(0, chip->ns_rem));
+		return HRTIMER_RESTART;
+	}
+
+	/* hrtimer calls us from both hardirq and softirq contexts,
+	 * so irqsave :( */
+	spin_lock_irqsave(&chip->substream_lock, flags);
+	/* Takashi Iwai says regarding this extra lock:
+
+	If the irq handler handles some data on the DMA buffer, it should
+	do snd_pcm_stream_lock().
+	That protects basically against all races among PCM callbacks, yes.
+	However, there are two remaining issues:
+	1. The substream pointer you try to lock isn't protected _before_
+	  this lock yet.
+	2. snd_pcm_period_elapsed() itself acquires the lock.
+	The requirement of another lock is because of 1.  When you get
+	chip->playback_substream, it's not protected.
+	Keeping this lock while snd_pcm_period_elapsed() assures the substream
+	is still protected (at least, not released).  And the other status is
+	handled properly inside snd_pcm_stream_lock() in
+	snd_pcm_period_elapsed().
+
+	*/
+	if (!chip->playback_substream)
+		goto exit_nr_unlock1;
+	substream = chip->playback_substream;
+	snd_pcm_stream_lock(substream);
+	if (!atomic_read(&chip->timer_active))
+		goto exit_nr_unlock2;
+
+	runtime = substream->runtime;
+	/* assume it is u8 mono */
+	val = runtime->dma_area[chip->playback_ptr];
+	timer_cnt = val * CUR_DIV() / 256;
+
+	if (timer_cnt && chip->enable) {
+		spin_lock(&i8253_lock);
+		if (!nforce_wa) {
+			outb_p(chip->val61, 0x61);
+			outb_p(timer_cnt, 0x42);
+			outb(chip->val61 ^ 1, 0x61);
+		} else {
+			outb(chip->val61 ^ 2, 0x61);
+			chip->thalf = 1;
+		}
+		spin_unlock(&i8253_lock);
+	}
+
+	period_bytes = snd_pcm_lib_period_bytes(substream);
+	buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
+	chip->playback_ptr += PCSP_INDEX_INC();
+	periods_elapsed = chip->playback_ptr - chip->period_ptr;
+	if (periods_elapsed < 0) {
+		printk(KERN_WARNING "PCSP: playback_ptr inconsistent "
+			"(%zi %zi %zi)\n",
+			chip->playback_ptr, period_bytes, buffer_bytes);
+		periods_elapsed += buffer_bytes;
+	}
+	periods_elapsed /= period_bytes;
+	/* wrap the pointer _before_ calling snd_pcm_period_elapsed(),
+	 * or ALSA will BUG on us. */
+	chip->playback_ptr %= buffer_bytes;
+
+	snd_pcm_stream_unlock(substream);
+
+	if (periods_elapsed) {
+		snd_pcm_period_elapsed(substream);
+		chip->period_ptr += periods_elapsed * period_bytes;
+		chip->period_ptr %= buffer_bytes;
+	}
+
+	spin_unlock_irqrestore(&chip->substream_lock, flags);
+
+	if (!atomic_read(&chip->timer_active))
+		return HRTIMER_NORESTART;
+
+	chip->ns_rem = PCSP_PERIOD_NS();
+	ns = (chip->thalf ? PCSP_CALC_NS(timer_cnt) : chip->ns_rem);
+	chip->ns_rem -= ns;
+	hrtimer_forward(&chip->timer, chip->timer.expires, ktime_set(0, ns));
+	return HRTIMER_RESTART;
+
+exit_nr_unlock2:
+	snd_pcm_stream_unlock(substream);
+exit_nr_unlock1:
+	spin_unlock_irqrestore(&chip->substream_lock, flags);
+	return HRTIMER_NORESTART;
+}
+
+static void pcsp_start_playing(struct snd_pcsp *chip)
+{
+#if PCSP_DEBUG
+	printk(KERN_INFO "PCSP: start_playing called\n");
+#endif
+	if (atomic_read(&chip->timer_active)) {
+		printk(KERN_ERR "PCSP: Timer already active\n");
+		return;
+	}
+
+	spin_lock(&i8253_lock);
+	chip->val61 = inb(0x61) | 0x03;
+	outb_p(0x92, 0x43);	/* binary, mode 1, LSB only, ch 2 */
+	spin_unlock(&i8253_lock);
+	atomic_set(&chip->timer_active, 1);
+	chip->thalf = 0;
+
+	tasklet_schedule(&pcsp_start_timer_tasklet);
+}
+
+static void pcsp_stop_playing(struct snd_pcsp *chip)
+{
+#if PCSP_DEBUG
+	printk(KERN_INFO "PCSP: stop_playing called\n");
+#endif
+	if (!atomic_read(&chip->timer_active))
+		return;
+
+	atomic_set(&chip->timer_active, 0);
+	spin_lock(&i8253_lock);
+	/* restore the timer */
+	outb_p(0xb6, 0x43);	/* binary, mode 3, LSB/MSB, ch 2 */
+	outb(chip->val61 & 0xFC, 0x61);
+	spin_unlock(&i8253_lock);
+}
+
+static int snd_pcsp_playback_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
+#if PCSP_DEBUG
+	printk(KERN_INFO "PCSP: close called\n");
+#endif
+	if (atomic_read(&chip->timer_active)) {
+		printk(KERN_ERR "PCSP: timer still active\n");
+		pcsp_stop_playing(chip);
+	}
+	spin_lock_irq(&chip->substream_lock);
+	chip->playback_substream = NULL;
+	spin_unlock_irq(&chip->substream_lock);
+	return 0;
+}
+
+static int snd_pcsp_playback_hw_params(struct snd_pcm_substream *substream,
+				       struct snd_pcm_hw_params *hw_params)
+{
+	int err;
+	err = snd_pcm_lib_malloc_pages(substream,
+				      params_buffer_bytes(hw_params));
+	if (err < 0)
+		return err;
+	return 0;
+}
+
+static int snd_pcsp_playback_hw_free(struct snd_pcm_substream *substream)
+{
+#if PCSP_DEBUG
+	printk(KERN_INFO "PCSP: hw_free called\n");
+#endif
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static int snd_pcsp_playback_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
+#if PCSP_DEBUG
+	printk(KERN_INFO "PCSP: prepare called, "
+			"size=%zi psize=%zi f=%zi f1=%i\n",
+			snd_pcm_lib_buffer_bytes(substream),
+			snd_pcm_lib_period_bytes(substream),
+			snd_pcm_lib_buffer_bytes(substream) /
+			snd_pcm_lib_period_bytes(substream),
+			substream->runtime->periods);
+#endif
+	chip->playback_ptr = 0;
+	chip->period_ptr = 0;
+	return 0;
+}
+
+static int snd_pcsp_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
+#if PCSP_DEBUG
+	printk(KERN_INFO "PCSP: trigger called\n");
+#endif
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		pcsp_start_playing(chip);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		pcsp_stop_playing(chip);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static snd_pcm_uframes_t snd_pcsp_playback_pointer(struct snd_pcm_substream
+						   *substream)
+{
+	struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
+	return bytes_to_frames(substream->runtime, chip->playback_ptr);
+}
+
+static struct snd_pcm_hardware snd_pcsp_playback = {
+	.info = (SNDRV_PCM_INFO_INTERLEAVED |
+		 SNDRV_PCM_INFO_HALF_DUPLEX |
+		 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+	.formats = SNDRV_PCM_FMTBIT_U8,
+	.rates = SNDRV_PCM_RATE_KNOT,
+	.rate_min = PCSP_DEFAULT_SRATE,
+	.rate_max = PCSP_DEFAULT_SRATE,
+	.channels_min = 1,
+	.channels_max = 1,
+	.buffer_bytes_max = PCSP_BUFFER_SIZE,
+	.period_bytes_min = 64,
+	.period_bytes_max = PCSP_MAX_PERIOD_SIZE,
+	.periods_min = 2,
+	.periods_max = PCSP_MAX_PERIODS,
+	.fifo_size = 0,
+};
+
+static int snd_pcsp_playback_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+#if PCSP_DEBUG
+	printk(KERN_INFO "PCSP: open called\n");
+#endif
+	if (atomic_read(&chip->timer_active)) {
+		printk(KERN_ERR "PCSP: still active!!\n");
+		return -EBUSY;
+	}
+	runtime->hw = snd_pcsp_playback;
+	spin_lock_irq(&chip->substream_lock);
+	chip->playback_substream = substream;
+	spin_unlock_irq(&chip->substream_lock);
+	return 0;
+}
+
+static struct snd_pcm_ops snd_pcsp_playback_ops = {
+	.open = snd_pcsp_playback_open,
+	.close = snd_pcsp_playback_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = snd_pcsp_playback_hw_params,
+	.hw_free = snd_pcsp_playback_hw_free,
+	.prepare = snd_pcsp_playback_prepare,
+	.trigger = snd_pcsp_trigger,
+	.pointer = snd_pcsp_playback_pointer,
+};
+
+int __devinit snd_pcsp_new_pcm(struct snd_pcsp *chip)
+{
+	int err;
+
+	err = snd_pcm_new(chip->card, "pcspeaker", 0, 1, 0, &chip->pcm);
+	if (err < 0)
+		return err;
+
+	snd_pcm_set_ops(chip->pcm, SNDRV_PCM_STREAM_PLAYBACK,
+			&snd_pcsp_playback_ops);
+
+	chip->pcm->private_data = chip;
+	chip->pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX;
+	strcpy(chip->pcm->name, "pcsp");
+
+	snd_pcm_lib_preallocate_pages_for_all(chip->pcm,
+					      SNDRV_DMA_TYPE_CONTINUOUS,
+					      snd_dma_continuous_data
+					      (GFP_KERNEL), PCSP_BUFFER_SIZE,
+					      PCSP_BUFFER_SIZE);
+
+	return 0;
+}
diff --git a/sound/drivers/pcsp/pcsp_mixer.c b/sound/drivers/pcsp/pcsp_mixer.c
new file mode 100644
index 0000000..64a695f
--- /dev/null
+++ b/sound/drivers/pcsp/pcsp_mixer.c
@@ -0,0 +1,143 @@
+/*
+ * PC-Speaker driver for Linux
+ *
+ * Mixer implementation.
+ * Copyright (C) 2001-2008  Stas Sergeev
+ */
+
+#include <sound/core.h>
+#include <sound/control.h>
+#include "pcsp.h"
+
+
+static int pcsp_enable_info(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int pcsp_enable_get(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol);
+	ucontrol->value.integer.value[0] = chip->enable;
+	return 0;
+}
+
+static int pcsp_enable_put(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol);
+	int changed = 0;
+	int enab = ucontrol->value.integer.value[0];
+	if (enab != chip->enable) {
+		chip->enable = enab;
+		changed = 1;
+	}
+	return changed;
+}
+
+static int pcsp_treble_info(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_info *uinfo)
+{
+	struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol);
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = chip->max_treble + 1;
+	if (uinfo->value.enumerated.item > chip->max_treble)
+		uinfo->value.enumerated.item = chip->max_treble;
+	sprintf(uinfo->value.enumerated.name, "%d", PCSP_RATE());
+	return 0;
+}
+
+static int pcsp_treble_get(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol);
+	ucontrol->value.enumerated.item[0] = chip->treble;
+	return 0;
+}
+
+static int pcsp_treble_put(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol);
+	int changed = 0;
+	int treble = ucontrol->value.enumerated.item[0];
+	if (treble != chip->treble) {
+		chip->treble = treble;
+#if PCSP_DEBUG
+		printk(KERN_INFO "PCSP: rate set to %i\n", PCSP_RATE());
+#endif
+		changed = 1;
+	}
+	return changed;
+}
+
+static int pcsp_pcspkr_info(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int pcsp_pcspkr_get(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol);
+	ucontrol->value.integer.value[0] = chip->pcspkr;
+	return 0;
+}
+
+static int pcsp_pcspkr_put(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol);
+	int changed = 0;
+	int spkr = ucontrol->value.integer.value[0];
+	if (spkr != chip->pcspkr) {
+		chip->pcspkr = spkr;
+		changed = 1;
+	}
+	return changed;
+}
+
+#define PCSP_MIXER_CONTROL(ctl_type, ctl_name) \
+{ \
+	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER, \
+	.name =		ctl_name, \
+	.info =		pcsp_##ctl_type##_info, \
+	.get =		pcsp_##ctl_type##_get, \
+	.put =		pcsp_##ctl_type##_put, \
+}
+
+static struct snd_kcontrol_new __devinitdata snd_pcsp_controls[] = {
+	PCSP_MIXER_CONTROL(enable, "Master Playback Switch"),
+	PCSP_MIXER_CONTROL(treble, "BaseFRQ Playback Volume"),
+	PCSP_MIXER_CONTROL(pcspkr, "PC Speaker Playback Switch"),
+};
+
+int __devinit snd_pcsp_new_mixer(struct snd_pcsp *chip)
+{
+	struct snd_card *card = chip->card;
+	int i, err;
+
+	for (i = 0; i < ARRAY_SIZE(snd_pcsp_controls); i++) {
+		err = snd_ctl_add(card,
+				 snd_ctl_new1(snd_pcsp_controls + i,
+					      chip));
+		if (err < 0)
+			return err;
+	}
+
+	strcpy(card->mixername, "PC-Speaker");
+
+	return 0;
+}
diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c
index 15061bd..d20d893b 100644
--- a/sound/i2c/other/ak4114.c
+++ b/sound/i2c/other/ak4114.c
@@ -27,6 +27,7 @@
 #include <sound/pcm.h>
 #include <sound/ak4114.h>
 #include <sound/asoundef.h>
+#include <sound/info.h>
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("AK4114 IEC958 (S/PDIF) receiver by Asahi Kasei");
@@ -446,6 +447,26 @@
 }
 };
 
+
+static void snd_ak4114_proc_regs_read(struct snd_info_entry *entry,
+		struct snd_info_buffer *buffer)
+{
+	struct ak4114 *ak4114 = entry->private_data;
+	int reg, val;
+	/* all ak4114 registers 0x00 - 0x1f */
+	for (reg = 0; reg < 0x20; reg++) {
+		val = reg_read(ak4114, reg);
+		snd_iprintf(buffer, "0x%02x = 0x%02x\n", reg, val);
+	}
+}
+
+static void snd_ak4114_proc_init(struct ak4114 *ak4114)
+{
+	struct snd_info_entry *entry;
+	if (!snd_card_proc_new(ak4114->card, "ak4114", &entry))
+		snd_info_set_text_ops(entry, ak4114, snd_ak4114_proc_regs_read);
+}
+
 int snd_ak4114_build(struct ak4114 *ak4114,
 		     struct snd_pcm_substream *ply_substream,
 		     struct snd_pcm_substream *cap_substream)
@@ -478,6 +499,7 @@
 			return err;
 		ak4114->kctls[idx] = kctl;
 	}
+	snd_ak4114_proc_init(ak4114);
 	/* trigger workq */
 	schedule_delayed_work(&ak4114->work, HZ / 10);
 	return 0;
@@ -590,7 +612,7 @@
 	struct ak4114 *chip = container_of(work, struct ak4114, work.work);
 
 	if (!chip->init)
-		snd_ak4114_check_rate_and_errors(chip, 0);
+		snd_ak4114_check_rate_and_errors(chip, chip->check_flags);
 
 	schedule_delayed_work(&chip->work, HZ / 10);
 }
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c
index 35fbbf2..288926d 100644
--- a/sound/i2c/other/ak4xxx-adda.c
+++ b/sound/i2c/other/ak4xxx-adda.c
@@ -70,7 +70,8 @@
 }
 
 /* reset procedure for AK4355 and AK4358 */
-static void ak4355_reset(struct snd_akm4xxx *ak, int state)
+static void ak435X_reset(struct snd_akm4xxx *ak, int state,
+		unsigned char total_regs)
 {
 	unsigned char reg;
 
@@ -78,7 +79,7 @@
 		snd_akm4xxx_write(ak, 0, 0x01, 0x02); /* reset and soft-mute */
 		return;
 	}
-	for (reg = 0x00; reg < 0x0b; reg++)
+	for (reg = 0x00; reg < total_regs; reg++)
 		if (reg != 0x01)
 			snd_akm4xxx_write(ak, 0, reg,
 					  snd_akm4xxx_get(ak, 0, reg));
@@ -118,8 +119,10 @@
 		/* FIXME: needed for ak4529? */
 		break;
 	case SND_AK4355:
+		ak435X_reset(ak, state, 0x0b);
+		break;
 	case SND_AK4358:
-		ak4355_reset(ak, state);
+		ak435X_reset(ak, state, 0x10);
 		break;
 	case SND_AK4381:
 		ak4381_reset(ak, state);
@@ -292,11 +295,6 @@
 	case SND_AK5365:
 		/* FIXME: any init sequence? */
 		return;
-	case NON_AKM:
-		/* fake value for non-akm codecs using akm infrastructure
-		 * (e.g. of ice1724) - certainly FIXME
-		 */
-		return;
 	default:
 		snd_BUG();
 		return;
@@ -374,6 +372,8 @@
 		nval = mask - nval;
 	if (AK_GET_NEEDSMSB(kcontrol->private_value))
 		nval |= 0x80;
+	/* printk(KERN_DEBUG "DEBUG - AK writing reg: chip %x addr %x,
+	   nval %x\n", chip, addr, nval); */
 	snd_akm4xxx_write(ak, chip, addr, nval);
 	return 1;
 }
diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c
index bed29ca..f3fd7b4 100644
--- a/sound/isa/sb/sb16_csp.c
+++ b/sound/isa/sb/sb16_csp.c
@@ -331,7 +331,7 @@
 		return -EFAULT;
 	if ((file_h.name != RIFF_HEADER) ||
 	    (le32_to_cpu(file_h.len) >= SNDRV_SB_CSP_MAX_MICROCODE_FILE_SIZE - sizeof(file_h))) {
-		snd_printd("%s: Invalid RIFF header\n", __FUNCTION__);
+		snd_printd("%s: Invalid RIFF header\n", __func__);
 		return -EINVAL;
 	}
 	data_ptr += sizeof(file_h);
@@ -340,7 +340,7 @@
 	if (copy_from_user(&item_type, data_ptr, sizeof(item_type)))
 		return -EFAULT;
 	if (item_type != CSP__HEADER) {
-		snd_printd("%s: Invalid RIFF file type\n", __FUNCTION__);
+		snd_printd("%s: Invalid RIFF file type\n", __func__);
 		return -EINVAL;
 	}
 	data_ptr += sizeof (item_type);
@@ -395,7 +395,7 @@
 				return -EFAULT;
 
 			if (code_h.name != MAIN_HEADER) {
-				snd_printd("%s: Missing 'main' microcode\n", __FUNCTION__);
+				snd_printd("%s: Missing 'main' microcode\n", __func__);
 				return -EINVAL;
 			}
 			data_ptr += sizeof(code_h);
@@ -439,7 +439,7 @@
 				p->acc_format = p->acc_width = p->acc_rates = 0;
 				p->mode = 0;
 				snd_printd("%s: Unsupported CSP codec type: 0x%04x\n",
-					   __FUNCTION__,
+					   __func__,
 					   le16_to_cpu(funcdesc_h.VOC_type));
 				return -EINVAL;
 			}
@@ -458,7 +458,7 @@
 			return 0;
 		}
 	}
-	snd_printd("%s: Function #%d not found\n", __FUNCTION__, info.func_req);
+	snd_printd("%s: Function #%d not found\n", __func__, info.func_req);
 	return -EINVAL;
 }
 
@@ -612,7 +612,7 @@
 static int snd_sb_csp_check_version(struct snd_sb_csp * p)
 {
 	if (p->version < 0x10 || p->version > 0x1f) {
-		snd_printd("%s: Invalid CSP version: 0x%x\n", __FUNCTION__, p->version);
+		snd_printd("%s: Invalid CSP version: 0x%x\n", __func__, p->version);
 		return 1;
 	}
 	return 0;
@@ -631,7 +631,7 @@
 	spin_lock_irqsave(&p->chip->reg_lock, flags);
 	snd_sbdsp_command(p->chip, 0x01);	/* CSP download command */
 	if (snd_sbdsp_get_byte(p->chip)) {
-		snd_printd("%s: Download command failed\n", __FUNCTION__);
+		snd_printd("%s: Download command failed\n", __func__);
 		goto __fail;
 	}
 	/* Send CSP low byte (size - 1) */
@@ -658,7 +658,7 @@
 			udelay (10);
 		}
 		if (status != 0x55) {
-			snd_printd("%s: Microcode initialization failed\n", __FUNCTION__);
+			snd_printd("%s: Microcode initialization failed\n", __func__);
 			goto __fail;
 		}
 	} else {
@@ -824,19 +824,19 @@
 	unsigned long flags;
 
 	if (!(p->running & (SNDRV_SB_CSP_ST_LOADED | SNDRV_SB_CSP_ST_AUTO))) {
-		snd_printd("%s: Microcode not loaded\n", __FUNCTION__);
+		snd_printd("%s: Microcode not loaded\n", __func__);
 		return -ENXIO;
 	}
 	if (p->running & SNDRV_SB_CSP_ST_RUNNING) {
-		snd_printd("%s: CSP already running\n", __FUNCTION__);
+		snd_printd("%s: CSP already running\n", __func__);
 		return -EBUSY;
 	}
 	if (!(sample_width & p->acc_width)) {
-		snd_printd("%s: Unsupported PCM sample width\n", __FUNCTION__);
+		snd_printd("%s: Unsupported PCM sample width\n", __func__);
 		return -EINVAL;
 	}
 	if (!(channels & p->acc_channels)) {
-		snd_printd("%s: Invalid number of channels\n", __FUNCTION__);
+		snd_printd("%s: Invalid number of channels\n", __func__);
 		return -EINVAL;
 	}
 
@@ -858,11 +858,11 @@
 		s_type |= 0x22;	/* 00dX 00dX    (d = 1 if 8 bit samples) */
 
 	if (set_codec_parameter(p->chip, 0x81, s_type)) {
-		snd_printd("%s: Set sample type command failed\n", __FUNCTION__);
+		snd_printd("%s: Set sample type command failed\n", __func__);
 		goto __fail;
 	}
 	if (set_codec_parameter(p->chip, 0x80, 0x00)) {
-		snd_printd("%s: Codec start command failed\n", __FUNCTION__);
+		snd_printd("%s: Codec start command failed\n", __func__);
 		goto __fail;
 	}
 	p->run_width = sample_width;
diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c
index d63c1af..b432d9a 100644
--- a/sound/isa/sb/sb_common.c
+++ b/sound/isa/sb/sb_common.c
@@ -51,7 +51,7 @@
 			outb(val, SBP(chip, COMMAND));
 			return 1;
 		}
-	snd_printd("%s [0x%lx]: timeout (0x%x)\n", __FUNCTION__, chip->port, val);
+	snd_printd("%s [0x%lx]: timeout (0x%x)\n", __func__, chip->port, val);
 	return 0;
 }
 
@@ -68,7 +68,7 @@
 			return val;
 		}
 	}
-	snd_printd("%s [0x%lx]: timeout\n", __FUNCTION__, chip->port);
+	snd_printd("%s [0x%lx]: timeout\n", __func__, chip->port);
 	return -ENODEV;
 }
 
@@ -87,7 +87,7 @@
 			else
 				break;
 		}
-	snd_printdd("%s [0x%lx] failed...\n", __FUNCTION__, chip->port);
+	snd_printdd("%s [0x%lx] failed...\n", __func__, chip->port);
 	return -ENODEV;
 }
 
diff --git a/sound/oss/dmabuf.c b/sound/oss/dmabuf.c
index eaf6997..1e90d76 100644
--- a/sound/oss/dmabuf.c
+++ b/sound/oss/dmabuf.c
@@ -795,9 +795,9 @@
 #ifdef BE_CONSERVATIVE
 	active_offs = dmap->byte_counter + dmap->qhead * dmap->fragment_size;
 #else
-	active_offs = DMAbuf_get_buffer_pointer(dev, dmap, DMODE_OUTPUT);
+	active_offs = max(DMAbuf_get_buffer_pointer(dev, dmap, DMODE_OUTPUT), 0);
 	/* Check for pointer wrapping situation */
-	if (active_offs < 0 || active_offs >= dmap->bytes_in_use)
+	if (active_offs >= dmap->bytes_in_use)
 		active_offs = 0;
 	active_offs += dmap->byte_counter;
 #endif
diff --git a/sound/oss/trident.c b/sound/oss/trident.c
index d6af906..f43f91e 100644
--- a/sound/oss/trident.c
+++ b/sound/oss/trident.c
@@ -3076,8 +3076,7 @@
 	u16 wcontrol;
 	unsigned long flags;
 
-	if (!card)
-		BUG();
+	BUG_ON(!card);
 
 	address = ALI_AC97_READ;
 	if (card->revision == ALI_5451_V02) {
@@ -3148,8 +3147,7 @@
 
 	data = ((u32) val) << 16;
 
-	if (!card)
-		BUG();
+	BUG_ON(!card);
 
 	address = ALI_AC97_WRITE;
 	mask = ALI_AC97_WRITE_ACTION | ALI_AC97_AUDIO_BUSY;
@@ -3213,8 +3211,7 @@
 	struct trident_card *card = NULL;
 
 	/* Added by Matt Wu */
-	if (!codec)
-		BUG();
+	BUG_ON(!codec);
 
 	card = (struct trident_card *) codec->private_data;
 
@@ -3240,8 +3237,7 @@
 	struct trident_card *card;
 
 	/*  Added by Matt Wu */
-	if (!codec)
-		BUG();
+	BUG_ON(!codec);
 
 	card = (struct trident_card *) codec->private_data;
 
diff --git a/sound/oss/trident.h b/sound/oss/trident.h
index 4713b49..ff30a1d 100644
--- a/sound/oss/trident.h
+++ b/sound/oss/trident.h
@@ -322,7 +322,7 @@
 #define VALIDATE_MAGIC(FOO,MAG)				\
 ({						  	\
 	if (!(FOO) || (FOO)->magic != MAG) { 		\
-		printk(invalid_magic,__FUNCTION__);	\
+		printk(invalid_magic,__func__);	\
 		return -ENXIO;			  	\
 	}					  	\
 })
diff --git a/sound/oss/vwsnd.c b/sound/oss/vwsnd.c
index d25249a..2c5aaa5 100644
--- a/sound/oss/vwsnd.c
+++ b/sound/oss/vwsnd.c
@@ -194,11 +194,11 @@
  *	DBGRV	- debug print function return when verbose
  */
 
-#define ASSERT(e)      ((e) ? (void) 0 : dbgassert(__FUNCTION__, __LINE__, #e))
+#define ASSERT(e)      ((e) ? (void) 0 : dbgassert(__func__, __LINE__, #e))
 #define DBGDO(x)            x
 #define DBGX(fmt, args...)  (in_interrupt() ? 0 : printk(KERN_ERR fmt, ##args))
-#define DBGP(fmt, args...)  (DBGX("%s: " fmt, __FUNCTION__ , ##args))
-#define DBGE(fmt, args...)  (DBGX("%s" fmt, __FUNCTION__ , ##args))
+#define DBGP(fmt, args...)  (DBGX("%s: " fmt, __func__ , ##args))
+#define DBGE(fmt, args...)  (DBGX("%s" fmt, __func__ , ##args))
 #define DBGC(rtn)           (DBGP("calling %s\n", rtn))
 #define DBGR()              (DBGP("returning\n"))
 #define DBGXV(fmt, args...) (shut_up ? 0 : DBGX(fmt, ##args))
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 812085d..581debf 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -122,6 +122,21 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-au8830.
 
+config SND_AW2
+	tristate "Emagic Audiowerk 2"
+	depends on SND
+	help
+	  Say Y here to include support for Emagic Audiowerk 2 soundcards.
+
+	  Supported features: Analog and SPDIF output. Analog or SPDIF input.
+	  Note: Switch between analog and digital input does not always work.
+	  It can produce continuous noise. The workaround is to switch again
+	  (and again) between digital and analog input until it works.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called snd-aw2.
+
+
 config SND_AZT3328
 	tristate "Aztech AZF3328 / PCI168 (EXPERIMENTAL)"
 	depends on SND && EXPERIMENTAL
@@ -162,6 +177,7 @@
 	depends on SND
 	select SND_AC97_CODEC
 	select SND_RAWMIDI
+	select SND_VMASTER
 	help
 	  Say Y here to include support for the Sound Blaster Audigy LS
 	  and Live 24bit.
@@ -517,6 +533,7 @@
 	tristate "Intel HD Audio"
 	depends on SND
 	select SND_PCM
+	select SND_VMASTER
 	help
 	  Say Y here to include support for Intel "High Definition
 	  Audio" (Azalia) motherboard devices.
@@ -680,6 +697,7 @@
 	depends on SND
 	select SND_MPU401_UART
 	select SND_AC97_CODEC
+	select SND_VMASTER
 	help
 	  Say Y here to include support for soundcards based on
 	  ICE/VT1724/1720 (Envy24HT/PT) chips.
@@ -896,12 +914,12 @@
 	  will be called snd-via82xx-modem.
 
 config SND_VIRTUOSO
-	tristate "Asus Virtuoso 200 (Xonar)"
+	tristate "Asus Virtuoso 100/200 (Xonar)"
 	depends on SND
 	select SND_OXYGEN_LIB
 	help
 	  Say Y here to include support for sound cards based on the
-	  Asus AV200 chip, i.e., Xonar D2 and Xonar D2X.
+	  Asus AV100/AV200 chips, i.e., Xonar D2, DX and D2X.
 
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-virtuoso.
diff --git a/sound/pci/Makefile b/sound/pci/Makefile
index 2d42fd2..85ef14b 100644
--- a/sound/pci/Makefile
+++ b/sound/pci/Makefile
@@ -58,6 +58,7 @@
 	ac97/ \
 	ali5451/ \
 	au88x0/ \
+	aw2/ \
 	ca0106/ \
 	cs46xx/ \
 	cs5535audio/ \
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index 50c637e..39198e5 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -114,10 +114,9 @@
 
 static int ac97_channel_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
-	static const char *texts[] = { "2ch", "4ch", "6ch" };
-	if (kcontrol->private_value)
-		return ac97_enum_text_info(kcontrol, uinfo, texts, 2); /* 4ch only */
-	return ac97_enum_text_info(kcontrol, uinfo, texts, 3);
+	static const char *texts[] = { "2ch", "4ch", "6ch", "8ch" };
+	return ac97_enum_text_info(kcontrol, uinfo, texts,
+		kcontrol->private_value);
 }
 
 static int ac97_channel_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -133,13 +132,8 @@
 	struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
 	unsigned char mode = ucontrol->value.enumerated.item[0];
 
-	if (kcontrol->private_value) {
-		if (mode >= 2)
-			return -EINVAL;
-	} else {
-		if (mode >= 3)
-			return -EINVAL;
-	}
+	if (mode >= kcontrol->private_value)
+		return -EINVAL;
 
 	if (mode != ac97->channel_mode) {
 		ac97->channel_mode = mode;
@@ -158,6 +152,7 @@
 		.get = ac97_surround_jack_mode_get, \
 		.put = ac97_surround_jack_mode_put, \
 	}
+/* 6ch */
 #define AC97_CHANNEL_MODE_CTL \
 	{ \
 		.iface	= SNDRV_CTL_ELEM_IFACE_MIXER, \
@@ -165,7 +160,9 @@
 		.info = ac97_channel_mode_info, \
 		.get = ac97_channel_mode_get, \
 		.put = ac97_channel_mode_put, \
+		.private_value = 3, \
 	}
+/* 4ch */
 #define AC97_CHANNEL_MODE_4CH_CTL \
 	{ \
 		.iface	= SNDRV_CTL_ELEM_IFACE_MIXER, \
@@ -173,7 +170,17 @@
 		.info = ac97_channel_mode_info, \
 		.get = ac97_channel_mode_get, \
 		.put = ac97_channel_mode_put, \
-		.private_value = 1, \
+		.private_value = 2, \
+	}
+/* 8ch */
+#define AC97_CHANNEL_MODE_8CH_CTL \
+	{ \
+		.iface  = SNDRV_CTL_ELEM_IFACE_MIXER, \
+		.name   = "Channel Mode", \
+		.info = ac97_channel_mode_info, \
+		.get = ac97_channel_mode_get, \
+		.put = ac97_channel_mode_put, \
+		.private_value = 4, \
 	}
 
 static inline int is_surround_on(struct snd_ac97 *ac97)
@@ -210,6 +217,10 @@
 	return !ac97->indep_surround && !is_clfe_on(ac97);
 }
 
+static inline int alc850_is_aux_back_surround(struct snd_ac97 *ac97)
+{
+	return is_surround_on(ac97);
+}
 
 /* The following snd_ac97_ymf753_... items added by David Shust (dshust@shustring.com) */
 /* Modified for YMF743 by Keita Maehara <maehara@debian.org> */
@@ -2816,10 +2827,12 @@
 
 #define AC97_ALC850_JACK_SELECT	0x76
 #define AC97_ALC850_MISC1	0x7a
+#define AC97_ALC850_MULTICH    0x6a
 
 static void alc850_update_jacks(struct snd_ac97 *ac97)
 {
 	int shared;
+	int aux_is_back_surround;
 	
 	/* shared Line-In / Surround Out */
 	shared = is_shared_surrout(ac97);
@@ -2837,13 +2850,18 @@
 	/* MIC-IN = 1, CENTER-LFE = 5 */
 	snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 4,
 			     shared ? (5<<4) : (1<<4));
+
+	aux_is_back_surround = alc850_is_aux_back_surround(ac97);
+	/* Aux is Back Surround */
+	snd_ac97_update_bits(ac97, AC97_ALC850_MULTICH, 1 << 10,
+				 aux_is_back_surround ? (1<<10) : (0<<10));
 }
 
 static const struct snd_kcontrol_new snd_ac97_controls_alc850[] = {
 	AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0),
 	AC97_SINGLE("Mic Front Input Switch", AC97_ALC850_JACK_SELECT, 15, 1, 1),
 	AC97_SURROUND_JACK_MODE_CTL,
-	AC97_CHANNEL_MODE_CTL,
+	AC97_CHANNEL_MODE_8CH_CTL,
 };
 
 static int patch_alc850_specific(struct snd_ac97 *ac97)
@@ -2869,6 +2887,7 @@
 	ac97->build_ops = &patch_alc850_ops;
 
 	ac97->spec.dev_flags = 0; /* for IEC958 playback route - ALC655 compatible */
+	ac97->flags |= AC97_HAS_8CH;
 
 	/* assume only page 0 for writing cache */
 	snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, AC97_PAGE_VENDOR);
@@ -2878,6 +2897,7 @@
 	   spdif-in monitor off, spdif-in PCM off
 	   center on mic off, surround on line-in off
 	   duplicate front off
+	   NB default bit 10=0 = Aux is Capture, not Back Surround
 	*/
 	snd_ac97_write_cache(ac97, AC97_ALC650_MULTICH, 1<<15);
 	/* SURR_OUT: on, Surr 1kOhm: on, Surr Amp: off, Front 1kOhm: off
diff --git a/sound/pci/ac97/ac97_pcm.c b/sound/pci/ac97/ac97_pcm.c
index 3674f35..48cbda9 100644
--- a/sound/pci/ac97/ac97_pcm.c
+++ b/sound/pci/ac97/ac97_pcm.c
@@ -574,7 +574,6 @@
 	r = rate > 48000;
 	bus = pcm->bus;
 	if (cfg == AC97_PCM_CFG_SPDIF) {
-		int err;
 		for (cidx = 0; cidx < 4; cidx++)
 			if (bus->codec[cidx] && (bus->codec[cidx]->ext_id & AC97_EI_SPDIF)) {
 				err = set_spdif_rate(bus->codec[cidx], rate);
diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c
index a66d515..39ec55b 100644
--- a/sound/pci/ad1889.c
+++ b/sound/pci/ad1889.c
@@ -264,10 +264,10 @@
 		mdelay(1);
 	if (!retry) {
 		snd_printk(KERN_ERR PFX "[%s] Link is not ready.\n",
-		       __FUNCTION__);
+		       __func__);
 		return -EIO;
 	}
-	ad1889_debug("[%s] ready after %d ms\n", __FUNCTION__, 400 - retry);
+	ad1889_debug("[%s] ready after %d ms\n", __func__, 400 - retry);
 
 	return 0;
 }
@@ -854,8 +854,6 @@
 
 	spin_unlock_irq(&chip->lock);
 
-	synchronize_irq(chip->irq);
-	
 	if (chip->irq >= 0)
 		free_irq(chip->irq, chip);
 
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
index 6a905ed..1a0fd65 100644
--- a/sound/pci/ali5451/ali5451.c
+++ b/sound/pci/ali5451/ali5451.c
@@ -1809,26 +1809,26 @@
 				 struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ali *codec = kcontrol->private_data;
-	unsigned int enable;
+	unsigned int spdif_enable;
 
-	enable = ucontrol->value.integer.value[0] ? 1 : 0;
+	spdif_enable = ucontrol->value.integer.value[0] ? 1 : 0;
 
 	spin_lock_irq(&codec->reg_lock);
 	switch (kcontrol->private_value) {
 	case 0:
-		enable = (codec->spdif_mask & 0x02) ? 1 : 0;
+		spdif_enable = (codec->spdif_mask & 0x02) ? 1 : 0;
 		break;
 	case 1:
-		enable = ((codec->spdif_mask & 0x02) &&
+		spdif_enable = ((codec->spdif_mask & 0x02) &&
 			  (codec->spdif_mask & 0x04)) ? 1 : 0;
 		break;
 	case 2:
-		enable = (codec->spdif_mask & 0x01) ? 1 : 0;
+		spdif_enable = (codec->spdif_mask & 0x01) ? 1 : 0;
 		break;
 	default:
 		break;
 	}
-	ucontrol->value.integer.value[0] = enable;
+	ucontrol->value.integer.value[0] = spdif_enable;
 	spin_unlock_irq(&codec->reg_lock);
 	return 0;
 }
@@ -1837,17 +1837,17 @@
 				 struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ali *codec = kcontrol->private_data;
-	unsigned int change = 0, enable = 0;
+	unsigned int change = 0, spdif_enable = 0;
 
-	enable = ucontrol->value.integer.value[0] ? 1 : 0;
+	spdif_enable = ucontrol->value.integer.value[0] ? 1 : 0;
 
 	spin_lock_irq(&codec->reg_lock);
 	switch (kcontrol->private_value) {
 	case 0:
 		change = (codec->spdif_mask & 0x02) ? 1 : 0;
-		change = change ^ enable;
+		change = change ^ spdif_enable;
 		if (change) {
-			if (enable) {
+			if (spdif_enable) {
 				codec->spdif_mask |= 0x02;
 				snd_ali_enable_spdif_out(codec);
 			} else {
@@ -1859,9 +1859,9 @@
 		break;
 	case 1: 
 		change = (codec->spdif_mask & 0x04) ? 1 : 0;
-		change = change ^ enable;
+		change = change ^ spdif_enable;
 		if (change && (codec->spdif_mask & 0x02)) {
-			if (enable) {
+			if (spdif_enable) {
 				codec->spdif_mask |= 0x04;
 				snd_ali_enable_spdif_chnout(codec);
 			} else {
@@ -1872,9 +1872,9 @@
 		break;
 	case 2:
 		change = (codec->spdif_mask & 0x01) ? 1 : 0;
-		change = change ^ enable;
+		change = change ^ spdif_enable;
 		if (change) {
-			if (enable) {
+			if (spdif_enable) {
 				codec->spdif_mask |= 0x01;
 				snd_ali_enable_spdif_in(codec);
 			} else {
@@ -2047,10 +2047,8 @@
 {
 	if (codec->hw_initialized)
 		snd_ali_disable_address_interrupt(codec);
-	if (codec->irq >= 0) {
-		synchronize_irq(codec->irq);
+	if (codec->irq >= 0)
 		free_irq(codec->irq, codec);
-	}
 	if (codec->port)
 		pci_release_regions(codec->pci);
 	pci_disable_device(codec->pci);
diff --git a/sound/pci/als300.c b/sound/pci/als300.c
index 0e990a7..8df6824 100644
--- a/sound/pci/als300.c
+++ b/sound/pci/als300.c
@@ -92,8 +92,8 @@
 
 #if DEBUG_CALLS
 #define snd_als300_dbgcalls(format, args...) printk(format, ##args)
-#define snd_als300_dbgcallenter() printk(KERN_ERR "--> %s\n", __FUNCTION__)
-#define snd_als300_dbgcallleave() printk(KERN_ERR "<-- %s\n", __FUNCTION__)
+#define snd_als300_dbgcallenter() printk(KERN_ERR "--> %s\n", __func__)
+#define snd_als300_dbgcallleave() printk(KERN_ERR "<-- %s\n", __func__)
 #else
 #define snd_als300_dbgcalls(format, args...)
 #define snd_als300_dbgcallenter()
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index 4594186..457228f 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -1553,7 +1553,7 @@
 	if (chip->irq < 0)
 		goto __hw_end;
 	snd_atiixp_chip_stop(chip);
-	synchronize_irq(chip->irq);
+
       __hw_end:
 	if (chip->irq >= 0)
 		free_irq(chip->irq, chip);
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index a67a869..d457a32 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -1197,7 +1197,7 @@
 	if (chip->irq < 0)
 		goto __hw_end;
 	snd_atiixp_chip_stop(chip);
-	synchronize_irq(chip->irq);
+
       __hw_end:
 	if (chip->irq >= 0)
 		free_irq(chip->irq, chip);
diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c
index 26819e2..68368e4 100644
--- a/sound/pci/au88x0/au88x0.c
+++ b/sound/pci/au88x0/au88x0.c
@@ -126,7 +126,6 @@
 	vortex_gameport_unregister(vortex);
 	vortex_core_shutdown(vortex);
 	// Take down PCI interface.
-	synchronize_irq(vortex->irq);
 	free_irq(vortex->irq, vortex);
 	iounmap(vortex->mmio);
 	pci_release_regions(vortex->pci_dev);
@@ -220,7 +219,6 @@
 	return 0;
 
       alloc_out:
-	synchronize_irq(chip->irq);
 	free_irq(chip->irq, chip);
       irq_out:
 	vortex_core_shutdown(chip);
diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c
index 526c6c5..f9a58b4 100644
--- a/sound/pci/au88x0/au88x0_pcm.c
+++ b/sound/pci/au88x0/au88x0_pcm.c
@@ -498,14 +498,14 @@
 };
 
 /* create a pcm device */
-static int __devinit snd_vortex_new_pcm(vortex_t * chip, int idx, int nr)
+static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr)
 {
 	struct snd_pcm *pcm;
 	struct snd_kcontrol *kctl;
 	int i;
 	int err, nr_capt;
 
-	if ((chip == 0) || (idx < 0) || (idx >= VORTEX_PCM_LAST))
+	if (!chip || idx < 0 || idx >= VORTEX_PCM_LAST)
 		return -ENODEV;
 
 	/* idx indicates which kind of PCM device. ADB, SPDIF, I2S and A3D share the 
@@ -514,9 +514,9 @@
 		nr_capt = nr;
 	else
 		nr_capt = 0;
-	if ((err =
-	     snd_pcm_new(chip->card, vortex_pcm_prettyname[idx], idx, nr,
-			 nr_capt, &pcm)) < 0)
+	err = snd_pcm_new(chip->card, vortex_pcm_prettyname[idx], idx, nr,
+			  nr_capt, &pcm);
+	if (err < 0)
 		return err;
 	strcpy(pcm->name, vortex_pcm_name[idx]);
 	chip->pcm[idx] = pcm;
diff --git a/sound/pci/aw2/Makefile b/sound/pci/aw2/Makefile
new file mode 100644
index 0000000..842335d
--- /dev/null
+++ b/sound/pci/aw2/Makefile
@@ -0,0 +1,3 @@
+snd-aw2-objs := aw2-alsa.o aw2-saa7146.o
+
+obj-$(CONFIG_SND_AW2) += snd-aw2.o
diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c
new file mode 100644
index 0000000..56f87cd
--- /dev/null
+++ b/sound/pci/aw2/aw2-alsa.c
@@ -0,0 +1,794 @@
+/*****************************************************************************
+ *
+ * Copyright (C) 2008 Cedric Bregardis <cedric.bregardis@free.fr> and
+ * Jean-Christian Hassler <jhassler@free.fr>
+ *
+ * This file is part of the Audiowerk2 ALSA driver
+ *
+ * The Audiowerk2 ALSA driver is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2.
+ *
+ * The Audiowerk2 ALSA driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Audiowerk2 ALSA driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+ * USA.
+ *
+ *****************************************************************************/
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/control.h>
+
+#include "saa7146.h"
+#include "aw2-saa7146.h"
+
+MODULE_AUTHOR("Cedric Bregardis <cedric.bregardis@free.fr>, "
+	      "Jean-Christian Hassler <jhassler@free.fr>");
+MODULE_DESCRIPTION("Emagic Audiowerk 2 sound driver");
+MODULE_LICENSE("GPL");
+
+/*********************************
+ * DEFINES
+ ********************************/
+#define PCI_VENDOR_ID_SAA7146		  0x1131
+#define PCI_DEVICE_ID_SAA7146		  0x7146
+
+#define CTL_ROUTE_ANALOG 0
+#define CTL_ROUTE_DIGITAL 1
+
+/*********************************
+ * TYPEDEFS
+ ********************************/
+  /* hardware definition */
+static struct snd_pcm_hardware snd_aw2_playback_hw = {
+	.info = (SNDRV_PCM_INFO_MMAP |
+		 SNDRV_PCM_INFO_INTERLEAVED |
+		 SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID),
+	.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	.rates = SNDRV_PCM_RATE_44100,
+	.rate_min = 44100,
+	.rate_max = 44100,
+	.channels_min = 2,
+	.channels_max = 4,
+	.buffer_bytes_max = 32768,
+	.period_bytes_min = 4096,
+	.period_bytes_max = 32768,
+	.periods_min = 1,
+	.periods_max = 1024,
+};
+
+static struct snd_pcm_hardware snd_aw2_capture_hw = {
+	.info = (SNDRV_PCM_INFO_MMAP |
+		 SNDRV_PCM_INFO_INTERLEAVED |
+		 SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID),
+	.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	.rates = SNDRV_PCM_RATE_44100,
+	.rate_min = 44100,
+	.rate_max = 44100,
+	.channels_min = 2,
+	.channels_max = 2,
+	.buffer_bytes_max = 32768,
+	.period_bytes_min = 4096,
+	.period_bytes_max = 32768,
+	.periods_min = 1,
+	.periods_max = 1024,
+};
+
+struct aw2_pcm_device {
+	struct snd_pcm *pcm;
+	unsigned int stream_number;
+	struct aw2 *chip;
+};
+
+struct aw2 {
+	struct snd_aw2_saa7146 saa7146;
+
+	struct pci_dev *pci;
+	int irq;
+	spinlock_t reg_lock;
+	struct mutex mtx;
+
+	unsigned long iobase_phys;
+	void __iomem *iobase_virt;
+
+	struct snd_card *card;
+
+	struct aw2_pcm_device device_playback[NB_STREAM_PLAYBACK];
+	struct aw2_pcm_device device_capture[NB_STREAM_CAPTURE];
+};
+
+/*********************************
+ * FUNCTION DECLARATIONS
+ ********************************/
+static int __init alsa_card_aw2_init(void);
+static void __exit alsa_card_aw2_exit(void);
+static int snd_aw2_dev_free(struct snd_device *device);
+static int __devinit snd_aw2_create(struct snd_card *card,
+				    struct pci_dev *pci, struct aw2 **rchip);
+static int __devinit snd_aw2_probe(struct pci_dev *pci,
+				   const struct pci_device_id *pci_id);
+static void __devexit snd_aw2_remove(struct pci_dev *pci);
+static int snd_aw2_pcm_playback_open(struct snd_pcm_substream *substream);
+static int snd_aw2_pcm_playback_close(struct snd_pcm_substream *substream);
+static int snd_aw2_pcm_capture_open(struct snd_pcm_substream *substream);
+static int snd_aw2_pcm_capture_close(struct snd_pcm_substream *substream);
+static int snd_aw2_pcm_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *hw_params);
+static int snd_aw2_pcm_hw_free(struct snd_pcm_substream *substream);
+static int snd_aw2_pcm_prepare_playback(struct snd_pcm_substream *substream);
+static int snd_aw2_pcm_prepare_capture(struct snd_pcm_substream *substream);
+static int snd_aw2_pcm_trigger_playback(struct snd_pcm_substream *substream,
+					int cmd);
+static int snd_aw2_pcm_trigger_capture(struct snd_pcm_substream *substream,
+				       int cmd);
+static snd_pcm_uframes_t snd_aw2_pcm_pointer_playback(struct snd_pcm_substream
+						      *substream);
+static snd_pcm_uframes_t snd_aw2_pcm_pointer_capture(struct snd_pcm_substream
+						     *substream);
+static int __devinit snd_aw2_new_pcm(struct aw2 *chip);
+
+static int snd_aw2_control_switch_capture_info(struct snd_kcontrol *kcontrol,
+					       struct snd_ctl_elem_info *uinfo);
+static int snd_aw2_control_switch_capture_get(struct snd_kcontrol *kcontrol,
+					      struct snd_ctl_elem_value
+					      *ucontrol);
+static int snd_aw2_control_switch_capture_put(struct snd_kcontrol *kcontrol,
+					      struct snd_ctl_elem_value
+					      *ucontrol);
+
+/*********************************
+ * VARIABLES
+ ********************************/
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for Audiowerk2 soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for the Audiowerk2 soundcard.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable Audiowerk2 soundcard.");
+
+static struct pci_device_id snd_aw2_ids[] = {
+	{PCI_VENDOR_ID_SAA7146, PCI_DEVICE_ID_SAA7146, PCI_ANY_ID, PCI_ANY_ID,
+	 0, 0, 0},
+	{0}
+};
+
+MODULE_DEVICE_TABLE(pci, snd_aw2_ids);
+
+/* pci_driver definition */
+static struct pci_driver driver = {
+	.name = "Emagic Audiowerk 2",
+	.id_table = snd_aw2_ids,
+	.probe = snd_aw2_probe,
+	.remove = __devexit_p(snd_aw2_remove),
+};
+
+/* operators for playback PCM alsa interface */
+static struct snd_pcm_ops snd_aw2_playback_ops = {
+	.open = snd_aw2_pcm_playback_open,
+	.close = snd_aw2_pcm_playback_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = snd_aw2_pcm_hw_params,
+	.hw_free = snd_aw2_pcm_hw_free,
+	.prepare = snd_aw2_pcm_prepare_playback,
+	.trigger = snd_aw2_pcm_trigger_playback,
+	.pointer = snd_aw2_pcm_pointer_playback,
+};
+
+/* operators for capture PCM alsa interface */
+static struct snd_pcm_ops snd_aw2_capture_ops = {
+	.open = snd_aw2_pcm_capture_open,
+	.close = snd_aw2_pcm_capture_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = snd_aw2_pcm_hw_params,
+	.hw_free = snd_aw2_pcm_hw_free,
+	.prepare = snd_aw2_pcm_prepare_capture,
+	.trigger = snd_aw2_pcm_trigger_capture,
+	.pointer = snd_aw2_pcm_pointer_capture,
+};
+
+static struct snd_kcontrol_new aw2_control __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "PCM Capture Route",
+	.index = 0,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.private_value = 0xffff,
+	.info = snd_aw2_control_switch_capture_info,
+	.get = snd_aw2_control_switch_capture_get,
+	.put = snd_aw2_control_switch_capture_put
+};
+
+/*********************************
+ * FUNCTION IMPLEMENTATIONS
+ ********************************/
+
+/* initialization of the module */
+static int __init alsa_card_aw2_init(void)
+{
+	snd_printdd(KERN_DEBUG "aw2: Load aw2 module\n");
+	return pci_register_driver(&driver);
+}
+
+/* clean up the module */
+static void __exit alsa_card_aw2_exit(void)
+{
+	snd_printdd(KERN_DEBUG "aw2: Unload aw2 module\n");
+	pci_unregister_driver(&driver);
+}
+
+module_init(alsa_card_aw2_init);
+module_exit(alsa_card_aw2_exit);
+
+/* component-destructor */
+static int snd_aw2_dev_free(struct snd_device *device)
+{
+	struct aw2 *chip = device->device_data;
+
+	/* Free hardware */
+	snd_aw2_saa7146_free(&chip->saa7146);
+
+	/* release the irq */
+	if (chip->irq >= 0)
+		free_irq(chip->irq, (void *)chip);
+	/* release the i/o ports & memory */
+	if (chip->iobase_virt)
+		iounmap(chip->iobase_virt);
+
+	pci_release_regions(chip->pci);
+	/* disable the PCI entry */
+	pci_disable_device(chip->pci);
+	/* release the data */
+	kfree(chip);
+
+	return 0;
+}
+
+/* chip-specific constructor */
+static int __devinit snd_aw2_create(struct snd_card *card,
+				    struct pci_dev *pci, struct aw2 **rchip)
+{
+	struct aw2 *chip;
+	int err;
+	static struct snd_device_ops ops = {
+		.dev_free = snd_aw2_dev_free,
+	};
+
+	*rchip = NULL;
+
+	/* initialize the PCI entry */
+	err = pci_enable_device(pci);
+	if (err < 0)
+		return err;
+	pci_set_master(pci);
+
+	/* check PCI availability (32bit DMA) */
+	if ((pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0) ||
+	    (pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0)) {
+		printk(KERN_ERR "aw2: Impossible to set 32bit mask DMA\n");
+		pci_disable_device(pci);
+		return -ENXIO;
+	}
+	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+	if (chip == NULL) {
+		pci_disable_device(pci);
+		return -ENOMEM;
+	}
+
+	/* initialize the stuff */
+	chip->card = card;
+	chip->pci = pci;
+	chip->irq = -1;
+
+	/* (1) PCI resource allocation */
+	err = pci_request_regions(pci, "Audiowerk2");
+	if (err < 0) {
+		pci_disable_device(pci);
+		kfree(chip);
+		return err;
+	}
+	chip->iobase_phys = pci_resource_start(pci, 0);
+	chip->iobase_virt =
+		ioremap_nocache(chip->iobase_phys,
+				pci_resource_len(pci, 0));
+
+	if (chip->iobase_virt == NULL) {
+		printk(KERN_ERR "aw2: unable to remap memory region");
+		pci_release_regions(pci);
+		pci_disable_device(pci);
+		kfree(chip);
+		return -ENOMEM;
+	}
+
+
+	if (request_irq(pci->irq, snd_aw2_saa7146_interrupt,
+			IRQF_SHARED, "Audiowerk2", chip)) {
+		printk(KERN_ERR "aw2: Cannot grab irq %d\n", pci->irq);
+
+		iounmap(chip->iobase_virt);
+		pci_release_regions(chip->pci);
+		pci_disable_device(chip->pci);
+		kfree(chip);
+		return -EBUSY;
+	}
+	chip->irq = pci->irq;
+
+	/* (2) initialization of the chip hardware */
+	snd_aw2_saa7146_setup(&chip->saa7146, chip->iobase_virt);
+	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+	if (err < 0) {
+		free_irq(chip->irq, (void *)chip);
+		iounmap(chip->iobase_virt);
+		pci_release_regions(chip->pci);
+		pci_disable_device(chip->pci);
+		kfree(chip);
+		return err;
+	}
+
+	snd_card_set_dev(card, &pci->dev);
+	*rchip = chip;
+
+	printk(KERN_INFO
+	       "Audiowerk 2 sound card (saa7146 chipset) detected and "
+	       "managed\n");
+	return 0;
+}
+
+/* constructor */
+static int __devinit snd_aw2_probe(struct pci_dev *pci,
+				   const struct pci_device_id *pci_id)
+{
+	static int dev;
+	struct snd_card *card;
+	struct aw2 *chip;
+	int err;
+
+	/* (1) Continue if device is not enabled, else inc dev */
+	if (dev >= SNDRV_CARDS)
+		return -ENODEV;
+	if (!enable[dev]) {
+		dev++;
+		return -ENOENT;
+	}
+
+	/* (2) Create card instance */
+	card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+	if (card == NULL)
+		return -ENOMEM;
+
+	/* (3) Create main component */
+	err = snd_aw2_create(card, pci, &chip);
+	if (err < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+	/* initialize mutex */
+	mutex_init(&chip->mtx);
+	/* init spinlock */
+	spin_lock_init(&chip->reg_lock);
+	/* (4) Define driver ID and name string */
+	strcpy(card->driver, "aw2");
+	strcpy(card->shortname, "Audiowerk2");
+
+	sprintf(card->longname, "%s with SAA7146 irq %i",
+		card->shortname, chip->irq);
+
+	/* (5) Create other components */
+	snd_aw2_new_pcm(chip);
+
+	/* (6) Register card instance */
+	err = snd_card_register(card);
+	if (err < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+	/* (7) Set PCI driver data */
+	pci_set_drvdata(pci, card);
+
+	dev++;
+	return 0;
+}
+
+/* destructor */
+static void __devexit snd_aw2_remove(struct pci_dev *pci)
+{
+	snd_card_free(pci_get_drvdata(pci));
+	pci_set_drvdata(pci, NULL);
+}
+
+/* open callback */
+static int snd_aw2_pcm_playback_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	snd_printdd(KERN_DEBUG "aw2: Playback_open \n");
+	runtime->hw = snd_aw2_playback_hw;
+	return 0;
+}
+
+/* close callback */
+static int snd_aw2_pcm_playback_close(struct snd_pcm_substream *substream)
+{
+	return 0;
+
+}
+
+static int snd_aw2_pcm_capture_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	snd_printdd(KERN_DEBUG "aw2: Capture_open \n");
+	runtime->hw = snd_aw2_capture_hw;
+	return 0;
+}
+
+/* close callback */
+static int snd_aw2_pcm_capture_close(struct snd_pcm_substream *substream)
+{
+	/* TODO: something to do ? */
+	return 0;
+}
+
+ /* hw_params callback */
+static int snd_aw2_pcm_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *hw_params)
+{
+	return snd_pcm_lib_malloc_pages(substream,
+					params_buffer_bytes(hw_params));
+}
+
+/* hw_free callback */
+static int snd_aw2_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_lib_free_pages(substream);
+}
+
+/* prepare callback for playback */
+static int snd_aw2_pcm_prepare_playback(struct snd_pcm_substream *substream)
+{
+	struct aw2_pcm_device *pcm_device = snd_pcm_substream_chip(substream);
+	struct aw2 *chip = pcm_device->chip;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	unsigned long period_size, buffer_size;
+
+	mutex_lock(&chip->mtx);
+
+	period_size = snd_pcm_lib_period_bytes(substream);
+	buffer_size = snd_pcm_lib_buffer_bytes(substream);
+
+	snd_aw2_saa7146_pcm_init_playback(&chip->saa7146,
+					  pcm_device->stream_number,
+					  runtime->dma_addr, period_size,
+					  buffer_size);
+
+	/* Define Interrupt callback */
+	snd_aw2_saa7146_define_it_playback_callback(pcm_device->stream_number,
+						    (snd_aw2_saa7146_it_cb)
+						    snd_pcm_period_elapsed,
+						    (void *)substream);
+
+	mutex_unlock(&chip->mtx);
+
+	return 0;
+}
+
+/* prepare callback for capture */
+static int snd_aw2_pcm_prepare_capture(struct snd_pcm_substream *substream)
+{
+	struct aw2_pcm_device *pcm_device = snd_pcm_substream_chip(substream);
+	struct aw2 *chip = pcm_device->chip;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	unsigned long period_size, buffer_size;
+
+	mutex_lock(&chip->mtx);
+
+	period_size = snd_pcm_lib_period_bytes(substream);
+	buffer_size = snd_pcm_lib_buffer_bytes(substream);
+
+	snd_aw2_saa7146_pcm_init_capture(&chip->saa7146,
+					 pcm_device->stream_number,
+					 runtime->dma_addr, period_size,
+					 buffer_size);
+
+	/* Define Interrupt callback */
+	snd_aw2_saa7146_define_it_capture_callback(pcm_device->stream_number,
+						   (snd_aw2_saa7146_it_cb)
+						   snd_pcm_period_elapsed,
+						   (void *)substream);
+
+	mutex_unlock(&chip->mtx);
+
+	return 0;
+}
+
+/* playback trigger callback */
+static int snd_aw2_pcm_trigger_playback(struct snd_pcm_substream *substream,
+					int cmd)
+{
+	int status = 0;
+	struct aw2_pcm_device *pcm_device = snd_pcm_substream_chip(substream);
+	struct aw2 *chip = pcm_device->chip;
+	spin_lock(&chip->reg_lock);
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		snd_aw2_saa7146_pcm_trigger_start_playback(&chip->saa7146,
+							   pcm_device->
+							   stream_number);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		snd_aw2_saa7146_pcm_trigger_stop_playback(&chip->saa7146,
+							  pcm_device->
+							  stream_number);
+		break;
+	default:
+		status = -EINVAL;
+	}
+	spin_unlock(&chip->reg_lock);
+	return status;
+}
+
+/* capture trigger callback */
+static int snd_aw2_pcm_trigger_capture(struct snd_pcm_substream *substream,
+				       int cmd)
+{
+	int status = 0;
+	struct aw2_pcm_device *pcm_device = snd_pcm_substream_chip(substream);
+	struct aw2 *chip = pcm_device->chip;
+	spin_lock(&chip->reg_lock);
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		snd_aw2_saa7146_pcm_trigger_start_capture(&chip->saa7146,
+							  pcm_device->
+							  stream_number);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		snd_aw2_saa7146_pcm_trigger_stop_capture(&chip->saa7146,
+							 pcm_device->
+							 stream_number);
+		break;
+	default:
+		status = -EINVAL;
+	}
+	spin_unlock(&chip->reg_lock);
+	return status;
+}
+
+/* playback pointer callback */
+static snd_pcm_uframes_t snd_aw2_pcm_pointer_playback(struct snd_pcm_substream
+						      *substream)
+{
+	struct aw2_pcm_device *pcm_device = snd_pcm_substream_chip(substream);
+	struct aw2 *chip = pcm_device->chip;
+	unsigned int current_ptr;
+
+	/* get the current hardware pointer */
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	current_ptr =
+		snd_aw2_saa7146_get_hw_ptr_playback(&chip->saa7146,
+						    pcm_device->stream_number,
+						    runtime->dma_area,
+						    runtime->buffer_size);
+
+	return bytes_to_frames(substream->runtime, current_ptr);
+}
+
+/* capture pointer callback */
+static snd_pcm_uframes_t snd_aw2_pcm_pointer_capture(struct snd_pcm_substream
+						     *substream)
+{
+	struct aw2_pcm_device *pcm_device = snd_pcm_substream_chip(substream);
+	struct aw2 *chip = pcm_device->chip;
+	unsigned int current_ptr;
+
+	/* get the current hardware pointer */
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	current_ptr =
+		snd_aw2_saa7146_get_hw_ptr_capture(&chip->saa7146,
+						   pcm_device->stream_number,
+						   runtime->dma_area,
+						   runtime->buffer_size);
+
+	return bytes_to_frames(substream->runtime, current_ptr);
+}
+
+/* create a pcm device */
+static int __devinit snd_aw2_new_pcm(struct aw2 *chip)
+{
+	struct snd_pcm *pcm_playback_ana;
+	struct snd_pcm *pcm_playback_num;
+	struct snd_pcm *pcm_capture;
+	struct aw2_pcm_device *pcm_device;
+	int err = 0;
+
+	/* Create new Alsa PCM device */
+
+	err = snd_pcm_new(chip->card, "Audiowerk2 analog playback", 0, 1, 0,
+			  &pcm_playback_ana);
+	if (err < 0) {
+		printk(KERN_ERR "aw2: snd_pcm_new error (0x%X)\n", err);
+		return err;
+	}
+
+	/* Creation ok */
+	pcm_device = &chip->device_playback[NUM_STREAM_PLAYBACK_ANA];
+
+	/* Set PCM device name */
+	strcpy(pcm_playback_ana->name, "Analog playback");
+	/* Associate private data to PCM device */
+	pcm_playback_ana->private_data = pcm_device;
+	/* set operators of PCM device */
+	snd_pcm_set_ops(pcm_playback_ana, SNDRV_PCM_STREAM_PLAYBACK,
+			&snd_aw2_playback_ops);
+	/* store PCM device */
+	pcm_device->pcm = pcm_playback_ana;
+	/* give base chip pointer to our internal pcm device
+	   structure */
+	pcm_device->chip = chip;
+	/* Give stream number to PCM device */
+	pcm_device->stream_number = NUM_STREAM_PLAYBACK_ANA;
+
+	/* pre-allocation of buffers */
+	/* Preallocate continuous pages. */
+	err = snd_pcm_lib_preallocate_pages_for_all(pcm_playback_ana,
+						    SNDRV_DMA_TYPE_DEV,
+						    snd_dma_pci_data
+						    (chip->pci),
+						    64 * 1024, 64 * 1024);
+	if (err)
+		printk(KERN_ERR "aw2: snd_pcm_lib_preallocate_pages_for_all "
+		       "error (0x%X)\n", err);
+
+	err = snd_pcm_new(chip->card, "Audiowerk2 digital playback", 1, 1, 0,
+			  &pcm_playback_num);
+
+	if (err < 0) {
+		printk(KERN_ERR "aw2: snd_pcm_new error (0x%X)\n", err);
+		return err;
+	}
+	/* Creation ok */
+	pcm_device = &chip->device_playback[NUM_STREAM_PLAYBACK_DIG];
+
+	/* Set PCM device name */
+	strcpy(pcm_playback_num->name, "Digital playback");
+	/* Associate private data to PCM device */
+	pcm_playback_num->private_data = pcm_device;
+	/* set operators of PCM device */
+	snd_pcm_set_ops(pcm_playback_num, SNDRV_PCM_STREAM_PLAYBACK,
+			&snd_aw2_playback_ops);
+	/* store PCM device */
+	pcm_device->pcm = pcm_playback_num;
+	/* give base chip pointer to our internal pcm device
+	   structure */
+	pcm_device->chip = chip;
+	/* Give stream number to PCM device */
+	pcm_device->stream_number = NUM_STREAM_PLAYBACK_DIG;
+
+	/* pre-allocation of buffers */
+	/* Preallocate continuous pages. */
+	err = snd_pcm_lib_preallocate_pages_for_all(pcm_playback_num,
+						    SNDRV_DMA_TYPE_DEV,
+						    snd_dma_pci_data
+						    (chip->pci),
+						    64 * 1024, 64 * 1024);
+	if (err)
+		printk(KERN_ERR
+		       "aw2: snd_pcm_lib_preallocate_pages_for_all error "
+		       "(0x%X)\n", err);
+
+
+
+	err = snd_pcm_new(chip->card, "Audiowerk2 capture", 2, 0, 1,
+			  &pcm_capture);
+
+	if (err < 0) {
+		printk(KERN_ERR "aw2: snd_pcm_new error (0x%X)\n", err);
+		return err;
+	}
+
+	/* Creation ok */
+	pcm_device = &chip->device_capture[NUM_STREAM_CAPTURE_ANA];
+
+	/* Set PCM device name */
+	strcpy(pcm_capture->name, "Capture");
+	/* Associate private data to PCM device */
+	pcm_capture->private_data = pcm_device;
+	/* set operators of PCM device */
+	snd_pcm_set_ops(pcm_capture, SNDRV_PCM_STREAM_CAPTURE,
+			&snd_aw2_capture_ops);
+	/* store PCM device */
+	pcm_device->pcm = pcm_capture;
+	/* give base chip pointer to our internal pcm device
+	   structure */
+	pcm_device->chip = chip;
+	/* Give stream number to PCM device */
+	pcm_device->stream_number = NUM_STREAM_CAPTURE_ANA;
+
+	/* pre-allocation of buffers */
+	/* Preallocate continuous pages. */
+	err = snd_pcm_lib_preallocate_pages_for_all(pcm_capture,
+						    SNDRV_DMA_TYPE_DEV,
+						    snd_dma_pci_data
+						    (chip->pci),
+						    64 * 1024, 64 * 1024);
+	if (err)
+		printk(KERN_ERR
+		       "aw2: snd_pcm_lib_preallocate_pages_for_all error "
+		       "(0x%X)\n", err);
+
+
+	/* Create control */
+	err = snd_ctl_add(chip->card, snd_ctl_new1(&aw2_control, chip));
+	if (err < 0) {
+		printk(KERN_ERR "aw2: snd_ctl_add error (0x%X)\n", err);
+		return err;
+	}
+
+	return 0;
+}
+
+static int snd_aw2_control_switch_capture_info(struct snd_kcontrol *kcontrol,
+					       struct snd_ctl_elem_info *uinfo)
+{
+	static char *texts[2] = {
+		"Analog", "Digital"
+	};
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 2;
+	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) {
+		uinfo->value.enumerated.item =
+		    uinfo->value.enumerated.items - 1;
+	}
+	strcpy(uinfo->value.enumerated.name,
+	       texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int snd_aw2_control_switch_capture_get(struct snd_kcontrol *kcontrol,
+					      struct snd_ctl_elem_value
+					      *ucontrol)
+{
+	struct aw2 *chip = snd_kcontrol_chip(kcontrol);
+	if (snd_aw2_saa7146_is_using_digital_input(&chip->saa7146))
+		ucontrol->value.enumerated.item[0] = CTL_ROUTE_DIGITAL;
+	else
+		ucontrol->value.enumerated.item[0] = CTL_ROUTE_ANALOG;
+	return 0;
+}
+
+static int snd_aw2_control_switch_capture_put(struct snd_kcontrol *kcontrol,
+					      struct snd_ctl_elem_value
+					      *ucontrol)
+{
+	struct aw2 *chip = snd_kcontrol_chip(kcontrol);
+	int changed = 0;
+	int is_disgital =
+	    snd_aw2_saa7146_is_using_digital_input(&chip->saa7146);
+
+	if (((ucontrol->value.integer.value[0] == CTL_ROUTE_DIGITAL)
+	     && !is_disgital)
+	    || ((ucontrol->value.integer.value[0] == CTL_ROUTE_ANALOG)
+		&& is_disgital)) {
+		snd_aw2_saa7146_use_digital_input(&chip->saa7146, !is_disgital);
+		changed = 1;
+	}
+	return changed;
+}
diff --git a/sound/pci/aw2/aw2-saa7146.c b/sound/pci/aw2/aw2-saa7146.c
new file mode 100644
index 0000000..6a3891a
--- /dev/null
+++ b/sound/pci/aw2/aw2-saa7146.c
@@ -0,0 +1,465 @@
+/*****************************************************************************
+ *
+ * Copyright (C) 2008 Cedric Bregardis <cedric.bregardis@free.fr> and
+ * Jean-Christian Hassler <jhassler@free.fr>
+ *
+ * This file is part of the Audiowerk2 ALSA driver
+ *
+ * The Audiowerk2 ALSA driver is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2.
+ *
+ * The Audiowerk2 ALSA driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Audiowerk2 ALSA driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+ * USA.
+ *
+ *****************************************************************************/
+
+#define AW2_SAA7146_M
+
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+#include "saa7146.h"
+#include "aw2-saa7146.h"
+
+#include "aw2-tsl.c"
+
+#define WRITEREG(value, addr) writel((value), chip->base_addr + (addr))
+#define READREG(addr) readl(chip->base_addr + (addr))
+
+static struct snd_aw2_saa7146_cb_param
+ arr_substream_it_playback_cb[NB_STREAM_PLAYBACK];
+static struct snd_aw2_saa7146_cb_param
+ arr_substream_it_capture_cb[NB_STREAM_CAPTURE];
+
+static int snd_aw2_saa7146_get_limit(int size);
+
+/* chip-specific destructor */
+int snd_aw2_saa7146_free(struct snd_aw2_saa7146 *chip)
+{
+	/* disable all irqs */
+	WRITEREG(0, IER);
+
+	/* reset saa7146 */
+	WRITEREG((MRST_N << 16), MC1);
+
+	/* Unset base addr */
+	chip->base_addr = NULL;
+
+	return 0;
+}
+
+void snd_aw2_saa7146_setup(struct snd_aw2_saa7146 *chip,
+			   void __iomem *pci_base_addr)
+{
+	/* set PCI burst/threshold
+
+	   Burst length definition
+	   VALUE    BURST LENGTH
+	   000      1 Dword
+	   001      2 Dwords
+	   010      4 Dwords
+	   011      8 Dwords
+	   100      16 Dwords
+	   101      32 Dwords
+	   110      64 Dwords
+	   111      128 Dwords
+
+	   Threshold definition
+	   VALUE    WRITE MODE              READ MODE
+	   00       1 Dword of valid data   1 empty Dword
+	   01       4 Dwords of valid data  4 empty Dwords
+	   10       8 Dwords of valid data  8 empty Dwords
+	   11       16 Dwords of valid data 16 empty Dwords */
+
+	unsigned int acon2;
+	unsigned int acon1 = 0;
+	int i;
+
+	/* Set base addr */
+	chip->base_addr = pci_base_addr;
+
+	/* disable all irqs */
+	WRITEREG(0, IER);
+
+	/* reset saa7146 */
+	WRITEREG((MRST_N << 16), MC1);
+
+	/* enable audio interface */
+#ifdef __BIG_ENDIAN
+	acon1 |= A1_SWAP;
+	acon1 |= A2_SWAP;
+#endif
+	/* WS0_CTRL, WS0_SYNC: input TSL1, I2S */
+
+	/* At initialization WS1 and WS2 are disbaled (configured as input */
+	acon1 |= 0 * WS1_CTRL;
+	acon1 |= 0 * WS2_CTRL;
+
+	/* WS4 is not used. So it must not restart A2.
+	   This is why it is configured as output (force to low) */
+	acon1 |= 3 * WS4_CTRL;
+
+	/* WS3_CTRL, WS3_SYNC: output TSL2, I2S */
+	acon1 |= 2 * WS3_CTRL;
+
+	/* A1 and A2 are active and asynchronous */
+	acon1 |= 3 * AUDIO_MODE;
+	WRITEREG(acon1, ACON1);
+
+	/* The following comes from original windows driver.
+	   It is needed to have a correct behavior of input and output
+	   simultenously, but I don't know why ! */
+	WRITEREG(3 * (BurstA1_in) + 3 * (ThreshA1_in) +
+		 3 * (BurstA1_out) + 3 * (ThreshA1_out) +
+		 3 * (BurstA2_out) + 3 * (ThreshA2_out), PCI_BT_A);
+
+	/* enable audio port pins */
+	WRITEREG((EAP << 16) | EAP, MC1);
+
+	/* enable I2C */
+	WRITEREG((EI2C << 16) | EI2C, MC1);
+	/* enable interrupts */
+	WRITEREG(A1_out | A2_out | A1_in | IIC_S | IIC_E, IER);
+
+	/* audio configuration */
+	acon2 = A2_CLKSRC | BCLK1_OEN;
+	WRITEREG(acon2, ACON2);
+
+	/* By default use analog input */
+	snd_aw2_saa7146_use_digital_input(chip, 0);
+
+	/* TSL setup */
+	for (i = 0; i < 8; ++i) {
+		WRITEREG(tsl1[i], TSL1 + (i * 4));
+		WRITEREG(tsl2[i], TSL2 + (i * 4));
+	}
+
+}
+
+void snd_aw2_saa7146_pcm_init_playback(struct snd_aw2_saa7146 *chip,
+				       int stream_number,
+				       unsigned long dma_addr,
+				       unsigned long period_size,
+				       unsigned long buffer_size)
+{
+	unsigned long dw_page, dw_limit;
+
+	/* Configure DMA for substream
+	   Configuration informations: ALSA has allocated continuous memory
+	   pages. So we don't need to use MMU of saa7146.
+	 */
+
+	/* No MMU -> nothing to do with PageA1, we only configure the limit of
+	   PageAx_out register */
+	/* Disable MMU */
+	dw_page = (0L << 11);
+
+	/* Configure Limit for DMA access.
+	   The limit register defines an address limit, which generates
+	   an interrupt if passed by the actual PCI address pointer.
+	   '0001' means an interrupt will be generated if the lower
+	   6 bits (64 bytes) of the PCI address are zero. '0010'
+	   defines a limit of 128 bytes, '0011' one of 256 bytes, and
+	   so on up to 1 Mbyte defined by '1111'. This interrupt range
+	   can be calculated as follows:
+	   Range = 2^(5 + Limit) bytes.
+	 */
+	dw_limit = snd_aw2_saa7146_get_limit(period_size);
+	dw_page |= (dw_limit << 4);
+
+	if (stream_number == 0) {
+		WRITEREG(dw_page, PageA2_out);
+
+		/* Base address for DMA transfert. */
+		/* This address has been reserved by ALSA. */
+		/* This is a physical address */
+		WRITEREG(dma_addr, BaseA2_out);
+
+		/* Define upper limit for DMA access */
+		WRITEREG(dma_addr + buffer_size, ProtA2_out);
+
+	} else if (stream_number == 1) {
+		WRITEREG(dw_page, PageA1_out);
+
+		/* Base address for DMA transfert. */
+		/* This address has been reserved by ALSA. */
+		/* This is a physical address */
+		WRITEREG(dma_addr, BaseA1_out);
+
+		/* Define upper limit for DMA access */
+		WRITEREG(dma_addr + buffer_size, ProtA1_out);
+	} else {
+		printk(KERN_ERR
+		       "aw2: snd_aw2_saa7146_pcm_init_playback: "
+		       "Substream number is not 0 or 1 -> not managed\n");
+	}
+}
+
+void snd_aw2_saa7146_pcm_init_capture(struct snd_aw2_saa7146 *chip,
+				      int stream_number, unsigned long dma_addr,
+				      unsigned long period_size,
+				      unsigned long buffer_size)
+{
+	unsigned long dw_page, dw_limit;
+
+	/* Configure DMA for substream
+	   Configuration informations: ALSA has allocated continuous memory
+	   pages. So we don't need to use MMU of saa7146.
+	 */
+
+	/* No MMU -> nothing to do with PageA1, we only configure the limit of
+	   PageAx_out register */
+	/* Disable MMU */
+	dw_page = (0L << 11);
+
+	/* Configure Limit for DMA access.
+	   The limit register defines an address limit, which generates
+	   an interrupt if passed by the actual PCI address pointer.
+	   '0001' means an interrupt will be generated if the lower
+	   6 bits (64 bytes) of the PCI address are zero. '0010'
+	   defines a limit of 128 bytes, '0011' one of 256 bytes, and
+	   so on up to 1 Mbyte defined by '1111'. This interrupt range
+	   can be calculated as follows:
+	   Range = 2^(5 + Limit) bytes.
+	 */
+	dw_limit = snd_aw2_saa7146_get_limit(period_size);
+	dw_page |= (dw_limit << 4);
+
+	if (stream_number == 0) {
+		WRITEREG(dw_page, PageA1_in);
+
+		/* Base address for DMA transfert. */
+		/* This address has been reserved by ALSA. */
+		/* This is a physical address */
+		WRITEREG(dma_addr, BaseA1_in);
+
+		/* Define upper limit for DMA access  */
+		WRITEREG(dma_addr + buffer_size, ProtA1_in);
+	} else {
+		printk(KERN_ERR
+		       "aw2: snd_aw2_saa7146_pcm_init_capture: "
+		       "Substream number is not 0 -> not managed\n");
+	}
+}
+
+void snd_aw2_saa7146_define_it_playback_callback(unsigned int stream_number,
+						 snd_aw2_saa7146_it_cb
+						 p_it_callback,
+						 void *p_callback_param)
+{
+	if (stream_number < NB_STREAM_PLAYBACK) {
+		arr_substream_it_playback_cb[stream_number].p_it_callback =
+		    (snd_aw2_saa7146_it_cb) p_it_callback;
+		arr_substream_it_playback_cb[stream_number].p_callback_param =
+		    (void *)p_callback_param;
+	}
+}
+
+void snd_aw2_saa7146_define_it_capture_callback(unsigned int stream_number,
+						snd_aw2_saa7146_it_cb
+						p_it_callback,
+						void *p_callback_param)
+{
+	if (stream_number < NB_STREAM_CAPTURE) {
+		arr_substream_it_capture_cb[stream_number].p_it_callback =
+		    (snd_aw2_saa7146_it_cb) p_it_callback;
+		arr_substream_it_capture_cb[stream_number].p_callback_param =
+		    (void *)p_callback_param;
+	}
+}
+
+void snd_aw2_saa7146_pcm_trigger_start_playback(struct snd_aw2_saa7146 *chip,
+						int stream_number)
+{
+	unsigned int acon1 = 0;
+	/* In aw8 driver, dma transfert is always active. It is
+	   started and stopped in a larger "space" */
+	acon1 = READREG(ACON1);
+	if (stream_number == 0) {
+		WRITEREG((TR_E_A2_OUT << 16) | TR_E_A2_OUT, MC1);
+
+		/* WS2_CTRL, WS2_SYNC: output TSL2, I2S */
+		acon1 |= 2 * WS2_CTRL;
+		WRITEREG(acon1, ACON1);
+
+	} else if (stream_number == 1) {
+		WRITEREG((TR_E_A1_OUT << 16) | TR_E_A1_OUT, MC1);
+
+		/* WS1_CTRL, WS1_SYNC: output TSL1, I2S */
+		acon1 |= 1 * WS1_CTRL;
+		WRITEREG(acon1, ACON1);
+	}
+}
+
+void snd_aw2_saa7146_pcm_trigger_stop_playback(struct snd_aw2_saa7146 *chip,
+					       int stream_number)
+{
+	unsigned int acon1 = 0;
+	acon1 = READREG(ACON1);
+	if (stream_number == 0) {
+		/* WS2_CTRL, WS2_SYNC: output TSL2, I2S */
+		acon1 &= ~(3 * WS2_CTRL);
+		WRITEREG(acon1, ACON1);
+
+		WRITEREG((TR_E_A2_OUT << 16), MC1);
+	} else if (stream_number == 1) {
+		/* WS1_CTRL, WS1_SYNC: output TSL1, I2S */
+		acon1 &= ~(3 * WS1_CTRL);
+		WRITEREG(acon1, ACON1);
+
+		WRITEREG((TR_E_A1_OUT << 16), MC1);
+	}
+}
+
+void snd_aw2_saa7146_pcm_trigger_start_capture(struct snd_aw2_saa7146 *chip,
+					       int stream_number)
+{
+	/* In aw8 driver, dma transfert is always active. It is
+	   started and stopped in a larger "space" */
+	if (stream_number == 0)
+		WRITEREG((TR_E_A1_IN << 16) | TR_E_A1_IN, MC1);
+}
+
+void snd_aw2_saa7146_pcm_trigger_stop_capture(struct snd_aw2_saa7146 *chip,
+					      int stream_number)
+{
+	if (stream_number == 0)
+		WRITEREG((TR_E_A1_IN << 16), MC1);
+}
+
+irqreturn_t snd_aw2_saa7146_interrupt(int irq, void *dev_id)
+{
+	unsigned int isr;
+	unsigned int iicsta;
+	struct snd_aw2_saa7146 *chip = dev_id;
+
+	isr = READREG(ISR);
+	if (!isr)
+		return IRQ_NONE;
+
+	WRITEREG(isr, ISR);
+
+	if (isr & (IIC_S | IIC_E)) {
+		iicsta = READREG(IICSTA);
+		WRITEREG(0x100, IICSTA);
+	}
+
+	if (isr & A1_out) {
+		if (arr_substream_it_playback_cb[1].p_it_callback != NULL) {
+			arr_substream_it_playback_cb[1].
+			    p_it_callback(arr_substream_it_playback_cb[1].
+					  p_callback_param);
+		}
+	}
+	if (isr & A2_out) {
+		if (arr_substream_it_playback_cb[0].p_it_callback != NULL) {
+			arr_substream_it_playback_cb[0].
+			    p_it_callback(arr_substream_it_playback_cb[0].
+					  p_callback_param);
+		}
+
+	}
+	if (isr & A1_in) {
+		if (arr_substream_it_capture_cb[0].p_it_callback != NULL) {
+			arr_substream_it_capture_cb[0].
+			    p_it_callback(arr_substream_it_capture_cb[0].
+					  p_callback_param);
+		}
+	}
+	return IRQ_HANDLED;
+}
+
+unsigned int snd_aw2_saa7146_get_hw_ptr_playback(struct snd_aw2_saa7146 *chip,
+						 int stream_number,
+						 unsigned char *start_addr,
+						 unsigned int buffer_size)
+{
+	long pci_adp = 0;
+	size_t ptr = 0;
+
+	if (stream_number == 0) {
+		pci_adp = READREG(PCI_ADP3);
+		ptr = pci_adp - (long)start_addr;
+
+		if (ptr == buffer_size)
+			ptr = 0;
+	}
+	if (stream_number == 1) {
+		pci_adp = READREG(PCI_ADP1);
+		ptr = pci_adp - (size_t) start_addr;
+
+		if (ptr == buffer_size)
+			ptr = 0;
+	}
+	return ptr;
+}
+
+unsigned int snd_aw2_saa7146_get_hw_ptr_capture(struct snd_aw2_saa7146 *chip,
+						int stream_number,
+						unsigned char *start_addr,
+						unsigned int buffer_size)
+{
+	size_t pci_adp = 0;
+	size_t ptr = 0;
+	if (stream_number == 0) {
+		pci_adp = READREG(PCI_ADP2);
+		ptr = pci_adp - (size_t) start_addr;
+
+		if (ptr == buffer_size)
+			ptr = 0;
+	}
+	return ptr;
+}
+
+void snd_aw2_saa7146_use_digital_input(struct snd_aw2_saa7146 *chip,
+				       int use_digital)
+{
+	/* FIXME: switch between analog and digital input does not always work.
+	   It can produce a kind of white noise. It seams that received data
+	   are inverted sometime (endian inversion). Why ? I don't know, maybe
+	   a problem of synchronization... However for the time being I have
+	   not found the problem. Workaround: switch again (and again) between
+	   digital and analog input until it works. */
+	if (use_digital)
+		WRITEREG(0x40, GPIO_CTRL);
+	else
+		WRITEREG(0x50, GPIO_CTRL);
+}
+
+int snd_aw2_saa7146_is_using_digital_input(struct snd_aw2_saa7146 *chip)
+{
+	unsigned int reg_val = READREG(GPIO_CTRL);
+	if ((reg_val & 0xFF) == 0x40)
+		return 1;
+	else
+		return 0;
+}
+
+
+static int snd_aw2_saa7146_get_limit(int size)
+{
+	int limitsize = 32;
+	int limit = 0;
+	while (limitsize < size) {
+		limitsize *= 2;
+		limit++;
+	}
+	return limit;
+}
diff --git a/sound/pci/aw2/aw2-saa7146.h b/sound/pci/aw2/aw2-saa7146.h
new file mode 100644
index 0000000..5b35e35
--- /dev/null
+++ b/sound/pci/aw2/aw2-saa7146.h
@@ -0,0 +1,105 @@
+/*****************************************************************************
+ *
+ * Copyright (C) 2008 Cedric Bregardis <cedric.bregardis@free.fr> and
+ * Jean-Christian Hassler <jhassler@free.fr>
+ *
+ * This file is part of the Audiowerk2 ALSA driver
+ *
+ * The Audiowerk2 ALSA driver is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2.
+ *
+ * The Audiowerk2 ALSA driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Audiowerk2 ALSA driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+ * USA.
+ *
+ *****************************************************************************/
+
+#ifndef AW2_SAA7146_H
+#define AW2_SAA7146_H
+
+#define NB_STREAM_PLAYBACK 2
+#define NB_STREAM_CAPTURE 1
+
+#define NUM_STREAM_PLAYBACK_ANA 0
+#define NUM_STREAM_PLAYBACK_DIG 1
+
+#define NUM_STREAM_CAPTURE_ANA 0
+
+typedef void (*snd_aw2_saa7146_it_cb) (void *);
+
+struct snd_aw2_saa7146_cb_param {
+	snd_aw2_saa7146_it_cb p_it_callback;
+	void *p_callback_param;
+};
+
+/* definition of the chip-specific record */
+
+struct snd_aw2_saa7146 {
+	void __iomem *base_addr;
+};
+
+extern void snd_aw2_saa7146_setup(struct snd_aw2_saa7146 *chip,
+				  void __iomem *pci_base_addr);
+extern int snd_aw2_saa7146_free(struct snd_aw2_saa7146 *chip);
+
+extern void snd_aw2_saa7146_pcm_init_playback(struct snd_aw2_saa7146 *chip,
+					      int stream_number,
+					      unsigned long dma_addr,
+					      unsigned long period_size,
+					      unsigned long buffer_size);
+extern void snd_aw2_saa7146_pcm_init_capture(struct snd_aw2_saa7146 *chip,
+					     int stream_number,
+					     unsigned long dma_addr,
+					     unsigned long period_size,
+					     unsigned long buffer_size);
+extern void snd_aw2_saa7146_define_it_playback_callback(unsigned int
+							stream_number,
+							snd_aw2_saa7146_it_cb
+							p_it_callback,
+							void *p_callback_param);
+extern void snd_aw2_saa7146_define_it_capture_callback(unsigned int
+						       stream_number,
+						       snd_aw2_saa7146_it_cb
+						       p_it_callback,
+						       void *p_callback_param);
+extern void snd_aw2_saa7146_pcm_trigger_start_capture(struct snd_aw2_saa7146
+						      *chip, int stream_number);
+extern void snd_aw2_saa7146_pcm_trigger_stop_capture(struct snd_aw2_saa7146
+						     *chip, int stream_number);
+
+extern void snd_aw2_saa7146_pcm_trigger_start_playback(struct snd_aw2_saa7146
+						       *chip,
+						       int stream_number);
+extern void snd_aw2_saa7146_pcm_trigger_stop_playback(struct snd_aw2_saa7146
+						      *chip, int stream_number);
+
+extern irqreturn_t snd_aw2_saa7146_interrupt(int irq, void *dev_id);
+extern unsigned int snd_aw2_saa7146_get_hw_ptr_playback(struct snd_aw2_saa7146
+							*chip,
+							int stream_number,
+							unsigned char
+							*start_addr,
+							unsigned int
+							buffer_size);
+extern unsigned int snd_aw2_saa7146_get_hw_ptr_capture(struct snd_aw2_saa7146
+						       *chip,
+						       int stream_number,
+						       unsigned char
+						       *start_addr,
+						       unsigned int
+						       buffer_size);
+
+extern void snd_aw2_saa7146_use_digital_input(struct snd_aw2_saa7146 *chip,
+					      int use_digital);
+
+extern int snd_aw2_saa7146_is_using_digital_input(struct snd_aw2_saa7146
+						  *chip);
+
+#endif
diff --git a/sound/pci/aw2/aw2-tsl.c b/sound/pci/aw2/aw2-tsl.c
new file mode 100644
index 0000000..459b031
--- /dev/null
+++ b/sound/pci/aw2/aw2-tsl.c
@@ -0,0 +1,110 @@
+/*****************************************************************************
+ *
+ * Copyright (C) 2008 Cedric Bregardis <cedric.bregardis@free.fr> and
+ * Jean-Christian Hassler <jhassler@free.fr>
+ * Copyright 1998 Emagic Soft- und Hardware GmbH
+ * Copyright 2002 Martijn Sipkema
+ *
+ * This file is part of the Audiowerk2 ALSA driver
+ *
+ * The Audiowerk2 ALSA driver is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2.
+ *
+ * The Audiowerk2 ALSA driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Audiowerk2 ALSA driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+ * USA.
+ *
+ *****************************************************************************/
+
+#define TSL_WS0		(1UL << 31)
+#define	TSL_WS1		(1UL << 30)
+#define	TSL_WS2		(1UL << 29)
+#define TSL_WS3		(1UL << 28)
+#define TSL_WS4		(1UL << 27)
+#define	TSL_DIS_A1	(1UL << 24)
+#define TSL_SDW_A1	(1UL << 23)
+#define TSL_SIB_A1	(1UL << 22)
+#define TSL_SF_A1	(1UL << 21)
+#define	TSL_LF_A1	(1UL << 20)
+#define TSL_BSEL_A1	(1UL << 17)
+#define TSL_DOD_A1	(1UL << 15)
+#define TSL_LOW_A1	(1UL << 14)
+#define TSL_DIS_A2	(1UL << 11)
+#define TSL_SDW_A2	(1UL << 10)
+#define TSL_SIB_A2	(1UL << 9)
+#define TSL_SF_A2	(1UL << 8)
+#define TSL_LF_A2	(1UL << 7)
+#define TSL_BSEL_A2	(1UL << 4)
+#define TSL_DOD_A2	(1UL << 2)
+#define TSL_LOW_A2	(1UL << 1)
+#define TSL_EOS		(1UL << 0)
+
+    /* Audiowerk8 hardware setup: */
+    /*      WS0, SD4, TSL1  - Analog/ digital in */
+    /*      WS1, SD0, TSL1  - Analog out #1, digital out */
+    /*      WS2, SD2, TSL1  - Analog out #2 */
+    /*      WS3, SD1, TSL2  - Analog out #3 */
+    /*      WS4, SD3, TSL2  - Analog out #4 */
+
+    /* Audiowerk8 timing: */
+    /*      Timeslot:     | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ... */
+
+    /*      A1_INPUT: */
+    /*      SD4:          <_ADC-L_>-------<_ADC-R_>-------< */
+    /*      WS0:          _______________/---------------\_ */
+
+    /*      A1_OUTPUT: */
+    /*      SD0:          <_1-L___>-------<_1-R___>-------< */
+    /*      WS1:          _______________/---------------\_ */
+    /*      SD2:          >-------<_2-L___>-------<_2-R___> */
+    /*      WS2:          -------\_______________/--------- */
+
+    /*      A2_OUTPUT: */
+    /*      SD1:          <_3-L___>-------<_3-R___>-------< */
+    /*      WS3:          _______________/---------------\_ */
+    /*      SD3:          >-------<_4-L___>-------<_4-R___> */
+    /*      WS4:          -------\_______________/--------- */
+
+static int tsl1[8] = {
+	1 * TSL_SDW_A1 | 3 * TSL_BSEL_A1 |
+	0 * TSL_DIS_A1 | 0 * TSL_DOD_A1 | TSL_LF_A1,
+
+	1 * TSL_SDW_A1 | 2 * TSL_BSEL_A1 |
+	0 * TSL_DIS_A1 | 0 * TSL_DOD_A1,
+
+	0 * TSL_SDW_A1 | 3 * TSL_BSEL_A1 |
+	0 * TSL_DIS_A1 | 0 * TSL_DOD_A1,
+
+	0 * TSL_SDW_A1 | 2 * TSL_BSEL_A1 |
+	0 * TSL_DIS_A1 | 0 * TSL_DOD_A1,
+
+	1 * TSL_SDW_A1 | 1 * TSL_BSEL_A1 |
+	0 * TSL_DIS_A1 | 0 * TSL_DOD_A1 | TSL_WS1 | TSL_WS0,
+
+	1 * TSL_SDW_A1 | 0 * TSL_BSEL_A1 |
+	0 * TSL_DIS_A1 | 0 * TSL_DOD_A1 | TSL_WS1 | TSL_WS0,
+
+	0 * TSL_SDW_A1 | 1 * TSL_BSEL_A1 |
+	0 * TSL_DIS_A1 | 0 * TSL_DOD_A1 | TSL_WS1 | TSL_WS0,
+
+	0 * TSL_SDW_A1 | 0 * TSL_BSEL_A1 | 0 * TSL_DIS_A1 |
+	0 * TSL_DOD_A1 | TSL_WS1 | TSL_WS0 | TSL_SF_A1 | TSL_EOS,
+};
+
+static int tsl2[8] = {
+	0 * TSL_SDW_A2 | 3 * TSL_BSEL_A2 | 2 * TSL_DOD_A2 | TSL_LF_A2,
+	0 * TSL_SDW_A2 | 2 * TSL_BSEL_A2 | 2 * TSL_DOD_A2,
+	0 * TSL_SDW_A2 | 3 * TSL_BSEL_A2 | 2 * TSL_DOD_A2,
+	0 * TSL_SDW_A2 | 2 * TSL_BSEL_A2 | 2 * TSL_DOD_A2,
+	0 * TSL_SDW_A2 | 1 * TSL_BSEL_A2 | 2 * TSL_DOD_A2 | TSL_WS2,
+	0 * TSL_SDW_A2 | 0 * TSL_BSEL_A2 | 2 * TSL_DOD_A2 | TSL_WS2,
+	0 * TSL_SDW_A2 | 1 * TSL_BSEL_A2 | 2 * TSL_DOD_A2 | TSL_WS2,
+	0 * TSL_SDW_A2 | 0 * TSL_BSEL_A2 | 2 * TSL_DOD_A2 | TSL_WS2 | TSL_EOS
+};
diff --git a/sound/pci/aw2/saa7146.h b/sound/pci/aw2/saa7146.h
new file mode 100644
index 0000000..ce0ab5f
--- /dev/null
+++ b/sound/pci/aw2/saa7146.h
@@ -0,0 +1,168 @@
+/*****************************************************************************
+ *
+ * Copyright (C) 2008 Cedric Bregardis <cedric.bregardis@free.fr> and
+ * Jean-Christian Hassler <jhassler@free.fr>
+ *
+ * This file is part of the Audiowerk2 ALSA driver
+ *
+ * The Audiowerk2 ALSA driver is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2.
+ *
+ * The Audiowerk2 ALSA driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Audiowerk2 ALSA driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+ * USA.
+ *
+ *****************************************************************************/
+
+/* SAA7146 registers */
+#define PCI_BT_A	0x4C
+#define IICTFR		0x8C
+#define IICSTA		0x90
+#define BaseA1_in	0x94
+#define ProtA1_in	0x98
+#define PageA1_in	0x9C
+#define BaseA1_out	0xA0
+#define ProtA1_out	0xA4
+#define PageA1_out	0xA8
+#define BaseA2_in	0xAC
+#define ProtA2_in	0xB0
+#define PageA2_in	0xB4
+#define BaseA2_out	0xB8
+#define ProtA2_out	0xBC
+#define PageA2_out	0xC0
+#define IER		0xDC
+#define GPIO_CTRL	0xE0
+#define ACON1		0xF4
+#define ACON2		0xF8
+#define MC1		0xFC
+#define MC2		0x100
+#define ISR		0x10C
+#define PSR		0x110
+#define SSR		0x114
+#define PCI_ADP1	0x12C
+#define PCI_ADP2	0x130
+#define PCI_ADP3	0x134
+#define PCI_ADP4	0x138
+#define LEVEL_REP	0x140
+#define FB_BUFFER1	0x144
+#define FB_BUFFER2	0x148
+#define TSL1		0x180
+#define TSL2		0x1C0
+
+#define ME	(1UL << 11)
+#define LIMIT	(1UL << 4)
+#define PV	(1UL << 3)
+
+/* PSR/ISR/IER */
+#define PPEF		(1UL << 31)
+#define PABO		(1UL << 30)
+#define IIC_S		(1UL << 17)
+#define IIC_E		(1UL << 16)
+#define A2_in		(1UL << 15)
+#define A2_out		(1UL << 14)
+#define A1_in		(1UL << 13)
+#define A1_out		(1UL << 12)
+#define AFOU		(1UL << 11)
+#define PIN3		(1UL << 6)
+#define PIN2		(1UL << 5)
+#define PIN1		(1UL << 4)
+#define PIN0		(1UL << 3)
+#define ECS		(1UL << 2)
+#define EC3S		(1UL << 1)
+#define EC0S		(1UL << 0)
+
+/* SSR */
+#define PRQ		(1UL << 31)
+#define PMA		(1UL << 30)
+#define IIC_EA		(1UL << 21)
+#define IIC_EW		(1UL << 20)
+#define IIC_ER		(1UL << 19)
+#define IIC_EL		(1UL << 18)
+#define IIC_EF		(1UL << 17)
+#define AF2_in		(1UL << 10)
+#define AF2_out		(1UL << 9)
+#define AF1_in		(1UL << 8)
+#define AF1_out		(1UL << 7)
+#define EC5S		(1UL << 3)
+#define EC4S		(1UL << 2)
+#define EC2S		(1UL << 1)
+#define EC1S		(1UL << 0)
+
+/* PCI_BT_A */
+#define BurstA1_in	(1UL << 26)
+#define ThreshA1_in	(1UL << 24)
+#define BurstA1_out	(1UL << 18)
+#define ThreshA1_out	(1UL << 16)
+#define BurstA2_in	(1UL << 10)
+#define ThreshA2_in	(1UL << 8)
+#define BurstA2_out	(1UL << 2)
+#define ThreshA2_out	(1UL << 0)
+
+/* MC1 */
+#define MRST_N		(1UL << 15)
+#define EAP		(1UL << 9)
+#define EI2C		(1UL << 8)
+#define TR_E_A2_OUT	(1UL << 3)
+#define TR_E_A2_IN	(1UL << 2)
+#define TR_E_A1_OUT	(1UL << 1)
+#define TR_E_A1_IN	(1UL << 0)
+
+/* MC2 */
+#define UPLD_IIC	(1UL << 0)
+
+/* ACON1 */
+#define AUDIO_MODE	(1UL << 29)
+#define MAXLEVEL	(1UL << 22)
+#define A1_SWAP		(1UL << 21)
+#define A2_SWAP		(1UL << 20)
+#define WS0_CTRL	(1UL << 18)
+#define WS0_SYNC	(1UL << 16)
+#define WS1_CTRL	(1UL << 14)
+#define WS1_SYNC	(1UL << 12)
+#define WS2_CTRL	(1UL << 10)
+#define WS2_SYNC	(1UL << 8)
+#define WS3_CTRL	(1UL << 6)
+#define WS3_SYNC	(1UL << 4)
+#define WS4_CTRL	(1UL << 2)
+#define WS4_SYNC	(1UL << 0)
+
+/* ACON2 */
+#define A1_CLKSRC	(1UL << 27)
+#define A2_CLKSRC	(1UL << 22)
+#define INVERT_BCLK1	(1UL << 21)
+#define INVERT_BCLK2	(1UL << 20)
+#define BCLK1_OEN	(1UL << 19)
+#define BCLK2_OEN	(1UL << 18)
+
+/* IICSTA */
+#define IICCC		(1UL << 8)
+#define ABORT		(1UL << 7)
+#define SPERR		(1UL << 6)
+#define APERR		(1UL << 5)
+#define DTERR		(1UL << 4)
+#define DRERR		(1UL << 3)
+#define AL		(1UL << 2)
+#define ERR		(1UL << 1)
+#define BUSY		(1UL << 0)
+
+/* IICTFR */
+#define BYTE2		(1UL << 24)
+#define BYTE1		(1UL << 16)
+#define BYTE0		(1UL << 8)
+#define ATRR2		(1UL << 6)
+#define ATRR1		(1UL << 4)
+#define ATRR0		(1UL << 2)
+#define ERR		(1UL << 1)
+#define BUSY		(1UL << 0)
+
+#define START	3
+#define CONT	2
+#define STOP	1
+#define NOP	0
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index 4e71a55..5f63af6 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -157,8 +157,8 @@
 
 #if DEBUG_CALLS
 #define snd_azf3328_dbgcalls(format, args...) printk(format, ##args)
-#define snd_azf3328_dbgcallenter() printk(KERN_ERR "--> %s\n", __FUNCTION__)
-#define snd_azf3328_dbgcallleave() printk(KERN_ERR "<-- %s\n", __FUNCTION__)
+#define snd_azf3328_dbgcallenter() printk(KERN_ERR "--> %s\n", __func__)
+#define snd_azf3328_dbgcallleave() printk(KERN_ERR "<-- %s\n", __func__)
 #else
 #define snd_azf3328_dbgcalls(format, args...)
 #define snd_azf3328_dbgcallenter()
@@ -1514,7 +1514,8 @@
 	/* well, at least we know how to disable the timer IRQ */
 	snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x00);
 
-        synchronize_irq(chip->irq);
+	if (chip->irq >= 0)
+        	synchronize_irq(chip->irq);
 __end_hw:
 	snd_azf3328_free_joystick(chip);
         if (chip->irq >= 0)
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index 176e0f0..ecbe79b 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -435,22 +435,22 @@
 static void snd_ca0106_intr_enable(struct snd_ca0106 *emu, unsigned int intrenb)
 {
 	unsigned long flags;
-	unsigned int enable;
-  
+	unsigned int intr_enable;
+
 	spin_lock_irqsave(&emu->emu_lock, flags);
-	enable = inl(emu->port + INTE) | intrenb;
-	outl(enable, emu->port + INTE);
+	intr_enable = inl(emu->port + INTE) | intrenb;
+	outl(intr_enable, emu->port + INTE);
 	spin_unlock_irqrestore(&emu->emu_lock, flags);
 }
 
 static void snd_ca0106_intr_disable(struct snd_ca0106 *emu, unsigned int intrenb)
 {
 	unsigned long flags;
-	unsigned int enable;
-  
+	unsigned int intr_enable;
+
 	spin_lock_irqsave(&emu->emu_lock, flags);
-	enable = inl(emu->port + INTE) & ~intrenb;
-	outl(enable, emu->port + INTE);
+	intr_enable = inl(emu->port + INTE) & ~intrenb;
+	outl(intr_enable, emu->port + INTE);
 	spin_unlock_irqrestore(&emu->emu_lock, flags);
 }
 
@@ -1114,6 +1114,8 @@
 		 * So we can fix: snd-malloc: Memory leak?  pages not freed = 8
 		 */
 	}
+	if (chip->irq >= 0)
+		free_irq(chip->irq, chip);
 	// release the data
 #if 1
 	if (chip->buffer.area)
@@ -1123,9 +1125,6 @@
 	// release the i/o port
 	release_and_free_resource(chip->res_port);
 
-	// release the irq
-	if (chip->irq >= 0)
-		free_irq(chip->irq, chip);
 	pci_disable_device(chip->pci);
 	kfree(chip);
 	return 0;
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c
index af73686..3025ed1 100644
--- a/sound/pci/ca0106/ca0106_mixer.c
+++ b/sound/pci/ca0106/ca0106_mixer.c
@@ -650,19 +650,55 @@
 
 #define ADD_CTLS(emu, ctls)						\
 	do {								\
-		int i, err;						\
+		int i, _err;						\
 		for (i = 0; i < ARRAY_SIZE(ctls); i++) {		\
-			err = snd_ctl_add(card, snd_ctl_new1(&ctls[i], emu)); \
-			if (err < 0)					\
-				return err;				\
+			_err = snd_ctl_add(card, snd_ctl_new1(&ctls[i], emu)); \
+			if (_err < 0)					\
+				return _err;				\
 		}							\
 	} while (0)
 
+static __devinitdata
+DECLARE_TLV_DB_SCALE(snd_ca0106_master_db_scale, -6375, 50, 1);
+
+static char *slave_vols[] __devinitdata = {
+	"Analog Front Playback Volume",
+        "Analog Rear Playback Volume",
+	"Analog Center/LFE Playback Volume",
+        "Analog Side Playback Volume",
+        "IEC958 Front Playback Volume",
+	"IEC958 Rear Playback Volume",
+	"IEC958 Center/LFE Playback Volume",
+	"IEC958 Unknown Playback Volume",
+        "CAPTURE feedback Playback Volume",
+	NULL
+};
+
+static char *slave_sws[] __devinitdata = {
+	"Analog Front Playback Switch",
+	"Analog Rear Playback Switch",
+	"Analog Center/LFE Playback Switch",
+	"Analog Side Playback Switch",
+	"IEC958 Playback Switch",
+	NULL
+};
+
+static void __devinit add_slaves(struct snd_card *card,
+				 struct snd_kcontrol *master, char **list)
+{
+	for (; *list; list++) {
+		struct snd_kcontrol *slave = ctl_find(card, *list);
+		if (slave)
+			snd_ctl_add_slave(master, slave);
+	}
+}
+
 int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
 {
 	int err;
         struct snd_card *card = emu->card;
 	char **c;
+	struct snd_kcontrol *vmaster;
 	static char *ca0106_remove_ctls[] = {
 		"Master Mono Playback Switch",
 		"Master Mono Playback Volume",
@@ -719,6 +755,21 @@
 	}
 	if (emu->details->spi_dac == 1)
 		ADD_CTLS(emu, snd_ca0106_volume_spi_dac_ctls);
+
+	/* Create virtual master controls */
+	vmaster = snd_ctl_make_virtual_master("Master Playback Volume",
+					      snd_ca0106_master_db_scale);
+	if (!vmaster)
+		return -ENOMEM;
+	add_slaves(card, vmaster, slave_vols);
+
+	if (emu->details->spi_dac == 1) {
+		vmaster = snd_ctl_make_virtual_master("Master Playback Switch",
+						      NULL);
+		if (!vmaster)
+			return -ENOMEM;
+		add_slaves(card, vmaster, slave_sws);
+	}
         return 0;
 }
 
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c
index 135f308..9971b5b 100644
--- a/sound/pci/cmipci.c
+++ b/sound/pci/cmipci.c
@@ -2744,12 +2744,13 @@
 	}
 
 	for (idx = 0; idx < CM_SAVED_MIXERS; idx++) {
-		struct snd_ctl_elem_id id;
+		struct snd_ctl_elem_id elem_id;
 		struct snd_kcontrol *ctl;
-		memset(&id, 0, sizeof(id));
-		id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-		strcpy(id.name, cm_saved_mixer[idx].name);
-		if ((ctl = snd_ctl_find_id(cm->card, &id)) != NULL)
+		memset(&elem_id, 0, sizeof(elem_id));
+		elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+		strcpy(elem_id.name, cm_saved_mixer[idx].name);
+		ctl = snd_ctl_find_id(cm->card, &elem_id);
+		if (ctl)
 			cm->mixer_res_ctl[idx] = ctl;
 	}
 
@@ -2932,8 +2933,6 @@
 		/* reset mixer */
 		snd_cmipci_mixer_write(cm, 0, 0);
 
-		synchronize_irq(cm->irq);
-
 		free_irq(cm->irq, cm);
 	}
 
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
index 87ddffc..e214e56 100644
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -2772,6 +2772,9 @@
 	if (chip->irq >= 0)
 		free_irq(chip->irq, chip);
 
+	if (chip->active_ctrl)
+		chip->active_ctrl(chip, -chip->amplifier);
+
 	for (idx = 0; idx < 5; idx++) {
 		struct snd_cs46xx_region *region = &chip->region.idx[idx];
 		if (region->remap_addr)
@@ -2779,9 +2782,6 @@
 		release_and_free_resource(region->resource);
 	}
 
-	if (chip->active_ctrl)
-		chip->active_ctrl(chip, -chip->amplifier);
-	
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
 	if (chip->dsp_spos_instance) {
 		cs46xx_dsp_spos_destroy(chip);
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c
index 90ec090..e16dc92 100644
--- a/sound/pci/echoaudio/echoaudio.c
+++ b/sound/pci/echoaudio/echoaudio.c
@@ -1852,15 +1852,16 @@
 static int snd_echo_free(struct echoaudio *chip)
 {
 	DE_INIT(("Stop DSP...\n"));
-	if (chip->comm_page) {
+	if (chip->comm_page)
 		rest_in_peace(chip);
-		snd_dma_free_pages(&chip->commpage_dma_buf);
-	}
 	DE_INIT(("Stopped.\n"));
 
 	if (chip->irq >= 0)
 		free_irq(chip->irq, chip);
 
+	if (chip->comm_page)
+		snd_dma_free_pages(&chip->commpage_dma_buf);
+
 	if (chip->dsp_registers)
 		iounmap(chip->dsp_registers);
 
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index 9a9b977..abde5b9 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -1249,11 +1249,6 @@
 	if (emu->port) {	/* avoid access to already used hardware */
 	       	snd_emu10k1_fx8010_tram_setup(emu, 0);
 		snd_emu10k1_done(emu);
-		/* remove reserved page */
-		if (emu->reserved_page) {
-			snd_emu10k1_synth_free(emu, (struct snd_util_memblk *)emu->reserved_page);
-			emu->reserved_page = NULL;
-		}
 		snd_emu10k1_free_efx(emu);
        	}
 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1010) {
@@ -1262,6 +1257,14 @@
 	}
 	if (emu->emu1010.firmware_thread)
 		kthread_stop(emu->emu1010.firmware_thread);
+	if (emu->irq >= 0)
+		free_irq(emu->irq, emu);
+	/* remove reserved page */
+	if (emu->reserved_page) {
+		snd_emu10k1_synth_free(emu,
+			(struct snd_util_memblk *)emu->reserved_page);
+		emu->reserved_page = NULL;
+	}
 	if (emu->memhdr)
 		snd_util_memhdr_free(emu->memhdr);
 	if (emu->silent_page.area)
@@ -1273,8 +1276,6 @@
 #ifdef CONFIG_PM
 	free_pm_buffer(emu);
 #endif
-	if (emu->irq >= 0)
-		free_irq(emu->irq, emu);
 	if (emu->port)
 		pci_release_regions(emu->pci);
 	if (emu->card_capabilities->ca0151_chip) /* P16V */	
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index 5512abd..491a4a5 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -327,22 +327,22 @@
 static void snd_emu10k1x_intr_enable(struct emu10k1x *emu, unsigned int intrenb)
 {
 	unsigned long flags;
-	unsigned int enable;
-  
+	unsigned int intr_enable;
+
 	spin_lock_irqsave(&emu->emu_lock, flags);
-	enable = inl(emu->port + INTE) | intrenb;
-	outl(enable, emu->port + INTE);
+	intr_enable = inl(emu->port + INTE) | intrenb;
+	outl(intr_enable, emu->port + INTE);
 	spin_unlock_irqrestore(&emu->emu_lock, flags);
 }
 
 static void snd_emu10k1x_intr_disable(struct emu10k1x *emu, unsigned int intrenb)
 {
 	unsigned long flags;
-	unsigned int enable;
-  
+	unsigned int intr_enable;
+
 	spin_lock_irqsave(&emu->emu_lock, flags);
-	enable = inl(emu->port + INTE) & ~intrenb;
-	outl(enable, emu->port + INTE);
+	intr_enable = inl(emu->port + INTE) & ~intrenb;
+	outl(intr_enable, emu->port + INTE);
 	spin_unlock_irqrestore(&emu->emu_lock, flags);
 }
 
@@ -754,13 +754,13 @@
 	// disable audio
 	outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG);
 
-	// release the i/o port
-	release_and_free_resource(chip->res_port);
-
-	// release the irq
+	/* release the irq */
 	if (chip->irq >= 0)
 		free_irq(chip->irq, chip);
 
+	// release the i/o port
+	release_and_free_resource(chip->res_port);
+
 	// release the DMA
 	if (chip->dma_buffer.area) {
 		snd_dma_free_pages(&chip->dma_buffer);
@@ -795,9 +795,9 @@
 
 	// capture interrupt
 	if (status & (IPR_CAP_0_LOOP | IPR_CAP_0_HALF_LOOP)) {
-		struct emu10k1x_voice *pvoice = &chip->capture_voice;
-		if (pvoice->use)
-			snd_emu10k1x_pcm_interrupt(chip, pvoice);
+		struct emu10k1x_voice *cap_voice = &chip->capture_voice;
+		if (cap_voice->use)
+			snd_emu10k1x_pcm_interrupt(chip, cap_voice);
 		else
 			snd_emu10k1x_intr_disable(chip, 
 						  INTE_CAP_0_LOOP |
diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c
index f3caa3f..216f974 100644
--- a/sound/pci/emu10k1/emuproc.c
+++ b/sound/pci/emu10k1/emuproc.c
@@ -412,7 +412,7 @@
 				     struct snd_info_buffer *buffer)
 {
 	struct snd_emu10k1 *emu = entry->private_data;
-	int value;
+	u32 value;
 	unsigned long flags;
 	int i;
 	snd_iprintf(buffer, "EMU1010 Registers:\n\n");
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index 72d85a5..fbf1124 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -1635,20 +1635,20 @@
 	if (has_spdif > 0 ||
 	    (!has_spdif && es1371_quirk_lookup(ensoniq, es1371_spdif_present))) {
 		struct snd_kcontrol *kctl;
-		int i, index = 0;
+		int i, is_spdif = 0;
 
 		ensoniq->spdif_default = ensoniq->spdif_stream =
 			SNDRV_PCM_DEFAULT_CON_SPDIF;
 		outl(ensoniq->spdif_default, ES_REG(ensoniq, CHANNEL_STATUS));
 
 		if (ensoniq->u.es1371.ac97->ext_id & AC97_EI_SPDIF)
-			index++;
+			is_spdif++;
 
 		for (i = 0; i < ARRAY_SIZE(snd_es1371_mixer_spdif); i++) {
 			kctl = snd_ctl_new1(&snd_es1371_mixer_spdif[i], ensoniq);
 			if (!kctl)
 				return -ENOMEM;
-			kctl->id.index = index;
+			kctl->id.index = is_spdif;
 			err = snd_ctl_add(card, kctl);
 			if (err < 0)
 				return err;
@@ -1910,7 +1910,8 @@
 	outl(0, ES_REG(ensoniq, CONTROL));	/* switch everything off */
 	outl(0, ES_REG(ensoniq, SERIAL));	/* clear serial interface */
 #endif
-	synchronize_irq(ensoniq->irq);
+	if (ensoniq->irq >= 0)
+		synchronize_irq(ensoniq->irq);
 	pci_set_power_state(ensoniq->pci, 3);
       __hw_end:
 #ifdef CHIP1370
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c
index 1a314fa..84fac1f 100644
--- a/sound/pci/es1938.c
+++ b/sound/pci/es1938.c
@@ -1488,7 +1488,6 @@
 
 	outb(0x00, SLIO_REG(chip, IRQCONTROL)); /* disable irqs */
 	if (chip->irq >= 0) {
-		synchronize_irq(chip->irq);
 		free_irq(chip->irq, chip);
 		chip->irq = -1;
 	}
@@ -1578,10 +1577,8 @@
 
 	snd_es1938_free_gameport(chip);
 
-	if (chip->irq >= 0) {
-		synchronize_irq(chip->irq);
+	if (chip->irq >= 0)
 		free_irq(chip->irq, chip);
-	}
 	pci_release_regions(chip->pci);
 	pci_disable_device(chip->pci);
 	kfree(chip);
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index 7d911a1..1bf298d 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -1827,6 +1827,22 @@
 
 	return 0;
 }
+/*
+ * suppress jitter on some maestros when playing stereo
+ */
+static void snd_es1968_suppress_jitter(struct es1968 *chip, struct esschan *es)
+{
+	unsigned int cp1;
+	unsigned int cp2;
+	unsigned int diff;
+
+	cp1 = __apu_get_register(chip, 0, 5);
+	cp2 = __apu_get_register(chip, 1, 5);
+	diff = (cp1 > cp2 ? cp1 - cp2 : cp2 - cp1);
+
+	if (diff > 1)
+		__maestro_write(chip, IDR0_DATA_PORT, cp1);
+}
 
 /*
  * update pointer
@@ -1948,8 +1964,11 @@
 		struct esschan *es;
 		spin_lock(&chip->substream_lock);
 		list_for_each_entry(es, &chip->substream_list, list) {
-			if (es->running)
+			if (es->running) {
 				snd_es1968_update_pcm(chip, es);
+				if (es->fmt & ESS_FMT_STEREO)
+					snd_es1968_suppress_jitter(chip, es);
+			}
 		}
 		spin_unlock(&chip->substream_lock);
 		if (chip->in_measurement) {
@@ -1972,7 +1991,7 @@
 {
 	struct snd_ac97_bus *pbus;
 	struct snd_ac97_template ac97;
-	struct snd_ctl_elem_id id;
+	struct snd_ctl_elem_id elem_id;
 	int err;
 	static struct snd_ac97_bus_ops ops = {
 		.write = snd_es1968_ac97_write,
@@ -1989,14 +2008,14 @@
 		return err;
 
 	/* attach master switch / volumes for h/w volume control */
-	memset(&id, 0, sizeof(id));
-	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-	strcpy(id.name, "Master Playback Switch");
-	chip->master_switch = snd_ctl_find_id(chip->card, &id);
-	memset(&id, 0, sizeof(id));
-	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-	strcpy(id.name, "Master Playback Volume");
-	chip->master_volume = snd_ctl_find_id(chip->card, &id);
+	memset(&elem_id, 0, sizeof(elem_id));
+	elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	strcpy(elem_id.name, "Master Playback Switch");
+	chip->master_switch = snd_ctl_find_id(chip->card, &elem_id);
+	memset(&elem_id, 0, sizeof(elem_id));
+	elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	strcpy(elem_id.name, "Master Playback Volume");
+	chip->master_volume = snd_ctl_find_id(chip->card, &elem_id);
 
 	return 0;
 }
@@ -2456,7 +2475,8 @@
 static int snd_es1968_free(struct es1968 *chip)
 {
 	if (chip->io_port) {
-		synchronize_irq(chip->irq);
+		if (chip->irq >= 0)
+			synchronize_irq(chip->irq);
 		outw(1, chip->io_port + 0x04); /* clear WP interrupts */
 		outw(0, chip->io_port + ESM_PORT_HOST_IRQ); /* disable IRQ */
 	}
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index 4c300e6..c129f9e 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -1285,7 +1285,6 @@
 
 static int snd_fm801_chip_init(struct fm801 *chip, int resume)
 {
-	int id;
 	unsigned short cmdw;
 
 	if (chip->tea575x_tuner & 0x0010)
@@ -1310,13 +1309,14 @@
 		} else {
 			/* my card has the secondary codec */
 			/* at address #3, so the loop is inverted */
-			for (id = 3; id > 0; id--) {
-				if (! wait_for_codec(chip, id, AC97_VENDOR_ID1,
+			int i;
+			for (i = 3; i > 0; i--) {
+				if (!wait_for_codec(chip, i, AC97_VENDOR_ID1,
 						     msecs_to_jiffies(50))) {
 					cmdw = inw(FM801_REG(chip, AC97_DATA));
 					if (cmdw != 0xffff && cmdw != 0) {
 						chip->secondary = 1;
-						chip->secondary_addr = id;
+						chip->secondary_addr = i;
 						break;
 					}
 				}
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index 9e0d8a1..ab0c726 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -2,7 +2,7 @@
 # since snd-hda-intel is the only driver using hda-codec,
 # merge it into a single module although it was originally
 # designed to be individual modules
-snd-hda-intel-y += hda_codec.o vmaster.o
+snd-hda-intel-y += hda_codec.o
 snd-hda-intel-$(CONFIG_PROC_FS) += hda_proc.o
 snd-hda-intel-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
 snd-hda-intel-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 37c4139..a6be6e3 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -31,6 +31,7 @@
 #include <sound/initval.h>
 #include "hda_local.h"
 #include <sound/hda_hwdep.h>
+#include "hda_patch.h"	/* codec presets */
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 /* define this option here to hide as static */
@@ -51,21 +52,50 @@
 
 /* codec vendor labels */
 static struct hda_vendor_id hda_vendor_ids[] = {
-	{ 0x10ec, "Realtek" },
+	{ 0x1002, "ATI" },
 	{ 0x1057, "Motorola" },
+	{ 0x1095, "Silicon Image" },
+	{ 0x10ec, "Realtek" },
 	{ 0x1106, "VIA" },
 	{ 0x111d, "IDT" },
+	{ 0x11c1, "LSI" },
 	{ 0x11d4, "Analog Devices" },
 	{ 0x13f6, "C-Media" },
 	{ 0x14f1, "Conexant" },
+	{ 0x17e8, "Chrontel" },
+	{ 0x1854, "LG" },
 	{ 0x434d, "C-Media" },
 	{ 0x8384, "SigmaTel" },
 	{} /* terminator */
 };
 
-/* codec presets */
-#include "hda_patch.h"
-
+static const struct hda_codec_preset *hda_preset_tables[] = {
+#ifdef CONFIG_SND_HDA_CODEC_REALTEK
+	snd_hda_preset_realtek,
+#endif
+#ifdef CONFIG_SND_HDA_CODEC_CMEDIA
+	snd_hda_preset_cmedia,
+#endif
+#ifdef CONFIG_SND_HDA_CODEC_ANALOG
+	snd_hda_preset_analog,
+#endif
+#ifdef CONFIG_SND_HDA_CODEC_SIGMATEL
+	snd_hda_preset_sigmatel,
+#endif
+#ifdef CONFIG_SND_HDA_CODEC_SI3054
+	snd_hda_preset_si3054,
+#endif
+#ifdef CONFIG_SND_HDA_CODEC_ATIHDMI
+	snd_hda_preset_atihdmi,
+#endif
+#ifdef CONFIG_SND_HDA_CODEC_CONEXANT
+	snd_hda_preset_conexant,
+#endif
+#ifdef CONFIG_SND_HDA_CODEC_VIA
+	snd_hda_preset_via,
+#endif
+	NULL
+};
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 static void hda_power_work(struct work_struct *work);
@@ -690,6 +720,19 @@
 	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, format);
 }
 
+void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid)
+{
+	if (!nid)
+		return;
+
+	snd_printdd("hda_codec_cleanup_stream: NID=0x%x\n", nid);
+	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0);
+#if 0 /* keep the format */
+	msleep(1);
+	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0);
+#endif
+}
+
 /*
  * amp access functions
  */
@@ -1037,16 +1080,24 @@
 }
 
 /* find a mixer control element with the given name */
-struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
-					    const char *name)
+static struct snd_kcontrol *
+_snd_hda_find_mixer_ctl(struct hda_codec *codec,
+			const char *name, int idx)
 {
 	struct snd_ctl_elem_id id;
 	memset(&id, 0, sizeof(id));
 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	id.index = idx;
 	strcpy(id.name, name);
 	return snd_ctl_find_id(codec->bus->card, &id);
 }
 
+struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
+					    const char *name)
+{
+	return _snd_hda_find_mixer_ctl(codec, name, 0);
+}
+
 /* create a virtual master control and add slaves */
 int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
 			unsigned int *tlv, const char **slaves)
@@ -1481,6 +1532,8 @@
 	{ } /* end */
 };
 
+#define SPDIF_MAX_IDX	4	/* 4 instances should be enough to probe */
+
 /**
  * snd_hda_create_spdif_out_ctls - create Output SPDIF-related controls
  * @codec: the HDA codec
@@ -1496,9 +1549,20 @@
 	int err;
 	struct snd_kcontrol *kctl;
 	struct snd_kcontrol_new *dig_mix;
+	int idx;
 
+	for (idx = 0; idx < SPDIF_MAX_IDX; idx++) {
+		if (!_snd_hda_find_mixer_ctl(codec, "IEC958 Playback Switch",
+					     idx))
+			break;
+	}
+	if (idx >= SPDIF_MAX_IDX) {
+		printk(KERN_ERR "hda_codec: too many IEC958 outputs\n");
+		return -EBUSY;
+	}
 	for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) {
 		kctl = snd_ctl_new1(dig_mix, codec);
+		kctl->id.index = idx;
 		kctl->private_value = nid;
 		err = snd_ctl_add(codec->bus->card, kctl);
 		if (err < 0)
@@ -1512,6 +1576,43 @@
 }
 
 /*
+ * SPDIF sharing with analog output
+ */
+static int spdif_share_sw_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_multi_out *mout = snd_kcontrol_chip(kcontrol);
+	ucontrol->value.integer.value[0] = mout->share_spdif;
+	return 0;
+}
+
+static int spdif_share_sw_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_multi_out *mout = snd_kcontrol_chip(kcontrol);
+	mout->share_spdif = !!ucontrol->value.integer.value[0];
+	return 0;
+}
+
+static struct snd_kcontrol_new spdif_share_sw = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "IEC958 Default PCM Playback Switch",
+	.info = snd_ctl_boolean_mono_info,
+	.get = spdif_share_sw_get,
+	.put = spdif_share_sw_put,
+};
+
+int snd_hda_create_spdif_share_sw(struct hda_codec *codec,
+				  struct hda_multi_out *mout)
+{
+	if (!mout->dig_out_nid)
+		return 0;
+	/* ATTENTION: here mout is passed as private_data, instead of codec */
+	return snd_ctl_add(codec->bus->card,
+			   snd_ctl_new1(&spdif_share_sw, mout));
+}
+
+/*
  * SPDIF input
  */
 
@@ -1595,7 +1696,17 @@
 	int err;
 	struct snd_kcontrol *kctl;
 	struct snd_kcontrol_new *dig_mix;
+	int idx;
 
+	for (idx = 0; idx < SPDIF_MAX_IDX; idx++) {
+		if (!_snd_hda_find_mixer_ctl(codec, "IEC958 Capture Switch",
+					     idx))
+			break;
+	}
+	if (idx >= SPDIF_MAX_IDX) {
+		printk(KERN_ERR "hda_codec: too many IEC958 inputs\n");
+		return -EBUSY;
+	}
 	for (dig_mix = dig_in_ctls; dig_mix->name; dig_mix++) {
 		kctl = snd_ctl_new1(dig_mix, codec);
 		kctl->private_value = nid;
@@ -2106,7 +2217,7 @@
 				   struct hda_codec *codec,
 				   struct snd_pcm_substream *substream)
 {
-	snd_hda_codec_setup_stream(codec, hinfo->nid, 0, 0, 0);
+	snd_hda_codec_cleanup_stream(codec, hinfo->nid);
 	return 0;
 }
 
@@ -2491,7 +2602,7 @@
 	mutex_lock(&codec->spdif_mutex);
 	if (mout->dig_out_used == HDA_DIG_ANALOG_DUP)
 		/* already opened as analog dup; reset it once */
-		snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 0, 0, 0);
+		snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid);
 	mout->dig_out_used = HDA_DIG_EXCLUSIVE;
 	mutex_unlock(&codec->spdif_mutex);
 	return 0;
@@ -2526,9 +2637,36 @@
  */
 int snd_hda_multi_out_analog_open(struct hda_codec *codec,
 				  struct hda_multi_out *mout,
-				  struct snd_pcm_substream *substream)
+				  struct snd_pcm_substream *substream,
+				  struct hda_pcm_stream *hinfo)
 {
-	substream->runtime->hw.channels_max = mout->max_channels;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	runtime->hw.channels_max = mout->max_channels;
+	if (mout->dig_out_nid) {
+		if (!mout->analog_rates) {
+			mout->analog_rates = hinfo->rates;
+			mout->analog_formats = hinfo->formats;
+			mout->analog_maxbps = hinfo->maxbps;
+		} else {
+			runtime->hw.rates = mout->analog_rates;
+			runtime->hw.formats = mout->analog_formats;
+			hinfo->maxbps = mout->analog_maxbps;
+		}
+		if (!mout->spdif_rates) {
+			snd_hda_query_supported_pcm(codec, mout->dig_out_nid,
+						    &mout->spdif_rates,
+						    &mout->spdif_formats,
+						    &mout->spdif_maxbps);
+		}
+		mutex_lock(&codec->spdif_mutex);
+		if (mout->share_spdif) {
+			runtime->hw.rates &= mout->spdif_rates;
+			runtime->hw.formats &= mout->spdif_formats;
+			if (mout->spdif_maxbps < hinfo->maxbps)
+				hinfo->maxbps = mout->spdif_maxbps;
+		}
+		mutex_unlock(&codec->spdif_mutex);
+	}
 	return snd_pcm_hw_constraint_step(substream->runtime, 0,
 					  SNDRV_PCM_HW_PARAM_CHANNELS, 2);
 }
@@ -2548,7 +2686,8 @@
 	int i;
 
 	mutex_lock(&codec->spdif_mutex);
-	if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
+	if (mout->dig_out_nid && mout->share_spdif &&
+	    mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
 		if (chs == 2 &&
 		    snd_hda_is_supported_format(codec, mout->dig_out_nid,
 						format) &&
@@ -2558,8 +2697,7 @@
 					     stream_tag, format);
 		} else {
 			mout->dig_out_used = 0;
-			snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
-						   0, 0, 0);
+			snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid);
 		}
 	}
 	mutex_unlock(&codec->spdif_mutex);
@@ -2601,17 +2739,16 @@
 	int i;
 
 	for (i = 0; i < mout->num_dacs; i++)
-		snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0);
+		snd_hda_codec_cleanup_stream(codec, nids[i]);
 	if (mout->hp_nid)
-		snd_hda_codec_setup_stream(codec, mout->hp_nid, 0, 0, 0);
+		snd_hda_codec_cleanup_stream(codec, mout->hp_nid);
 	for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
 		if (mout->extra_out_nid[i])
-			snd_hda_codec_setup_stream(codec,
-						   mout->extra_out_nid[i],
-						   0, 0, 0);
+			snd_hda_codec_cleanup_stream(codec,
+						     mout->extra_out_nid[i]);
 	mutex_lock(&codec->spdif_mutex);
 	if (mout->dig_out_nid && mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
-		snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 0, 0, 0);
+		snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid);
 		mout->dig_out_used = 0;
 	}
 	mutex_unlock(&codec->spdif_mutex);
@@ -2790,6 +2927,30 @@
 		}
 	}
 
+	/* FIX-UP:
+	 * If no line-out is defined but multiple HPs are found,
+	 * some of them might be the real line-outs.
+	 */
+	if (!cfg->line_outs && cfg->hp_outs > 1) {
+		int i = 0;
+		while (i < cfg->hp_outs) {
+			/* The real HPs should have the sequence 0x0f */
+			if ((sequences_hp[i] & 0x0f) == 0x0f) {
+				i++;
+				continue;
+			}
+			/* Move it to the line-out table */
+			cfg->line_out_pins[cfg->line_outs] = cfg->hp_pins[i];
+			sequences_line_out[cfg->line_outs] = sequences_hp[i];
+			cfg->line_outs++;
+			cfg->hp_outs--;
+			memmove(cfg->hp_pins + i, cfg->hp_pins + i + 1,
+				sizeof(cfg->hp_pins[0]) * (cfg->hp_outs - i));
+			memmove(sequences_hp + i - 1, sequences_hp + i,
+				sizeof(sequences_hp[0]) * (cfg->hp_outs - i));
+		}
+	}
+
 	/* sort by sequence */
 	sort_pins_by_sequence(cfg->line_out_pins, sequences_line_out,
 			      cfg->line_outs);
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index f148711..dcd390b 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -590,11 +590,21 @@
 	struct hda_pcm_ops ops;
 };
 
+/* PCM types */
+enum {
+	HDA_PCM_TYPE_AUDIO,
+	HDA_PCM_TYPE_SPDIF,
+	HDA_PCM_TYPE_HDMI,
+	HDA_PCM_TYPE_MODEM,
+	HDA_PCM_NTYPES
+};
+
 /* for PCM creation */
 struct hda_pcm {
 	char *name;
 	struct hda_pcm_stream stream[2];
-	unsigned int is_modem;	/* modem codec? */
+	unsigned int pcm_type;	/* HDA_PCM_TYPE_XXX */
+	int device;	/* assigned device number */
 };
 
 /* codec information */
@@ -712,6 +722,7 @@
 void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
 				u32 stream_tag,
 				int channel_id, int format);
+void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid);
 unsigned int snd_hda_calc_stream_format(unsigned int rate,
 					unsigned int channels,
 					unsigned int format,
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index f9de7c4..59e4389 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -1007,8 +1007,8 @@
 {
 	struct hda_gspec *spec = codec->spec;
 
-	snd_hda_codec_setup_stream(codec, hinfo->nid, 0, 0, 0);
-	snd_hda_codec_setup_stream(codec, spec->dac_node[1]->nid, 0, 0, 0);
+	snd_hda_codec_cleanup_stream(codec, hinfo->nid);
+	snd_hda_codec_cleanup_stream(codec, spec->dac_node[1]->nid);
 	return 0;
 }
 
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 4be36c8..b3a618e 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -39,6 +39,7 @@
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/dma-mapping.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -185,35 +186,28 @@
 
 /* max number of SDs */
 /* ICH, ATI and VIA have 4 playback and 4 capture */
-#define ICH6_CAPTURE_INDEX	0
 #define ICH6_NUM_CAPTURE	4
-#define ICH6_PLAYBACK_INDEX	4
 #define ICH6_NUM_PLAYBACK	4
 
 /* ULI has 6 playback and 5 capture */
-#define ULI_CAPTURE_INDEX	0
 #define ULI_NUM_CAPTURE		5
-#define ULI_PLAYBACK_INDEX	5
 #define ULI_NUM_PLAYBACK	6
 
 /* ATI HDMI has 1 playback and 0 capture */
-#define ATIHDMI_CAPTURE_INDEX	0
 #define ATIHDMI_NUM_CAPTURE	0
-#define ATIHDMI_PLAYBACK_INDEX	0
 #define ATIHDMI_NUM_PLAYBACK	1
 
 /* this number is statically defined for simplicity */
 #define MAX_AZX_DEV		16
 
 /* max number of fragments - we may use more if allocating more pages for BDL */
-#define BDL_SIZE		PAGE_ALIGN(8192)
-#define AZX_MAX_FRAG		(BDL_SIZE / (MAX_AZX_DEV * 16))
+#define BDL_SIZE		4096
+#define AZX_MAX_BDL_ENTRIES	(BDL_SIZE / 16)
+#define AZX_MAX_FRAG		32
 /* max buffer size - no h/w limit, you can increase as you like */
 #define AZX_MAX_BUF_SIZE	(1024*1024*1024)
 /* max number of PCM devics per card */
-#define AZX_MAX_AUDIO_PCMS	6
-#define AZX_MAX_MODEM_PCMS	2
-#define AZX_MAX_PCMS		(AZX_MAX_AUDIO_PCMS + AZX_MAX_MODEM_PCMS)
+#define AZX_MAX_PCMS		8
 
 /* RIRB int mask: overrun[2], response[0] */
 #define RIRB_INT_RESPONSE	0x01
@@ -227,6 +221,9 @@
 /* SD_CTL bits */
 #define SD_CTL_STREAM_RESET	0x01	/* stream reset bit */
 #define SD_CTL_DMA_START	0x02	/* stream DMA start bit */
+#define SD_CTL_STRIPE		(3 << 16)	/* stripe control */
+#define SD_CTL_TRAFFIC_PRIO	(1 << 18)	/* traffic priority */
+#define SD_CTL_DIR		(1 << 19)	/* bi-directional stream */
 #define SD_CTL_STREAM_TAG_MASK	(0xf << 20)
 #define SD_CTL_STREAM_TAG_SHIFT	20
 
@@ -284,12 +281,10 @@
  */
 
 struct azx_dev {
-	u32 *bdl;		/* virtual address of the BDL */
-	dma_addr_t bdl_addr;	/* physical address of the BDL */
+	struct snd_dma_buffer bdl; /* BDL buffer */
 	u32 *posbuf;		/* position buffer pointer */
 
 	unsigned int bufsize;	/* size of the play buffer in bytes */
-	unsigned int fragsize;	/* size of each period in bytes */
 	unsigned int frags;	/* number for period in the play buffer */
 	unsigned int fifo_size;	/* FIFO size */
 
@@ -350,7 +345,6 @@
 	struct azx_dev *azx_dev;
 
 	/* PCM */
-	unsigned int pcm_devs;
 	struct snd_pcm *pcm[AZX_MAX_PCMS];
 
 	/* HD codec */
@@ -361,8 +355,7 @@
 	struct azx_rb corb;
 	struct azx_rb rirb;
 
-	/* BDL, CORB/RIRB and position buffers */
-	struct snd_dma_buffer bdl;
+	/* CORB/RIRB and position buffers */
 	struct snd_dma_buffer rb;
 	struct snd_dma_buffer posbuf;
 
@@ -546,8 +539,9 @@
 		if (res_ex & ICH6_RIRB_EX_UNSOL_EV)
 			snd_hda_queue_unsol_event(chip->bus, res, res_ex);
 		else if (chip->rirb.cmds) {
-			chip->rirb.cmds--;
 			chip->rirb.res = res;
+			smp_wmb();
+			chip->rirb.cmds--;
 		}
 	}
 }
@@ -566,8 +560,10 @@
 			azx_update_rirb(chip);
 			spin_unlock_irq(&chip->reg_lock);
 		}
-		if (!chip->rirb.cmds)
+		if (!chip->rirb.cmds) {
+			smp_rmb();
 			return chip->rirb.res; /* the last value */
+		}
 		if (time_after(jiffies, timeout))
 			break;
 		if (codec->bus->needs_damn_long_delay)
@@ -965,30 +961,57 @@
 /*
  * set up BDL entries
  */
-static void azx_setup_periods(struct azx_dev *azx_dev)
+static int azx_setup_periods(struct snd_pcm_substream *substream,
+			     struct azx_dev *azx_dev)
 {
-	u32 *bdl = azx_dev->bdl;
-	dma_addr_t dma_addr = azx_dev->substream->runtime->dma_addr;
-	int idx;
+	struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
+	u32 *bdl;
+	int i, ofs, periods, period_bytes;
 
 	/* reset BDL address */
 	azx_sd_writel(azx_dev, SD_BDLPL, 0);
 	azx_sd_writel(azx_dev, SD_BDLPU, 0);
 
+	period_bytes = snd_pcm_lib_period_bytes(substream);
+	periods = azx_dev->bufsize / period_bytes;
+
 	/* program the initial BDL entries */
-	for (idx = 0; idx < azx_dev->frags; idx++) {
-		unsigned int off = idx << 2; /* 4 dword step */
-		dma_addr_t addr = dma_addr + idx * azx_dev->fragsize;
-		/* program the address field of the BDL entry */
-		bdl[off] = cpu_to_le32((u32)addr);
-		bdl[off+1] = cpu_to_le32(upper_32bit(addr));
-
-		/* program the size field of the BDL entry */
-		bdl[off+2] = cpu_to_le32(azx_dev->fragsize);
-
-		/* program the IOC to enable interrupt when buffer completes */
-		bdl[off+3] = cpu_to_le32(0x01);
+	bdl = (u32 *)azx_dev->bdl.area;
+	ofs = 0;
+	azx_dev->frags = 0;
+	for (i = 0; i < periods; i++) {
+		int size, rest;
+		if (i >= AZX_MAX_BDL_ENTRIES) {
+			snd_printk(KERN_ERR "Too many BDL entries: "
+				   "buffer=%d, period=%d\n",
+				   azx_dev->bufsize, period_bytes);
+			/* reset */
+			azx_sd_writel(azx_dev, SD_BDLPL, 0);
+			azx_sd_writel(azx_dev, SD_BDLPU, 0);
+			return -EINVAL;
+		}
+		rest = period_bytes;
+		do {
+			dma_addr_t addr = snd_pcm_sgbuf_get_addr(sgbuf, ofs);
+			/* program the address field of the BDL entry */
+			bdl[0] = cpu_to_le32((u32)addr);
+			bdl[1] = cpu_to_le32(upper_32bit(addr));
+			/* program the size field of the BDL entry */
+			size = PAGE_SIZE - (ofs % PAGE_SIZE);
+			if (rest < size)
+				size = rest;
+			bdl[2] = cpu_to_le32(size);
+			/* program the IOC to enable interrupt
+			 * only when the whole fragment is processed
+			 */
+			rest -= size;
+			bdl[3] = rest ? 0 : cpu_to_le32(0x01);
+			bdl += 4;
+			azx_dev->frags++;
+			ofs += size;
+		} while (rest > 0);
 	}
+	return 0;
 }
 
 /*
@@ -1037,14 +1060,17 @@
 
 	/* program the BDL address */
 	/* lower BDL address */
-	azx_sd_writel(azx_dev, SD_BDLPL, (u32)azx_dev->bdl_addr);
+	azx_sd_writel(azx_dev, SD_BDLPL, (u32)azx_dev->bdl.addr);
 	/* upper BDL address */
-	azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl_addr));
+	azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl.addr));
 
 	/* enable the position buffer */
-	if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
-		azx_writel(chip, DPLBASE,
-			   (u32)chip->posbuf.addr |ICH6_DPLBASE_ENABLE);
+	if (chip->position_fix == POS_FIX_POSBUF ||
+	    chip->position_fix == POS_FIX_AUTO) {
+		if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
+			azx_writel(chip, DPLBASE,
+				(u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE);
+	}
 
 	/* set the interrupt enable bits in the descriptor control register */
 	azx_sd_writel(azx_dev, SD_CTL,
@@ -1157,7 +1183,8 @@
 				 SNDRV_PCM_INFO_MMAP_VALID |
 				 /* No full-resume yet implemented */
 				 /* SNDRV_PCM_INFO_RESUME |*/
-				 SNDRV_PCM_INFO_PAUSE),
+				 SNDRV_PCM_INFO_PAUSE |
+				 SNDRV_PCM_INFO_SYNC_START),
 	.formats =		SNDRV_PCM_FMTBIT_S16_LE,
 	.rates =		SNDRV_PCM_RATE_48000,
 	.rate_min =		48000,
@@ -1219,6 +1246,7 @@
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 
 	runtime->private_data = azx_dev;
+	snd_pcm_set_sync(substream);
 	mutex_unlock(&chip->open_mutex);
 	return 0;
 }
@@ -1275,8 +1303,6 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 
 	azx_dev->bufsize = snd_pcm_lib_buffer_bytes(substream);
-	azx_dev->fragsize = snd_pcm_lib_period_bytes(substream);
-	azx_dev->frags = azx_dev->bufsize / azx_dev->fragsize;
 	azx_dev->format_val = snd_hda_calc_stream_format(runtime->rate,
 							 runtime->channels,
 							 runtime->format,
@@ -1288,10 +1314,10 @@
 		return -EINVAL;
 	}
 
-	snd_printdd("azx_pcm_prepare: bufsize=0x%x, fragsize=0x%x, "
-		    "format=0x%x\n",
-		    azx_dev->bufsize, azx_dev->fragsize, azx_dev->format_val);
-	azx_setup_periods(azx_dev);
+	snd_printdd("azx_pcm_prepare: bufsize=0x%x, format=0x%x\n",
+		    azx_dev->bufsize, azx_dev->format_val);
+	if (azx_setup_periods(substream, azx_dev) < 0)
+		return -EINVAL;
 	azx_setup_controller(chip, azx_dev);
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1;
@@ -1305,37 +1331,94 @@
 static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 {
 	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
-	struct azx_dev *azx_dev = get_azx_dev(substream);
 	struct azx *chip = apcm->chip;
-	int err = 0;
+	struct azx_dev *azx_dev;
+	struct snd_pcm_substream *s;
+	int start, nsync = 0, sbits = 0;
+	int nwait, timeout;
 
-	spin_lock(&chip->reg_lock);
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_START:
-		azx_stream_start(chip, azx_dev);
-		azx_dev->running = 1;
+		start = 1;
 		break;
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_STOP:
-		azx_stream_stop(chip, azx_dev);
-		azx_dev->running = 0;
+		start = 0;
 		break;
 	default:
-		err = -EINVAL;
+		return -EINVAL;
+	}
+
+	snd_pcm_group_for_each_entry(s, substream) {
+		if (s->pcm->card != substream->pcm->card)
+			continue;
+		azx_dev = get_azx_dev(s);
+		sbits |= 1 << azx_dev->index;
+		nsync++;
+		snd_pcm_trigger_done(s, substream);
+	}
+
+	spin_lock(&chip->reg_lock);
+	if (nsync > 1) {
+		/* first, set SYNC bits of corresponding streams */
+		azx_writel(chip, SYNC, azx_readl(chip, SYNC) | sbits);
+	}
+	snd_pcm_group_for_each_entry(s, substream) {
+		if (s->pcm->card != substream->pcm->card)
+			continue;
+		azx_dev = get_azx_dev(s);
+		if (start)
+			azx_stream_start(chip, azx_dev);
+		else
+			azx_stream_stop(chip, azx_dev);
+		azx_dev->running = start;
 	}
 	spin_unlock(&chip->reg_lock);
-	if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH ||
-	    cmd == SNDRV_PCM_TRIGGER_SUSPEND ||
-	    cmd == SNDRV_PCM_TRIGGER_STOP) {
-		int timeout = 5000;
-		while ((azx_sd_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START) &&
-		       --timeout)
-			;
+	if (start) {
+		if (nsync == 1)
+			return 0;
+		/* wait until all FIFOs get ready */
+		for (timeout = 5000; timeout; timeout--) {
+			nwait = 0;
+			snd_pcm_group_for_each_entry(s, substream) {
+				if (s->pcm->card != substream->pcm->card)
+					continue;
+				azx_dev = get_azx_dev(s);
+				if (!(azx_sd_readb(azx_dev, SD_STS) &
+				      SD_STS_FIFO_READY))
+					nwait++;
+			}
+			if (!nwait)
+				break;
+			cpu_relax();
+		}
+	} else {
+		/* wait until all RUN bits are cleared */
+		for (timeout = 5000; timeout; timeout--) {
+			nwait = 0;
+			snd_pcm_group_for_each_entry(s, substream) {
+				if (s->pcm->card != substream->pcm->card)
+					continue;
+				azx_dev = get_azx_dev(s);
+				if (azx_sd_readb(azx_dev, SD_CTL) &
+				    SD_CTL_DMA_START)
+					nwait++;
+			}
+			if (!nwait)
+				break;
+			cpu_relax();
+		}
 	}
-	return err;
+	if (nsync > 1) {
+		spin_lock(&chip->reg_lock);
+		/* reset SYNC bits */
+		azx_writel(chip, SYNC, azx_readl(chip, SYNC) & ~sbits);
+		spin_unlock(&chip->reg_lock);
+	}
+	return 0;
 }
 
 static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
@@ -1378,6 +1461,7 @@
 	.prepare = azx_pcm_prepare,
 	.trigger = azx_pcm_trigger,
 	.pointer = azx_pcm_pointer,
+	.page = snd_pcm_sgbuf_ops_page,
 };
 
 static void azx_pcm_free(struct snd_pcm *pcm)
@@ -1386,7 +1470,7 @@
 }
 
 static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec,
-				      struct hda_pcm *cpcm, int pcm_dev)
+				      struct hda_pcm *cpcm)
 {
 	int err;
 	struct snd_pcm *pcm;
@@ -1400,7 +1484,7 @@
 
 	snd_assert(cpcm->name, return -EINVAL);
 
-	err = snd_pcm_new(chip->card, cpcm->name, pcm_dev,
+	err = snd_pcm_new(chip->card, cpcm->name, cpcm->device,
 			  cpcm->stream[0].substreams,
 			  cpcm->stream[1].substreams,
 			  &pcm);
@@ -1420,62 +1504,70 @@
 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &azx_pcm_ops);
 	if (cpcm->stream[1].substreams)
 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops);
-	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
 					      snd_dma_pci_data(chip->pci),
 					      1024 * 64, 1024 * 1024);
-	chip->pcm[pcm_dev] = pcm;
-	if (chip->pcm_devs < pcm_dev + 1)
-		chip->pcm_devs = pcm_dev + 1;
-
+	chip->pcm[cpcm->device] = pcm;
 	return 0;
 }
 
 static int __devinit azx_pcm_create(struct azx *chip)
 {
+	static const char *dev_name[HDA_PCM_NTYPES] = {
+		"Audio", "SPDIF", "HDMI", "Modem"
+	};
+	/* starting device index for each PCM type */
+	static int dev_idx[HDA_PCM_NTYPES] = {
+		[HDA_PCM_TYPE_AUDIO] = 0,
+		[HDA_PCM_TYPE_SPDIF] = 1,
+		[HDA_PCM_TYPE_HDMI] = 3,
+		[HDA_PCM_TYPE_MODEM] = 6
+	};
+	/* normal audio device indices; not linear to keep compatibility */
+	static int audio_idx[4] = { 0, 2, 4, 5 };
 	struct hda_codec *codec;
 	int c, err;
-	int pcm_dev;
+	int num_devs[HDA_PCM_NTYPES];
 
 	err = snd_hda_build_pcms(chip->bus);
 	if (err < 0)
 		return err;
 
 	/* create audio PCMs */
-	pcm_dev = 0;
+	memset(num_devs, 0, sizeof(num_devs));
 	list_for_each_entry(codec, &chip->bus->codec_list, list) {
 		for (c = 0; c < codec->num_pcms; c++) {
-			if (codec->pcm_info[c].is_modem)
-				continue; /* create later */
-			if (pcm_dev >= AZX_MAX_AUDIO_PCMS) {
-				snd_printk(KERN_ERR SFX
-					   "Too many audio PCMs\n");
-				return -EINVAL;
+			struct hda_pcm *cpcm = &codec->pcm_info[c];
+			int type = cpcm->pcm_type;
+			switch (type) {
+			case HDA_PCM_TYPE_AUDIO:
+				if (num_devs[type] >= ARRAY_SIZE(audio_idx)) {
+					snd_printk(KERN_WARNING
+						   "Too many audio devices\n");
+					continue;
+				}
+				cpcm->device = audio_idx[num_devs[type]];
+				break;
+			case HDA_PCM_TYPE_SPDIF:
+			case HDA_PCM_TYPE_HDMI:
+			case HDA_PCM_TYPE_MODEM:
+				if (num_devs[type]) {
+					snd_printk(KERN_WARNING
+						   "%s already defined\n",
+						   dev_name[type]);
+					continue;
+				}
+				cpcm->device = dev_idx[type];
+				break;
+			default:
+				snd_printk(KERN_WARNING
+					   "Invalid PCM type %d\n", type);
+				continue;
 			}
-			err = create_codec_pcm(chip, codec,
-					       &codec->pcm_info[c], pcm_dev);
+			num_devs[type]++;
+			err = create_codec_pcm(chip, codec, cpcm);
 			if (err < 0)
 				return err;
-			pcm_dev++;
-		}
-	}
-
-	/* create modem PCMs */
-	pcm_dev = AZX_MAX_AUDIO_PCMS;
-	list_for_each_entry(codec, &chip->bus->codec_list, list) {
-		for (c = 0; c < codec->num_pcms; c++) {
-			if (!codec->pcm_info[c].is_modem)
-				continue; /* already created */
-			if (pcm_dev >= AZX_MAX_PCMS) {
-				snd_printk(KERN_ERR SFX
-					   "Too many modem PCMs\n");
-				return -EINVAL;
-			}
-			err = create_codec_pcm(chip, codec,
-					       &codec->pcm_info[c], pcm_dev);
-			if (err < 0)
-				return err;
-			chip->pcm[pcm_dev]->dev_class = SNDRV_PCM_CLASS_MODEM;
-			pcm_dev++;
 		}
 	}
 	return 0;
@@ -1502,10 +1594,7 @@
 	 * and initialize
 	 */
 	for (i = 0; i < chip->num_streams; i++) {
-		unsigned int off = sizeof(u32) * (i * AZX_MAX_FRAG * 4);
 		struct azx_dev *azx_dev = &chip->azx_dev[i];
-		azx_dev->bdl = (u32 *)(chip->bdl.area + off);
-		azx_dev->bdl_addr = chip->bdl.addr + off;
 		azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8);
 		/* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
 		azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80);
@@ -1587,13 +1676,12 @@
 	int i;
 
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
-	for (i = 0; i < chip->pcm_devs; i++)
+	for (i = 0; i < AZX_MAX_PCMS; i++)
 		snd_pcm_suspend_all(chip->pcm[i]);
 	if (chip->initialized)
 		snd_hda_suspend(chip->bus, state);
 	azx_stop_chip(chip);
 	if (chip->irq >= 0) {
-		synchronize_irq(chip->irq);
 		free_irq(chip->irq, chip);
 		chip->irq = -1;
 	}
@@ -1641,24 +1729,26 @@
  */
 static int azx_free(struct azx *chip)
 {
+	int i;
+
 	if (chip->initialized) {
-		int i;
 		for (i = 0; i < chip->num_streams; i++)
 			azx_stream_stop(chip, &chip->azx_dev[i]);
 		azx_stop_chip(chip);
 	}
 
-	if (chip->irq >= 0) {
-		synchronize_irq(chip->irq);
+	if (chip->irq >= 0)
 		free_irq(chip->irq, (void*)chip);
-	}
 	if (chip->msi)
 		pci_disable_msi(chip->pci);
 	if (chip->remap_addr)
 		iounmap(chip->remap_addr);
 
-	if (chip->bdl.area)
-		snd_dma_free_pages(&chip->bdl);
+	if (chip->azx_dev) {
+		for (i = 0; i < chip->num_streams; i++)
+			if (chip->azx_dev[i].bdl.area)
+				snd_dma_free_pages(&chip->azx_dev[i].bdl);
+	}
 	if (chip->rb.area)
 		snd_dma_free_pages(&chip->rb);
 	if (chip->posbuf.area)
@@ -1682,6 +1772,7 @@
 static struct snd_pci_quirk position_fix_list[] __devinitdata = {
 	SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_NONE),
 	SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_NONE),
+	SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_NONE),
 	{}
 };
 
@@ -1740,7 +1831,7 @@
 				struct azx **rchip)
 {
 	struct azx *chip;
-	int err;
+	int i, err;
 	unsigned short gcap;
 	static struct snd_device_ops ops = {
 		.dev_free = azx_dev_free,
@@ -1812,38 +1903,35 @@
 	gcap = azx_readw(chip, GCAP);
 	snd_printdd("chipset global capabilities = 0x%x\n", gcap);
 
-	if (gcap) {
-		/* read number of streams from GCAP register instead of using
-		 * hardcoded value
-		 */
-		chip->playback_streams = (gcap & (0xF << 12)) >> 12;
-		chip->capture_streams = (gcap & (0xF << 8)) >> 8;
-		chip->playback_index_offset = chip->capture_streams;
-		chip->capture_index_offset = 0;
-	} else {
+	/* allow 64bit DMA address if supported by H/W */
+	if ((gcap & 0x01) && !pci_set_dma_mask(pci, DMA_64BIT_MASK))
+		pci_set_consistent_dma_mask(pci, DMA_64BIT_MASK);
+
+	/* read number of streams from GCAP register instead of using
+	 * hardcoded value
+	 */
+	chip->capture_streams = (gcap >> 8) & 0x0f;
+	chip->playback_streams = (gcap >> 12) & 0x0f;
+	if (!chip->playback_streams && !chip->capture_streams) {
 		/* gcap didn't give any info, switching to old method */
 
 		switch (chip->driver_type) {
 		case AZX_DRIVER_ULI:
 			chip->playback_streams = ULI_NUM_PLAYBACK;
 			chip->capture_streams = ULI_NUM_CAPTURE;
-			chip->playback_index_offset = ULI_PLAYBACK_INDEX;
-			chip->capture_index_offset = ULI_CAPTURE_INDEX;
 			break;
 		case AZX_DRIVER_ATIHDMI:
 			chip->playback_streams = ATIHDMI_NUM_PLAYBACK;
 			chip->capture_streams = ATIHDMI_NUM_CAPTURE;
-			chip->playback_index_offset = ATIHDMI_PLAYBACK_INDEX;
-			chip->capture_index_offset = ATIHDMI_CAPTURE_INDEX;
 			break;
 		default:
 			chip->playback_streams = ICH6_NUM_PLAYBACK;
 			chip->capture_streams = ICH6_NUM_CAPTURE;
-			chip->playback_index_offset = ICH6_PLAYBACK_INDEX;
-			chip->capture_index_offset = ICH6_CAPTURE_INDEX;
 			break;
 		}
 	}
+	chip->capture_index_offset = 0;
+	chip->playback_index_offset = chip->capture_streams;
 	chip->num_streams = chip->playback_streams + chip->capture_streams;
 	chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev),
 				GFP_KERNEL);
@@ -1852,13 +1940,15 @@
 		goto errout;
 	}
 
-	/* allocate memory for the BDL for each stream */
-	err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
-				  snd_dma_pci_data(chip->pci),
-				  BDL_SIZE, &chip->bdl);
-	if (err < 0) {
-		snd_printk(KERN_ERR SFX "cannot allocate BDL\n");
-		goto errout;
+	for (i = 0; i < chip->num_streams; i++) {
+		/* allocate memory for the BDL for each stream */
+		err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
+					  snd_dma_pci_data(chip->pci),
+					  BDL_SIZE, &chip->azx_dev[i].bdl);
+		if (err < 0) {
+			snd_printk(KERN_ERR SFX "cannot allocate BDL\n");
+			goto errout;
+		}
 	}
 	/* allocate memory for the position buffer */
 	err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
@@ -1994,48 +2084,63 @@
 
 /* PCI IDs */
 static struct pci_device_id azx_ids[] = {
-	{ 0x8086, 0x2668, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH6 */
-	{ 0x8086, 0x27d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH7 */
-	{ 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ESB2 */
-	{ 0x8086, 0x284b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH8 */
-	{ 0x8086, 0x293e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */
-	{ 0x8086, 0x293f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */
-	{ 0x8086, 0x3a3e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH10 */
-	{ 0x8086, 0x3a6e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH10 */
-	{ 0x8086, 0x811b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SCH }, /* SCH*/
-	{ 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */
-	{ 0x1002, 0x4383, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB600 */
-	{ 0x1002, 0x793b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS600 HDMI */
-	{ 0x1002, 0x7919, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS690 HDMI */
-	{ 0x1002, 0x960f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS780 HDMI */
-	{ 0x1002, 0xaa00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI R600 HDMI */
-	{ 0x1002, 0xaa08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV630 HDMI */
-	{ 0x1002, 0xaa10, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV610 HDMI */
-	{ 0x1002, 0xaa18, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV670 HDMI */
-	{ 0x1002, 0xaa20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV635 HDMI */
-	{ 0x1002, 0xaa28, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV620 HDMI */
-	{ 0x1002, 0xaa30, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV770 HDMI */
-	{ 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_VIA }, /* VIA VT8251/VT8237A */
-	{ 0x1039, 0x7502, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SIS }, /* SIS966 */
-	{ 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */
-	{ 0x10de, 0x026c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP51 */
-	{ 0x10de, 0x0371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP55 */
-	{ 0x10de, 0x03e4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP61 */
-	{ 0x10de, 0x03f0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP61 */
-	{ 0x10de, 0x044a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP65 */
-	{ 0x10de, 0x044b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP65 */
-	{ 0x10de, 0x055c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP67 */
-	{ 0x10de, 0x055d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP67 */
-	{ 0x10de, 0x07fc, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP73 */
-	{ 0x10de, 0x07fd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP73 */
-	{ 0x10de, 0x0774, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */
-	{ 0x10de, 0x0775, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */
-	{ 0x10de, 0x0776, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */
-	{ 0x10de, 0x0777, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */
-	{ 0x10de, 0x0ac0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP79 */
-	{ 0x10de, 0x0ac1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP79 */
-	{ 0x10de, 0x0ac2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP79 */
-	{ 0x10de, 0x0ac3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP79 */
+	/* ICH 6..10 */
+	{ PCI_DEVICE(0x8086, 0x2668), .driver_data = AZX_DRIVER_ICH },
+	{ PCI_DEVICE(0x8086, 0x27d8), .driver_data = AZX_DRIVER_ICH },
+	{ PCI_DEVICE(0x8086, 0x269a), .driver_data = AZX_DRIVER_ICH },
+	{ PCI_DEVICE(0x8086, 0x284b), .driver_data = AZX_DRIVER_ICH },
+	{ PCI_DEVICE(0x8086, 0x293e), .driver_data = AZX_DRIVER_ICH },
+	{ PCI_DEVICE(0x8086, 0x293f), .driver_data = AZX_DRIVER_ICH },
+	{ PCI_DEVICE(0x8086, 0x3a3e), .driver_data = AZX_DRIVER_ICH },
+	{ PCI_DEVICE(0x8086, 0x3a6e), .driver_data = AZX_DRIVER_ICH },
+	/* SCH */
+	{ PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH },
+	/* ATI SB 450/600 */
+	{ PCI_DEVICE(0x1002, 0x437b), .driver_data = AZX_DRIVER_ATI },
+	{ PCI_DEVICE(0x1002, 0x4383), .driver_data = AZX_DRIVER_ATI },
+	/* ATI HDMI */
+	{ PCI_DEVICE(0x1002, 0x793b), .driver_data = AZX_DRIVER_ATIHDMI },
+	{ PCI_DEVICE(0x1002, 0x7919), .driver_data = AZX_DRIVER_ATIHDMI },
+	{ PCI_DEVICE(0x1002, 0x960f), .driver_data = AZX_DRIVER_ATIHDMI },
+	{ PCI_DEVICE(0x1002, 0xaa00), .driver_data = AZX_DRIVER_ATIHDMI },
+	{ PCI_DEVICE(0x1002, 0xaa08), .driver_data = AZX_DRIVER_ATIHDMI },
+	{ PCI_DEVICE(0x1002, 0xaa10), .driver_data = AZX_DRIVER_ATIHDMI },
+	{ PCI_DEVICE(0x1002, 0xaa18), .driver_data = AZX_DRIVER_ATIHDMI },
+	{ PCI_DEVICE(0x1002, 0xaa20), .driver_data = AZX_DRIVER_ATIHDMI },
+	{ PCI_DEVICE(0x1002, 0xaa28), .driver_data = AZX_DRIVER_ATIHDMI },
+	{ PCI_DEVICE(0x1002, 0xaa30), .driver_data = AZX_DRIVER_ATIHDMI },
+	{ PCI_DEVICE(0x1002, 0xaa38), .driver_data = AZX_DRIVER_ATIHDMI },
+	{ PCI_DEVICE(0x1002, 0xaa40), .driver_data = AZX_DRIVER_ATIHDMI },
+	{ PCI_DEVICE(0x1002, 0xaa48), .driver_data = AZX_DRIVER_ATIHDMI },
+	/* VIA VT8251/VT8237A */
+	{ PCI_DEVICE(0x1106, 0x3288), .driver_data = AZX_DRIVER_VIA },
+	/* SIS966 */
+	{ PCI_DEVICE(0x1039, 0x7502), .driver_data = AZX_DRIVER_SIS },
+	/* ULI M5461 */
+	{ PCI_DEVICE(0x10b9, 0x5461), .driver_data = AZX_DRIVER_ULI },
+	/* NVIDIA MCP */
+	{ PCI_DEVICE(0x10de, 0x026c), .driver_data = AZX_DRIVER_NVIDIA },
+	{ PCI_DEVICE(0x10de, 0x0371), .driver_data = AZX_DRIVER_NVIDIA },
+	{ PCI_DEVICE(0x10de, 0x03e4), .driver_data = AZX_DRIVER_NVIDIA },
+	{ PCI_DEVICE(0x10de, 0x03f0), .driver_data = AZX_DRIVER_NVIDIA },
+	{ PCI_DEVICE(0x10de, 0x044a), .driver_data = AZX_DRIVER_NVIDIA },
+	{ PCI_DEVICE(0x10de, 0x044b), .driver_data = AZX_DRIVER_NVIDIA },
+	{ PCI_DEVICE(0x10de, 0x055c), .driver_data = AZX_DRIVER_NVIDIA },
+	{ PCI_DEVICE(0x10de, 0x055d), .driver_data = AZX_DRIVER_NVIDIA },
+	{ PCI_DEVICE(0x10de, 0x0774), .driver_data = AZX_DRIVER_NVIDIA },
+	{ PCI_DEVICE(0x10de, 0x0775), .driver_data = AZX_DRIVER_NVIDIA },
+	{ PCI_DEVICE(0x10de, 0x0776), .driver_data = AZX_DRIVER_NVIDIA },
+	{ PCI_DEVICE(0x10de, 0x0777), .driver_data = AZX_DRIVER_NVIDIA },
+	{ PCI_DEVICE(0x10de, 0x07fc), .driver_data = AZX_DRIVER_NVIDIA },
+	{ PCI_DEVICE(0x10de, 0x07fd), .driver_data = AZX_DRIVER_NVIDIA },
+	{ PCI_DEVICE(0x10de, 0x0ac0), .driver_data = AZX_DRIVER_NVIDIA },
+	{ PCI_DEVICE(0x10de, 0x0ac1), .driver_data = AZX_DRIVER_NVIDIA },
+	{ PCI_DEVICE(0x10de, 0x0ac2), .driver_data = AZX_DRIVER_NVIDIA },
+	{ PCI_DEVICE(0x10de, 0x0ac3), .driver_data = AZX_DRIVER_NVIDIA },
+	{ PCI_DEVICE(0x10de, 0x0bd4), .driver_data = AZX_DRIVER_NVIDIA },
+	{ PCI_DEVICE(0x10de, 0x0bd5), .driver_data = AZX_DRIVER_NVIDIA },
+	{ PCI_DEVICE(0x10de, 0x0bd6), .driver_data = AZX_DRIVER_NVIDIA },
+	{ PCI_DEVICE(0x10de, 0x0bd7), .driver_data = AZX_DRIVER_NVIDIA },
 	{ 0, }
 };
 MODULE_DEVICE_TABLE(pci, azx_ids);
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index ad0014a..5c9e578 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -228,8 +228,18 @@
 	int max_channels;	/* currently supported analog channels */
 	int dig_out_used;	/* current usage of digital out (HDA_DIG_XXX) */
 	int no_share_stream;	/* don't share a stream with multiple pins */
+	int share_spdif;	/* share SPDIF pin */
+	/* PCM information for both analog and SPDIF DACs */
+	unsigned int analog_rates;
+	unsigned int analog_maxbps;
+	u64 analog_formats;
+	unsigned int spdif_rates;
+	unsigned int spdif_maxbps;
+	u64 spdif_formats;
 };
 
+int snd_hda_create_spdif_share_sw(struct hda_codec *codec,
+				  struct hda_multi_out *mout);
 int snd_hda_multi_out_dig_open(struct hda_codec *codec,
 			       struct hda_multi_out *mout);
 int snd_hda_multi_out_dig_close(struct hda_codec *codec,
@@ -241,7 +251,8 @@
 				  struct snd_pcm_substream *substream);
 int snd_hda_multi_out_analog_open(struct hda_codec *codec,
 				  struct hda_multi_out *mout,
-				  struct snd_pcm_substream *substream);
+				  struct snd_pcm_substream *substream,
+				  struct hda_pcm_stream *hinfo);
 int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
 				     struct hda_multi_out *mout,
 				     unsigned int stream_tag,
@@ -407,11 +418,4 @@
 				 hda_nid_t nid);
 #endif /* CONFIG_SND_HDA_POWER_SAVE */
 
-/*
- * virtual master control
- */
-struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
-						 const unsigned int *tlv);
-int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave);
-		      
 #endif /* __SOUND_HDA_LOCAL_H */
diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h
index f5c23bb..2fdf235 100644
--- a/sound/pci/hda/hda_patch.h
+++ b/sound/pci/hda/hda_patch.h
@@ -18,31 +18,3 @@
 extern struct hda_codec_preset snd_hda_preset_conexant[];
 /* VIA codecs */
 extern struct hda_codec_preset snd_hda_preset_via[];
-
-static const struct hda_codec_preset *hda_preset_tables[] = {
-#ifdef CONFIG_SND_HDA_CODEC_REALTEK
-	snd_hda_preset_realtek,
-#endif
-#ifdef CONFIG_SND_HDA_CODEC_CMEDIA
-	snd_hda_preset_cmedia,
-#endif
-#ifdef CONFIG_SND_HDA_CODEC_ANALOG
-	snd_hda_preset_analog,
-#endif
-#ifdef CONFIG_SND_HDA_CODEC_SIGMATEL
-	snd_hda_preset_sigmatel,
-#endif
-#ifdef CONFIG_SND_HDA_CODEC_SI3054
-	snd_hda_preset_si3054,
-#endif
-#ifdef CONFIG_SND_HDA_CODEC_ATIHDMI
-	snd_hda_preset_atihdmi,
-#endif
-#ifdef CONFIG_SND_HDA_CODEC_CONEXANT
-	snd_hda_preset_conexant,
-#endif
-#ifdef CONFIG_SND_HDA_CODEC_VIA
-	snd_hda_preset_via,
-#endif
-	NULL
-};
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index c864928..e0a605a 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -28,6 +28,7 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_patch.h"
 
 struct ad198x_spec {
 	struct snd_kcontrol_new *mixers[5];
@@ -80,7 +81,6 @@
 #endif
 	/* for virtual master */
 	hda_nid_t vmaster_nid;
-	u32 vmaster_tlv[4];
 	const char **slave_vols;
 	const char **slave_sws;
 };
@@ -171,6 +171,11 @@
 		err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
 		if (err < 0)
 			return err;
+		err = snd_hda_create_spdif_share_sw(codec,
+						    &spec->multiout);
+		if (err < 0)
+			return err;
+		spec->multiout.share_spdif = 1;
 	} 
 	if (spec->dig_in_nid) {
 		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
@@ -180,10 +185,11 @@
 
 	/* if we have no master control, let's create it */
 	if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
+		unsigned int vmaster_tlv[4];
 		snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
-					HDA_OUTPUT, spec->vmaster_tlv);
+					HDA_OUTPUT, vmaster_tlv);
 		err = snd_hda_add_vmaster(codec, "Master Playback Volume",
-					  spec->vmaster_tlv,
+					  vmaster_tlv,
 					  (spec->slave_vols ?
 					   spec->slave_vols : ad_slave_vols));
 		if (err < 0)
@@ -217,7 +223,8 @@
 				    struct snd_pcm_substream *substream)
 {
 	struct ad198x_spec *spec = codec->spec;
-	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
+					     hinfo);
 }
 
 static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
@@ -289,8 +296,7 @@
 				      struct snd_pcm_substream *substream)
 {
 	struct ad198x_spec *spec = codec->spec;
-	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
-				   0, 0, 0);
+	snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
 	return 0;
 }
 
@@ -359,6 +365,7 @@
 		info++;
 		codec->num_pcms++;
 		info->name = "AD198x Digital";
+		info->pcm_type = HDA_PCM_TYPE_SPDIF;
 		info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback;
 		info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
 		if (spec->dig_in_nid) {
@@ -611,13 +618,19 @@
 	},
 };
 
+static struct hda_input_mux ad1986a_automic_capture_source = {
+	.num_items = 2,
+	.items = {
+		{ "Mic", 0x0 },
+		{ "Mix", 0x5 },
+	},
+};
+
 static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
 	HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
 	HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
@@ -641,6 +654,33 @@
 	{ } /* end */
 };
 
+/* re-connect the mic boost input according to the jack sensing */
+static void ad1986a_automic(struct hda_codec *codec)
+{
+	unsigned int present;
+	present = snd_hda_codec_read(codec, 0x1f, 0, AC_VERB_GET_PIN_SENSE, 0);
+	/* 0 = 0x1f, 2 = 0x1d, 4 = mixed */
+	snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_CONNECT_SEL,
+			    (present & AC_PINSENSE_PRESENCE) ? 0 : 2);
+}
+
+#define AD1986A_MIC_EVENT		0x36
+
+static void ad1986a_automic_unsol_event(struct hda_codec *codec,
+					    unsigned int res)
+{
+	if ((res >> 26) != AD1986A_MIC_EVENT)
+		return;
+	ad1986a_automic(codec);
+}
+
+static int ad1986a_automic_init(struct hda_codec *codec)
+{
+	ad198x_init(codec);
+	ad1986a_automic(codec);
+	return 0;
+}
+
 /* laptop-automute - 2ch only */
 
 static void ad1986a_update_hp(struct hda_codec *codec)
@@ -844,6 +884,15 @@
 	{}
 };
 
+static struct hda_verb ad1986a_automic_verbs[] = {
+	{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	/*{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},*/
+	{0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
+	{0x1f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_MIC_EVENT},
+	{}
+};
+
 /* Ultra initialization */
 static struct hda_verb ad1986a_ultra_init[] = {
 	/* eapd initialization */
@@ -986,14 +1035,17 @@
 		break;
 	case AD1986A_LAPTOP_EAPD:
 		spec->mixers[0] = ad1986a_laptop_eapd_mixers;
-		spec->num_init_verbs = 2;
+		spec->num_init_verbs = 3;
 		spec->init_verbs[1] = ad1986a_eapd_init_verbs;
+		spec->init_verbs[2] = ad1986a_automic_verbs;
 		spec->multiout.max_channels = 2;
 		spec->multiout.num_dacs = 1;
 		spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
 		if (!is_jack_available(codec, 0x25))
 			spec->multiout.dig_out_nid = 0;
-		spec->input_mux = &ad1986a_laptop_eapd_capture_source;
+		spec->input_mux = &ad1986a_automic_capture_source;
+		codec->patch_ops.unsol_event = ad1986a_automic_unsol_event;
+		codec->patch_ops.init = ad1986a_automic_init;
 		break;
 	case AD1986A_LAPTOP_AUTOMUTE:
 		spec->mixers[0] = ad1986a_laptop_automute_mixers;
@@ -1365,7 +1417,10 @@
 
 	if (! ad198x_eapd_put(kcontrol, ucontrol))
 		return 0;
-
+	/* change speaker pin appropriately */
+	snd_hda_codec_write(codec, 0x05, 0,
+			    AC_VERB_SET_PIN_WIDGET_CONTROL,
+			    spec->cur_eapd ? PIN_OUT : 0);
 	/* toggle HP mute appropriately */
 	snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0,
 				 HDA_AMP_MUTE,
@@ -2087,6 +2142,10 @@
 	{ } /* end */
 };
 
+static struct snd_kcontrol_new ad1989_spdif_out_mixers[] = {
+	HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
+	{ } /* end */
+};
 
 /*
  * initialization verbs
@@ -2187,6 +2246,13 @@
 	{ }
 };
 
+/* AD1989 has no ADC -> SPDIF route */
+static struct hda_verb ad1989_spdif_init_verbs[] = {
+	/* SPDIF out pin */
+	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
+	{ }
+};
+
 /*
  * verbs for 3stack (+dig)
  */
@@ -2894,10 +2960,19 @@
 	spec->mixers[spec->num_mixers++] = ad1988_capture_mixers;
 	spec->init_verbs[spec->num_init_verbs++] = ad1988_capture_init_verbs;
 	if (spec->multiout.dig_out_nid) {
-		spec->mixers[spec->num_mixers++] = ad1988_spdif_out_mixers;
-		spec->init_verbs[spec->num_init_verbs++] = ad1988_spdif_init_verbs;
+		if (codec->vendor_id >= 0x11d4989a) {
+			spec->mixers[spec->num_mixers++] =
+				ad1989_spdif_out_mixers;
+			spec->init_verbs[spec->num_init_verbs++] =
+				ad1989_spdif_init_verbs;
+		} else {
+			spec->mixers[spec->num_mixers++] =
+				ad1988_spdif_out_mixers;
+			spec->init_verbs[spec->num_init_verbs++] =
+				ad1988_spdif_init_verbs;
+		}
 	}
-	if (spec->dig_in_nid)
+	if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a)
 		spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers;
 
 	codec->patch_ops = ad198x_patch_ops;
@@ -3133,11 +3208,12 @@
  * Lenovo Thinkpad T61/X61
  */
 static struct hda_input_mux ad1984_thinkpad_capture_source = {
-	.num_items = 3,
+	.num_items = 4,
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Internal Mic", 0x1 },
 		{ "Mix", 0x3 },
+		{ "Docking-Station", 0x4 },
 	},
 };
 
@@ -3268,8 +3344,7 @@
 				   struct hda_codec *codec,
 				   struct snd_pcm_substream *substream)
 {
-	snd_hda_codec_setup_stream(codec, 0x05 + substream->number,
-				   0, 0, 0);
+	snd_hda_codec_cleanup_stream(codec, 0x05 + substream->number);
 	return 0;
 }
 
@@ -3356,6 +3431,472 @@
 
 
 /*
+ * AD1883 / AD1884A / AD1984A / AD1984B
+ *
+ * port-B (0x14) - front mic-in
+ * port-E (0x1c) - rear mic-in
+ * port-F (0x16) - CD / ext out
+ * port-C (0x15) - rear line-in
+ * port-D (0x12) - rear line-out
+ * port-A (0x11) - front hp-out
+ *
+ * AD1984A = AD1884A + digital-mic
+ * AD1883 = equivalent with AD1984A
+ * AD1984B = AD1984A + extra SPDIF-out
+ *
+ * FIXME:
+ * We share the single DAC for both HP and line-outs (see AD1884/1984).
+ */
+
+static hda_nid_t ad1884a_dac_nids[1] = {
+	0x03,
+};
+
+#define ad1884a_adc_nids	ad1884_adc_nids
+#define ad1884a_capsrc_nids	ad1884_capsrc_nids
+
+#define AD1884A_SPDIF_OUT	0x02
+
+static struct hda_input_mux ad1884a_capture_source = {
+	.num_items = 5,
+	.items = {
+		{ "Front Mic", 0x0 },
+		{ "Mic", 0x4 },
+		{ "Line", 0x1 },
+		{ "CD", 0x2 },
+		{ "Mix", 0x3 },
+	},
+};
+
+static struct snd_kcontrol_new ad1884a_base_mixers[] = {
+	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
+	HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
+	HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
+	HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line Boost", 0x15, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x25, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* The multiple "Capture Source" controls confuse alsamixer
+		 * So call somewhat different..
+		 */
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 2,
+		.info = ad198x_mux_enum_info,
+		.get = ad198x_mux_enum_get,
+		.put = ad198x_mux_enum_put,
+	},
+	/* SPDIF controls */
+	HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
+		/* identical with ad1983 */
+		.info = ad1983_spdif_route_info,
+		.get = ad1983_spdif_route_get,
+		.put = ad1983_spdif_route_put,
+	},
+	{ } /* end */
+};
+
+/*
+ * initialization verbs
+ */
+static struct hda_verb ad1884a_init_verbs[] = {
+	/* DACs; unmute as default */
+	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
+	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
+	/* Port-A (HP) mixer - route only from analog mixer */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	/* Port-A pin */
+	{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Port-D (Line-out) mixer - route only from analog mixer */
+	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	/* Port-D pin */
+	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Mono-out mixer - route only from analog mixer */
+	{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	/* Mono-out pin */
+	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Port-B (front mic) pin */
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Port-C (rear line-in) pin */
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Port-E (rear mic) pin */
+	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	{0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* no boost */
+	/* Port-F (CD) pin */
+	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Analog mixer; mute as default */
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, /* aux */
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
+	/* Analog Mix output amp */
+	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* capture sources */
+	{0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	{0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* SPDIF output amp */
+	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
+	{ } /* end */
+};
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static struct hda_amp_list ad1884a_loopbacks[] = {
+	{ 0x20, HDA_INPUT, 0 }, /* Front Mic */
+	{ 0x20, HDA_INPUT, 1 }, /* Mic */
+	{ 0x20, HDA_INPUT, 2 }, /* CD */
+	{ 0x20, HDA_INPUT, 4 }, /* Docking */
+	{ } /* end */
+};
+#endif
+
+/*
+ * Laptop model
+ *
+ * Port A: Headphone jack
+ * Port B: MIC jack
+ * Port C: Internal MIC
+ * Port D: Dock Line Out (if enabled)
+ * Port E: Dock Line In (if enabled)
+ * Port F: Internal speakers
+ */
+
+static struct hda_input_mux ad1884a_laptop_capture_source = {
+	.num_items = 4,
+	.items = {
+		{ "Mic", 0x0 },		/* port-B */
+		{ "Internal Mic", 0x1 }, /* port-C */
+		{ "Dock Mic", 0x4 },	/* port-E */
+		{ "Mix", 0x3 },
+	},
+};
+
+static struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
+	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Dock Playback Switch", 0x12, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
+	HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
+	HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
+	HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
+	HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
+	HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Dock Mic Boost", 0x25, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* The multiple "Capture Source" controls confuse alsamixer
+		 * So call somewhat different..
+		 */
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 2,
+		.info = ad198x_mux_enum_info,
+		.get = ad198x_mux_enum_get,
+		.put = ad198x_mux_enum_put,
+	},
+	{ } /* end */
+};
+
+static struct hda_input_mux ad1884a_mobile_capture_source = {
+	.num_items = 2,
+	.items = {
+		{ "Mic", 0x1 }, /* port-C */
+		{ "Mix", 0x3 },
+	},
+};
+
+static struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
+	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
+	HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
+	HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
+	HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x15, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Capture Source",
+		.info = ad198x_mux_enum_info,
+		.get = ad198x_mux_enum_get,
+		.put = ad198x_mux_enum_put,
+	},
+	{ } /* end */
+};
+
+/* mute internal speaker if HP is plugged */
+static void ad1884a_hp_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+
+	present = snd_hda_codec_read(codec, 0x11, 0,
+				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
+				 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+	snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
+			    present ? 0x00 : 0x02);
+}
+
+#define AD1884A_HP_EVENT		0x37
+
+/* unsolicited event for HP jack sensing */
+static void ad1884a_hp_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+	if ((res >> 26) != AD1884A_HP_EVENT)
+		return;
+	ad1884a_hp_automute(codec);
+}
+
+/* initialize jack-sensing, too */
+static int ad1884a_hp_init(struct hda_codec *codec)
+{
+	ad198x_init(codec);
+	ad1884a_hp_automute(codec);
+	return 0;
+}
+
+/* additional verbs for laptop model */
+static struct hda_verb ad1884a_laptop_verbs[] = {
+	/* Port-A (HP) pin - always unmuted */
+	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	/* Port-F (int speaker) mixer - route only from analog mixer */
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	/* Port-F pin */
+	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* analog mix */
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+	/* unsolicited event for pin-sense */
+	{0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
+	{ } /* end */
+};
+
+/*
+ * Thinkpad X300
+ * 0x11 - HP
+ * 0x12 - speaker
+ * 0x14 - mic-in
+ * 0x17 - built-in mic
+ */
+
+static struct hda_verb ad1984a_thinkpad_verbs[] = {
+	/* HP unmute */
+	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	/* analog mix */
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+	/* turn on EAPD */
+	{0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
+	/* unsolicited event for pin-sense */
+	{0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
+	/* internal mic - dmic */
+	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	/* set magic COEFs for dmic */
+	{0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
+	{0x01, AC_VERB_SET_PROC_COEF, 0x08},
+	{ } /* end */
+};
+
+static struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = {
+	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
+	HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
+	HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
+	HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Internal Mic Boost", 0x17, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Capture Source",
+		.info = ad198x_mux_enum_info,
+		.get = ad198x_mux_enum_get,
+		.put = ad198x_mux_enum_put,
+	},
+	{ } /* end */
+};
+
+static struct hda_input_mux ad1984a_thinkpad_capture_source = {
+	.num_items = 3,
+	.items = {
+		{ "Mic", 0x0 },
+		{ "Internal Mic", 0x5 },
+		{ "Mix", 0x3 },
+	},
+};
+
+/* mute internal speaker if HP is plugged */
+static void ad1984a_thinkpad_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+
+	present = snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0)
+		& AC_PINSENSE_PRESENCE;
+	snd_hda_codec_amp_stereo(codec, 0x12, HDA_OUTPUT, 0,
+				 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+}
+
+/* unsolicited event for HP jack sensing */
+static void ad1984a_thinkpad_unsol_event(struct hda_codec *codec,
+					 unsigned int res)
+{
+	if ((res >> 26) != AD1884A_HP_EVENT)
+		return;
+	ad1984a_thinkpad_automute(codec);
+}
+
+/* initialize jack-sensing, too */
+static int ad1984a_thinkpad_init(struct hda_codec *codec)
+{
+	ad198x_init(codec);
+	ad1984a_thinkpad_automute(codec);
+	return 0;
+}
+
+/*
+ */
+
+enum {
+	AD1884A_DESKTOP,
+	AD1884A_LAPTOP,
+	AD1884A_MOBILE,
+	AD1884A_THINKPAD,
+	AD1884A_MODELS
+};
+
+static const char *ad1884a_models[AD1884A_MODELS] = {
+	[AD1884A_DESKTOP]	= "desktop",
+	[AD1884A_LAPTOP]	= "laptop",
+	[AD1884A_MOBILE]	= "mobile",
+	[AD1884A_THINKPAD]	= "thinkpad",
+};
+
+static struct snd_pci_quirk ad1884a_cfg_tbl[] = {
+	SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE),
+	SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD),
+	{}
+};
+
+static int patch_ad1884a(struct hda_codec *codec)
+{
+	struct ad198x_spec *spec;
+	int board_config;
+
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	mutex_init(&spec->amp_mutex);
+	codec->spec = spec;
+
+	spec->multiout.max_channels = 2;
+	spec->multiout.num_dacs = ARRAY_SIZE(ad1884a_dac_nids);
+	spec->multiout.dac_nids = ad1884a_dac_nids;
+	spec->multiout.dig_out_nid = AD1884A_SPDIF_OUT;
+	spec->num_adc_nids = ARRAY_SIZE(ad1884a_adc_nids);
+	spec->adc_nids = ad1884a_adc_nids;
+	spec->capsrc_nids = ad1884a_capsrc_nids;
+	spec->input_mux = &ad1884a_capture_source;
+	spec->num_mixers = 1;
+	spec->mixers[0] = ad1884a_base_mixers;
+	spec->num_init_verbs = 1;
+	spec->init_verbs[0] = ad1884a_init_verbs;
+	spec->spdif_route = 0;
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+	spec->loopback.amplist = ad1884a_loopbacks;
+#endif
+	codec->patch_ops = ad198x_patch_ops;
+
+	/* override some parameters */
+	board_config = snd_hda_check_board_config(codec, AD1884A_MODELS,
+						  ad1884a_models,
+						  ad1884a_cfg_tbl);
+	switch (board_config) {
+	case AD1884A_LAPTOP:
+		spec->mixers[0] = ad1884a_laptop_mixers;
+		spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs;
+		spec->multiout.dig_out_nid = 0;
+		spec->input_mux = &ad1884a_laptop_capture_source;
+		codec->patch_ops.unsol_event = ad1884a_hp_unsol_event;
+		codec->patch_ops.init = ad1884a_hp_init;
+		break;
+	case AD1884A_MOBILE:
+		spec->mixers[0] = ad1884a_mobile_mixers;
+		spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs;
+		spec->multiout.dig_out_nid = 0;
+		spec->input_mux = &ad1884a_mobile_capture_source;
+		codec->patch_ops.unsol_event = ad1884a_hp_unsol_event;
+		codec->patch_ops.init = ad1884a_hp_init;
+		break;
+	case AD1884A_THINKPAD:
+		spec->mixers[0] = ad1984a_thinkpad_mixers;
+		spec->init_verbs[spec->num_init_verbs++] =
+			ad1984a_thinkpad_verbs;
+		spec->multiout.dig_out_nid = 0;
+		spec->input_mux = &ad1984a_thinkpad_capture_source;
+		codec->patch_ops.unsol_event = ad1984a_thinkpad_unsol_event;
+		codec->patch_ops.init = ad1984a_thinkpad_init;
+		break;
+	}
+
+	return 0;
+}
+
+
+/*
  * AD1882
  *
  * port-A - front hp-out
@@ -3654,13 +4195,19 @@
  * patch entries
  */
 struct hda_codec_preset snd_hda_preset_analog[] = {
+	{ .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a },
 	{ .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 },
+	{ .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a },
 	{ .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 },
+	{ .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884a },
+	{ .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884a },
 	{ .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 },
 	{ .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 },
 	{ .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1984 },
 	{ .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a },
 	{ .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 },
 	{ .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 },
+	{ .id = 0x11d4989a, .name = "AD1989A", .patch = patch_ad1988 },
+	{ .id = 0x11d4989b, .name = "AD1989B", .patch = patch_ad1988 },
 	{} /* terminator */
 };
diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c
index 9a8bb4c..1227250 100644
--- a/sound/pci/hda/patch_atihdmi.c
+++ b/sound/pci/hda/patch_atihdmi.c
@@ -27,6 +27,7 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_patch.h"
 
 struct atihdmi_spec {
 	struct hda_multi_out multiout;
@@ -58,6 +59,10 @@
 static int atihdmi_init(struct hda_codec *codec)
 {
 	snd_hda_sequence_write(codec, atihdmi_basic_init);
+	/* SI codec requires to unmute the pin */
+	if (get_wcaps(codec, 0x03) & AC_WCAP_OUT_AMP)
+		snd_hda_codec_write(codec, 0x03, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+				    AMP_OUT_UNMUTE);
 	return 0;
 }
 
@@ -112,6 +117,7 @@
 	codec->pcm_info = info;
 
 	info->name = "ATI HDMI";
+	info->pcm_type = HDA_PCM_TYPE_HDMI;
 	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = atihdmi_pcm_digital_playback;
 
 	return 0;
@@ -158,5 +164,7 @@
 	{ .id = 0x10027919, .name = "ATI RS600 HDMI", .patch = patch_atihdmi },
 	{ .id = 0x1002791a, .name = "ATI RS690/780 HDMI", .patch = patch_atihdmi },
 	{ .id = 0x1002aa01, .name = "ATI R6xx HDMI", .patch = patch_atihdmi },
+	{ .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_atihdmi },
+	{ .id = 0x17e80047, .name = "Chrontel HDMI",  .patch = patch_atihdmi },
 	{} /* terminator */
 };
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c
index 3d6097b..c73ce07 100644
--- a/sound/pci/hda/patch_cmedia.c
+++ b/sound/pci/hda/patch_cmedia.c
@@ -28,6 +28,7 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_patch.h"
 #define NUM_PINS	11
 
 
@@ -329,6 +330,11 @@
 		err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
 		if (err < 0)
 			return err;
+		err = snd_hda_create_spdif_share_sw(codec,
+						    &spec->multiout);
+		if (err < 0)
+			return err;
+		spec->multiout.share_spdif = 1;
 	}
 	if (spec->dig_in_nid) {
 		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
@@ -432,7 +438,8 @@
 				     struct snd_pcm_substream *substream)
 {
 	struct cmi_spec *spec = codec->spec;
-	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
+					     hinfo);
 }
 
 static int cmi9880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
@@ -506,7 +513,7 @@
 {
 	struct cmi_spec *spec = codec->spec;
 
-	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0);
+	snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
 	return 0;
 }
 
@@ -571,6 +578,7 @@
 		codec->num_pcms++;
 		info++;
 		info->name = "CMI9880 Digital";
+		info->pcm_type = HDA_PCM_TYPE_SPDIF;
 		if (spec->multiout.dig_out_nid) {
 			info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cmi9880_pcm_digital_playback;
 			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
@@ -603,6 +611,7 @@
 
 static struct snd_pci_quirk cmi9880_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", CMI_FULL_DIG),
+	SND_PCI_QUIRK(0x1854, 0x0032, "LG", CMI_FULL_DIG),
 	{} /* terminator */
 };
 
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 7206b30..36fd852 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -27,6 +27,7 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_patch.h"
 
 #define CXT_PIN_DIR_IN              0x00
 #define CXT_PIN_DIR_OUT             0x01
@@ -98,7 +99,8 @@
 				      struct snd_pcm_substream *substream)
 {
 	struct conexant_spec *spec = codec->spec;
-	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
+					     hinfo);
 }
 
 static int conexant_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
@@ -172,8 +174,7 @@
 				      struct snd_pcm_substream *substream)
 {
 	struct conexant_spec *spec = codec->spec;
-	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
-				   0, 0, 0);
+	snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
 	return 0;
 }
 
@@ -241,7 +242,7 @@
 				      struct snd_pcm_substream *substream)
 {
 	struct conexant_spec *spec = codec->spec;
-	snd_hda_codec_setup_stream(codec, spec->cur_adc, 0, 0, 0);
+	snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
 	spec->cur_adc = 0;
 	return 0;
 }
@@ -284,6 +285,7 @@
 		info++;
 		codec->num_pcms++;
 		info->name = "Conexant Digital";
+		info->pcm_type = HDA_PCM_TYPE_SPDIF;
 		info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
 			conexant_pcm_digital_playback;
 		info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
@@ -371,6 +373,11 @@
 						    spec->multiout.dig_out_nid);
 		if (err < 0)
 			return err;
+		err = snd_hda_create_spdif_share_sw(codec,
+						    &spec->multiout);
+		if (err < 0)
+			return err;
+		spec->multiout.share_spdif = 1;
 	} 
 	if (spec->dig_in_nid) {
 		err = snd_hda_create_spdif_in_ctls(codec,spec->dig_in_nid);
@@ -511,6 +518,14 @@
 	}
 };
 
+static struct hda_input_mux cxt5045_capture_source_hp530 = {
+	.num_items = 2,
+	.items = {
+		{ "ExtMic", 0x1 },
+		{ "IntMic", 0x2 },
+	}
+};
+
 /* turn on/off EAPD (+ mute HP) as a master switch */
 static int cxt5045_hp_master_sw_put(struct snd_kcontrol *kcontrol,
 				    struct snd_ctl_elem_value *ucontrol)
@@ -639,6 +654,37 @@
 	{}
 };
 
+static struct snd_kcontrol_new cxt5045_mixers_hp530[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Capture Source",
+		.info = conexant_mux_enum_info,
+		.get = conexant_mux_enum_get,
+		.put = conexant_mux_enum_put
+	},
+	HDA_CODEC_VOLUME("Int Mic Capture Volume", 0x1a, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("Int Mic Capture Switch", 0x1a, 0x02, HDA_INPUT),
+	HDA_CODEC_VOLUME("Ext Mic Capture Volume", 0x1a, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("Ext Mic Capture Switch", 0x1a, 0x01, HDA_INPUT),
+	HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x17, 0x2, HDA_INPUT),
+	HDA_CODEC_MUTE("Int Mic Playback Switch", 0x17, 0x2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x17, 0x1, HDA_INPUT),
+	HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x17, 0x1, HDA_INPUT),
+	HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Switch",
+		.info = cxt_eapd_info,
+		.get = cxt_eapd_get,
+		.put = cxt5045_hp_master_sw_put,
+		.private_value = 0x10,
+	},
+
+	{}
+};
+
 static struct hda_verb cxt5045_init_verbs[] = {
 	/* Line in, Mic */
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
@@ -833,6 +879,7 @@
 	CXT5045_LAPTOP_MICSENSE,
 	CXT5045_LAPTOP_HPMICSENSE,
 	CXT5045_BENQ,
+	CXT5045_LAPTOP_HP530,
 #ifdef CONFIG_SND_DEBUG
 	CXT5045_TEST,
 #endif
@@ -844,6 +891,7 @@
 	[CXT5045_LAPTOP_MICSENSE]	= "laptop-micsense",
 	[CXT5045_LAPTOP_HPMICSENSE]	= "laptop-hpmicsense",
 	[CXT5045_BENQ]			= "benq",
+	[CXT5045_LAPTOP_HP530]		= "laptop-hp530",
 #ifdef CONFIG_SND_DEBUG
 	[CXT5045_TEST]		= "test",
 #endif
@@ -857,7 +905,7 @@
 	SND_PCI_QUIRK(0x103c, 0x30bb, "HP DV8000", CXT5045_LAPTOP_HPSENSE),
 	SND_PCI_QUIRK(0x103c, 0x30cd, "HP DV Series", CXT5045_LAPTOP_HPSENSE),
 	SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV9533EG", CXT5045_LAPTOP_HPSENSE),
-	SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HPSENSE),
+	SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530),
 	SND_PCI_QUIRK(0x103c, 0x30d9, "HP Spartan", CXT5045_LAPTOP_HPSENSE),
 	SND_PCI_QUIRK(0x152d, 0x0753, "Benq R55E", CXT5045_BENQ),
 	SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE),
@@ -941,6 +989,14 @@
 		spec->num_mixers = 2;
 		codec->patch_ops.init = cxt5045_init;
 		break;
+	case CXT5045_LAPTOP_HP530:
+		codec->patch_ops.unsol_event = cxt5045_hp_unsol_event;
+		spec->input_mux = &cxt5045_capture_source_hp530;
+		spec->num_init_verbs = 2;
+		spec->init_verbs[1] = cxt5045_hp_sense_init_verbs;
+		spec->mixers[0] = cxt5045_mixers_hp530;
+		codec->patch_ops.init = cxt5045_init;
+		break;
 #ifdef CONFIG_SND_DEBUG
 	case CXT5045_TEST:
 		spec->input_mux = &cxt5045_test_capture_source;
@@ -1537,7 +1593,7 @@
 	new_adc = spec->adc_nids[spec->cur_adc_idx];
 	if (spec->cur_adc && spec->cur_adc != new_adc) {
 		/* stream is running, let's swap the current ADC */
-		snd_hda_codec_setup_stream(codec, spec->cur_adc, 0, 0, 0);
+		snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
 		spec->cur_adc = new_adc;
 		snd_hda_codec_setup_stream(codec, new_adc,
 					   spec->cur_adc_stream_tag, 0,
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 33282f9..cdda64b 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -30,6 +30,7 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_patch.h"
 
 #define ALC880_FRONT_EVENT		0x01
 #define ALC880_DCVOL_EVENT		0x02
@@ -97,16 +98,19 @@
 	ALC262_SONY_ASSAMD,
 	ALC262_BENQ_T31,
 	ALC262_ULTRA,
+	ALC262_LENOVO_3000,
 	ALC262_AUTO,
 	ALC262_MODEL_LAST /* last tag */
 };
 
 /* ALC268 models */
 enum {
+	ALC267_QUANTA_IL1,
 	ALC268_3ST,
 	ALC268_TOSHIBA,
 	ALC268_ACER,
 	ALC268_DELL,
+	ALC268_ZEPTO,
 #ifdef CONFIG_SND_DEBUG
 	ALC268_TEST,
 #endif
@@ -195,10 +199,11 @@
 	ALC883_LENOVO_NB0763,
 	ALC888_LENOVO_MS7195_DIG,
 	ALC883_HAIER_W66,		
-	ALC888_6ST_HP,
 	ALC888_3ST_HP,
 	ALC888_6ST_DELL,
 	ALC883_MITAC,
+	ALC883_CLEVO_M720,
+	ALC883_FUJITSU_PI2515,
 	ALC883_AUTO,
 	ALC883_MODEL_LAST,
 };
@@ -237,6 +242,7 @@
 	/* capture */
 	unsigned int num_adc_nids;
 	hda_nid_t *adc_nids;
+	hda_nid_t *capsrc_nids;
 	hda_nid_t dig_in_nid;		/* digital-in NID; optional */
 
 	/* capture source */
@@ -270,7 +276,6 @@
 
 	/* for virtual master */
 	hda_nid_t vmaster_nid;
-	u32 vmaster_tlv[4];
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	struct hda_loopback_check loopback;
 #endif
@@ -290,6 +295,7 @@
 	hda_nid_t hp_nid;		/* optional */
 	unsigned int num_adc_nids;
 	hda_nid_t *adc_nids;
+	hda_nid_t *capsrc_nids;
 	hda_nid_t dig_in_nid;
 	unsigned int num_channel_mode;
 	const struct hda_channel_mode *channel_mode;
@@ -336,9 +342,10 @@
 	struct alc_spec *spec = codec->spec;
 	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 	unsigned int mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
+	hda_nid_t nid = spec->capsrc_nids ?
+		spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
 	return snd_hda_input_mux_put(codec, &spec->input_mux[mux_idx], ucontrol,
-				     spec->adc_nids[adc_idx],
-				     &spec->cur_mux[adc_idx]);
+				     nid, &spec->cur_mux[adc_idx]);
 }
 
 
@@ -707,6 +714,7 @@
 
 	spec->num_adc_nids = preset->num_adc_nids;
 	spec->adc_nids = preset->adc_nids;
+	spec->capsrc_nids = preset->capsrc_nids;
 	spec->dig_in_nid = preset->dig_in_nid;
 
 	spec->unsol_event = preset->unsol_event;
@@ -741,7 +749,6 @@
 static void alc_sku_automute(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
-	unsigned int mute;
 	unsigned int present;
 	unsigned int hp_nid = spec->autocfg.hp_pins[0];
 	unsigned int sp_nid = spec->autocfg.speaker_pins[0];
@@ -751,16 +758,8 @@
 	present = snd_hda_codec_read(codec, hp_nid, 0,
 				     AC_VERB_GET_PIN_SENSE, 0);
 	spec->jack_present = (present & 0x80000000) != 0;
-	if (spec->jack_present) {
-		/* mute internal speaker */
-		snd_hda_codec_amp_stereo(codec, sp_nid, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, HDA_AMP_MUTE);
-	} else {
-		/* unmute internal speaker if necessary */
-		mute = snd_hda_codec_amp_read(codec, hp_nid, 0, HDA_OUTPUT, 0);
-		snd_hda_codec_amp_stereo(codec, sp_nid, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, mute);
-	}
+	snd_hda_codec_write(codec, sp_nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+			    spec->jack_present ? 0 : PIN_OUT);
 }
 
 /* unsolicited event for HP jack sensing */
@@ -1319,11 +1318,19 @@
 	HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
 	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
 	{ } /* end */
 };
 
+static struct hda_input_mux alc880_f1734_capture_source = {
+	.num_items = 2,
+	.items = {
+		{ "Mic", 0x1 },
+		{ "CD", 0x4 },
+	},
+};
+
 
 /*
  * ALC880 ASUS model
@@ -1516,6 +1523,11 @@
 						    spec->multiout.dig_out_nid);
 		if (err < 0)
 			return err;
+		err = snd_hda_create_spdif_share_sw(codec,
+						    &spec->multiout);
+		if (err < 0)
+			return err;
+		spec->multiout.share_spdif = 1;
 	}
 	if (spec->dig_in_nid) {
 		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
@@ -1525,10 +1537,11 @@
 
 	/* if we have no master control, let's create it */
 	if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
+		unsigned int vmaster_tlv[4];
 		snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
-					HDA_OUTPUT, spec->vmaster_tlv);
+					HDA_OUTPUT, vmaster_tlv);
 		err = snd_hda_add_vmaster(codec, "Master Playback Volume",
-					  spec->vmaster_tlv, alc_slave_vols);
+					  vmaster_tlv, alc_slave_vols);
 		if (err < 0)
 			return err;
 	}
@@ -1882,7 +1895,7 @@
  	present = snd_hda_codec_read(codec, 0x14, 0,
 				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
 	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x15, HDA_INPUT, 0, HDA_AMP_MUTE, bits);
+	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, HDA_AMP_MUTE, bits);
 }
 
 static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
@@ -1915,6 +1928,7 @@
  * HP = 0x14, speaker-out = 0x15, mic = 0x18
  */
 static struct hda_verb alc880_pin_f1734_init_verbs[] = {
+	{0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
 	{0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
@@ -1927,7 +1941,7 @@
 
 	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
 	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
@@ -1935,6 +1949,9 @@
 	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 
+	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
+	{0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
+
 	{ }
 };
 
@@ -2318,7 +2335,8 @@
 				    struct snd_pcm_substream *substream)
 {
 	struct alc_spec *spec = codec->spec;
-	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
+					     hinfo);
 }
 
 static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
@@ -2392,8 +2410,8 @@
 {
 	struct alc_spec *spec = codec->spec;
 
-	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
-				   0, 0, 0);
+	snd_hda_codec_cleanup_stream(codec,
+				     spec->adc_nids[substream->number + 1]);
 	return 0;
 }
 
@@ -2498,6 +2516,7 @@
 		codec->num_pcms = 2;
 		info = spec->pcm_rec + 1;
 		info->name = spec->stream_name_digital;
+		info->pcm_type = HDA_PCM_TYPE_SPDIF;
 		if (spec->multiout.dig_out_nid &&
 		    spec->stream_digital_playback) {
 			info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
@@ -2560,6 +2579,7 @@
 		kfree(spec->kctl_alloc);
 	}
 	kfree(spec);
+	codec->spec = NULL; /* to be sure */
 }
 
 /*
@@ -3057,7 +3077,9 @@
 		.hp_nid = 0x02,
 		.num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
 		.channel_mode = alc880_2_jack_modes,
-		.input_mux = &alc880_capture_source,
+		.input_mux = &alc880_f1734_capture_source,
+		.unsol_event = alc880_uniwill_p53_unsol_event,
+		.init_hook = alc880_uniwill_p53_hp_automute,
 	},
 	[ALC880_ASUS] = {
 		.mixers = { alc880_asus_mixer },
@@ -3467,15 +3489,21 @@
 	return 0;
 }
 
+static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
+			       unsigned int pin_type)
+{
+	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+			    pin_type);
+	/* unmute pin */
+	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+			    AMP_OUT_UNMUTE);
+}
+
 static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
 					      hda_nid_t nid, int pin_type,
 					      int dac_idx)
 {
-	/* set as output */
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    pin_type);
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-			    AMP_OUT_UNMUTE);
+	alc_set_pin_output(codec, nid, pin_type);
 	/* need the manual connection? */
 	if (alc880_is_multi_pin(nid)) {
 		struct alc_spec *spec = codec->spec;
@@ -3597,9 +3625,12 @@
 /* additional initialization for auto-configuration model */
 static void alc880_auto_init(struct hda_codec *codec)
 {
+	struct alc_spec *spec = codec->spec;
 	alc880_auto_init_multi_out(codec);
 	alc880_auto_init_extra_out(codec);
 	alc880_auto_init_analog_input(codec);
+	if (spec->unsol_event)
+		alc_sku_automute(codec);
 }
 
 /*
@@ -4795,11 +4826,7 @@
 					      hda_nid_t nid, int pin_type,
 					      int sel_idx)
 {
-	/* set as output */
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    pin_type);
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-			    AMP_OUT_UNMUTE);
+	alc_set_pin_output(codec, nid, pin_type);
 	/* need the manual connection? */
 	if (nid >= 0x12) {
 		int idx = nid - 0x12;
@@ -4929,7 +4956,7 @@
 	/* check whether NID 0x04 is valid */
 	wcap = get_wcaps(codec, 0x04);
 	wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */
-	if (wcap != AC_WID_AUD_IN) {
+	if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
 		spec->adc_nids = alc260_adc_nids_alt;
 		spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
 		spec->mixers[spec->num_mixers] = alc260_capture_alt_mixer;
@@ -4946,8 +4973,11 @@
 /* additional initialization for auto-configuration model */
 static void alc260_auto_init(struct hda_codec *codec)
 {
+	struct alc_spec *spec = codec->spec;
 	alc260_auto_init_multi_out(codec);
 	alc260_auto_init_analog_input(codec);
+	if (spec->unsol_event)
+		alc_sku_automute(codec);
 }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -5204,6 +5234,9 @@
 #define alc882_adc_nids		alc880_adc_nids
 #define alc882_adc_nids_alt	alc880_adc_nids_alt
 
+static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
+static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
+
 /* input MUX */
 /* FIXME: should be a matrix-type input source selection */
 
@@ -5226,15 +5259,11 @@
 	struct alc_spec *spec = codec->spec;
 	const struct hda_input_mux *imux = spec->input_mux;
 	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-	static hda_nid_t capture_mixers[3] = { 0x24, 0x23, 0x22 };
-	hda_nid_t nid;
+	hda_nid_t nid = spec->capsrc_nids ?
+		spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
 	unsigned int *cur_val = &spec->cur_mux[adc_idx];
 	unsigned int i, idx;
 
-	if (spec->num_adc_nids < 3)
-		nid = capture_mixers[adc_idx + 1];
-	else
-		nid = capture_mixers[adc_idx];
 	idx = ucontrol->value.enumerated.item[0];
 	if (idx >= imux->num_items)
 		idx = imux->num_items - 1;
@@ -6111,6 +6140,7 @@
 		.dig_out_nid = ALC882_DIGOUT_NID,
 		.num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
 		.adc_nids = alc882_adc_nids,
+		.capsrc_nids = alc882_capsrc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
 		.channel_mode = alc882_3ST_6ch_modes,
 		.need_dac_fix = 1,
@@ -6127,6 +6157,7 @@
 		.dig_out_nid = ALC882_DIGOUT_NID,
 		.num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
 		.adc_nids = alc882_adc_nids,
+		.capsrc_nids = alc882_capsrc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
 		.channel_mode = alc882_3ST_6ch_modes,
 		.need_dac_fix = 1,
@@ -6182,15 +6213,11 @@
 	struct alc_spec *spec = codec->spec;
 	int idx;
 
+	alc_set_pin_output(codec, nid, pin_type);
 	if (spec->multiout.dac_nids[dac_idx] == 0x25)
 		idx = 4;
 	else
 		idx = spec->multiout.dac_nids[dac_idx] - 2;
-
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    pin_type);
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-			    AMP_OUT_UNMUTE);
 	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
 
 }
@@ -6219,6 +6246,9 @@
 	if (pin) /* connect to front */
 		/* use dac 0 */
 		alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+	pin = spec->autocfg.speaker_pins[0];
+	if (pin)
+		alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
 }
 
 #define alc882_is_input_pin(nid)	alc880_is_input_pin(nid)
@@ -6231,16 +6261,21 @@
 
 	for (i = 0; i < AUTO_PIN_LAST; i++) {
 		hda_nid_t nid = spec->autocfg.input_pins[i];
-		if (alc882_is_input_pin(nid)) {
-			snd_hda_codec_write(codec, nid, 0,
-					    AC_VERB_SET_PIN_WIDGET_CONTROL,
-					    i <= AUTO_PIN_FRONT_MIC ?
-					    PIN_VREF80 : PIN_IN);
-			if (nid != ALC882_PIN_CD_NID)
-				snd_hda_codec_write(codec, nid, 0,
-						    AC_VERB_SET_AMP_GAIN_MUTE,
-						    AMP_OUT_MUTE);
+		unsigned int vref;
+		if (!nid)
+			continue;
+		vref = PIN_IN;
+		if (1 /*i <= AUTO_PIN_FRONT_MIC*/) {
+			if (snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP) &
+			    AC_PINCAP_VREF_80)
+				vref = PIN_VREF80;
 		}
+		snd_hda_codec_write(codec, nid, 0,
+				    AC_VERB_SET_PIN_WIDGET_CONTROL, vref);
+		if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
+			snd_hda_codec_write(codec, nid, 0,
+					    AC_VERB_SET_AMP_GAIN_MUTE,
+					    AMP_OUT_MUTE);
 	}
 }
 
@@ -6294,11 +6329,16 @@
 /* additional initialization for auto-configuration model */
 static void alc882_auto_init(struct hda_codec *codec)
 {
+	struct alc_spec *spec = codec->spec;
 	alc882_auto_init_multi_out(codec);
 	alc882_auto_init_hp_out(codec);
 	alc882_auto_init_analog_input(codec);
+	if (spec->unsol_event)
+		alc_sku_automute(codec);
 }
 
+static int patch_alc883(struct hda_codec *codec); /* called in patch_alc882() */
+
 static int patch_alc882(struct hda_codec *codec)
 {
 	struct alc_spec *spec;
@@ -6328,6 +6368,11 @@
 			board_config = ALC885_MBP3;
 			break;
 		default:
+			/* ALC889A is handled better as ALC888-compatible */
+			if (codec->revision_id == 0x100103) {
+				alc_free(codec);
+				return patch_alc883(codec);
+			}
 			printk(KERN_INFO "hda_codec: Unknown model for ALC882, "
 		       			 "trying auto-probe from BIOS...\n");
 			board_config = ALC882_AUTO;
@@ -6372,12 +6417,14 @@
 		if (wcap != AC_WID_AUD_IN) {
 			spec->adc_nids = alc882_adc_nids_alt;
 			spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt);
+			spec->capsrc_nids = alc882_capsrc_nids_alt;
 			spec->mixers[spec->num_mixers] =
 				alc882_capture_alt_mixer;
 			spec->num_mixers++;
 		} else {
 			spec->adc_nids = alc882_adc_nids;
 			spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids);
+			spec->capsrc_nids = alc882_capsrc_nids;
 			spec->mixers[spec->num_mixers] = alc882_capture_mixer;
 			spec->num_mixers++;
 		}
@@ -6412,7 +6459,7 @@
 
 static hda_nid_t alc883_dac_nids[4] = {
 	/* front, rear, clfe, rear_surr */
-	0x02, 0x04, 0x03, 0x05
+	0x02, 0x03, 0x04, 0x05
 };
 
 static hda_nid_t alc883_adc_nids[2] = {
@@ -6420,6 +6467,8 @@
 	0x08, 0x09,
 };
 
+static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 };
+
 /* input MUX */
 /* FIXME: should be a matrix-type input source selection */
 
@@ -6451,35 +6500,18 @@
 	},
 };
 
+static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
+	.num_items = 2,
+	.items = {
+		{ "Mic", 0x0 },
+		{ "Int Mic", 0x1 },
+	},
+};
+
 #define alc883_mux_enum_info alc_mux_enum_info
 #define alc883_mux_enum_get alc_mux_enum_get
-
-static int alc883_mux_enum_put(struct snd_kcontrol *kcontrol,
-			       struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct alc_spec *spec = codec->spec;
-	const struct hda_input_mux *imux = spec->input_mux;
-	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-	static hda_nid_t capture_mixers[2] = { 0x23, 0x22 };
-	hda_nid_t nid = capture_mixers[adc_idx];
-	unsigned int *cur_val = &spec->cur_mux[adc_idx];
-	unsigned int i, idx;
-
-	idx = ucontrol->value.enumerated.item[0];
-	if (idx >= imux->num_items)
-		idx = imux->num_items - 1;
-	if (*cur_val == idx)
-		return 0;
-	for (i = 0; i < imux->num_items; i++) {
-		unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
-		snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
-					 imux->items[i].index,
-					 HDA_AMP_MUTE, v);
-	}
-	*cur_val = idx;
-	return 1;
-}
+/* ALC883 has the ALC882-type input selection */
+#define alc883_mux_enum_put alc882_mux_enum_put
 
 /*
  * 2ch mode
@@ -6638,6 +6670,60 @@
 	{ } /* end */
 };
 
+static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
+	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 2,
+		.info = alc883_mux_enum_info,
+		.get = alc883_mux_enum_get,
+		.put = alc883_mux_enum_put,
+	},
+	{ } /* end */
+};
+
+static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
+	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 2,
+		.info = alc883_mux_enum_info,
+		.get = alc883_mux_enum_get,
+		.put = alc883_mux_enum_put,
+	},
+	{ } /* end */
+};
+
 static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
@@ -6787,6 +6873,9 @@
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
 	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
@@ -6878,124 +6967,6 @@
 	{ } /* end */
 };	
 
-static struct snd_kcontrol_new alc888_6st_hp_mixer[] = {
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
-	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
-	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-	HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
-	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 2,
-		.info = alc883_mux_enum_info,
-		.get = alc883_mux_enum_get,
-		.put = alc883_mux_enum_put,
-	},
-	{ } /* end */
-};
-
-static struct snd_kcontrol_new alc888_3st_hp_mixer[] = {
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
-	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
-	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-	HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
-	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 2,
-		.info = alc883_mux_enum_info,
-		.get = alc883_mux_enum_get,
-		.put = alc883_mux_enum_put,
-	},
-	{ } /* end */
-};
-
-static struct snd_kcontrol_new alc888_6st_dell_mixer[] = {
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
-	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
-	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-	HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
-	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 2,
-		.info = alc883_mux_enum_info,
-		.get = alc883_mux_enum_get,
-		.put = alc883_mux_enum_put,
-	},
-	{ } /* end */
-};
-
 static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
@@ -7171,6 +7142,35 @@
 	{ } /* end */
 };
 
+static struct hda_verb alc883_clevo_m720_verbs[] = {
+	/* HP */
+	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	/* Int speaker */
+	{0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+
+	/* enable unsolicited event */
+	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
+
+	{ } /* end */
+};
+
+static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
+	/* HP */
+	{0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	/* Subwoofer */
+	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+
+	/* enable unsolicited event */
+	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+
+	{ } /* end */
+};
+
 static struct hda_verb alc883_tagra_verbs[] = {
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -7227,26 +7227,14 @@
 	{ } /* end */
 };
 
-static struct hda_verb alc888_6st_hp_verbs[] = {
-	{0x14, AC_VERB_SET_CONNECT_SEL, 0x00},	/* Front: output 0 (0x0c) */
-	{0x15, AC_VERB_SET_CONNECT_SEL, 0x02},	/* Rear : output 2 (0x0e) */
-	{0x16, AC_VERB_SET_CONNECT_SEL, 0x01},	/* CLFE : output 1 (0x0d) */
-	{0x17, AC_VERB_SET_CONNECT_SEL, 0x03},	/* Side : output 3 (0x0f) */
-	{ }
-};
-
 static struct hda_verb alc888_3st_hp_verbs[] = {
 	{0x14, AC_VERB_SET_CONNECT_SEL, 0x00},	/* Front: output 0 (0x0c) */
-	{0x18, AC_VERB_SET_CONNECT_SEL, 0x01},	/* Rear : output 1 (0x0d) */
-	{0x16, AC_VERB_SET_CONNECT_SEL, 0x02},	/* CLFE : output 2 (0x0e) */
+	{0x16, AC_VERB_SET_CONNECT_SEL, 0x01},	/* Rear : output 1 (0x0d) */
+	{0x18, AC_VERB_SET_CONNECT_SEL, 0x02},	/* CLFE : output 2 (0x0e) */
 	{ }
 };
 
 static struct hda_verb alc888_6st_dell_verbs[] = {
-	{0x14, AC_VERB_SET_CONNECT_SEL, 0x00},	/* Front: output 0 (0x0c) */
-	{0x15, AC_VERB_SET_CONNECT_SEL, 0x02},	/* Rear : output 1 (0x0e) */
-	{0x16, AC_VERB_SET_CONNECT_SEL, 0x01},	/* CLFE : output 2 (0x0d) */
-	{0x17, AC_VERB_SET_CONNECT_SEL, 0x03},	/* Side : output 3 (0x0f) */
 	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
 	{ }
 };
@@ -7354,6 +7342,68 @@
 		alc883_tagra_automute(codec);
 }
 
+/* toggle speaker-output according to the hp-jack state */
+static void alc883_clevo_m720_hp_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+	unsigned char bits;
+
+	present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0)
+		& AC_PINSENSE_PRESENCE;
+	bits = present ? HDA_AMP_MUTE : 0;
+	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+				 HDA_AMP_MUTE, bits);
+}
+
+static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+
+	present = snd_hda_codec_read(codec, 0x18, 0,
+				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
+				 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+}
+
+static void alc883_clevo_m720_automute(struct hda_codec *codec)
+{
+	alc883_clevo_m720_hp_automute(codec);
+	alc883_clevo_m720_mic_automute(codec);
+}
+
+static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
+					   unsigned int res)
+{
+	switch (res >> 26) {
+	case ALC880_HP_EVENT:
+		alc883_clevo_m720_hp_automute(codec);
+		break;
+	case ALC880_MIC_EVENT:
+		alc883_clevo_m720_mic_automute(codec);
+		break;
+	}
+}
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc883_2ch_fujitsu_pi2515_automute(struct hda_codec *codec)
+{
+ 	unsigned int present;
+	unsigned char bits;
+
+ 	present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0)
+		& AC_PINSENSE_PRESENCE;
+	bits = present ? HDA_AMP_MUTE : 0;
+	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
+				 HDA_AMP_MUTE, bits);
+}
+
+static void alc883_2ch_fujitsu_pi2515_unsol_event(struct hda_codec *codec,
+						  unsigned int res)
+{
+	if ((res >> 26) == ALC880_HP_EVENT)
+		alc883_2ch_fujitsu_pi2515_automute(codec);
+}
+
 static void alc883_haier_w66_automute(struct hda_codec *codec)
 {
 	unsigned int present;
@@ -7587,10 +7637,11 @@
 	[ALC883_LENOVO_NB0763]	= "lenovo-nb0763",
 	[ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
 	[ALC883_HAIER_W66] 	= "haier-w66",
-	[ALC888_6ST_HP]		= "6stack-hp",
 	[ALC888_3ST_HP]		= "3stack-hp",
 	[ALC888_6ST_DELL]	= "6stack-dell",
 	[ALC883_MITAC]		= "mitac",
+	[ALC883_CLEVO_M720]	= "clevo-m720",
+	[ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
 	[ALC883_AUTO]		= "auto",
 };
 
@@ -7604,7 +7655,7 @@
 	SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
 	SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
 	SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
-	SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC888_6ST_HP),
+	SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
 	SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
 	SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
 	SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
@@ -7614,7 +7665,9 @@
 	SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
 	SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
 	SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
+	SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC883_TARGA_2ch_DIG),
 	SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
+	SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
 	SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
 	SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
 	SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
@@ -7627,13 +7680,17 @@
 	SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
 	SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
 	SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
+	SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
 	SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
 	SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
 	SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
 	SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
+	SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
+	SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
 	SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD),
 	SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
 	SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
+	SND_PCI_QUIRK(0x1734, 0x1108, "Fujitsu AMILO Pi2515", ALC883_FUJITSU_PI2515),
 	SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
 	SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
 	SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
@@ -7652,8 +7709,6 @@
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
 		.dig_out_nid = ALC883_DIGOUT_NID,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.dig_in_nid = ALC883_DIGIN_NID,
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
@@ -7665,8 +7720,6 @@
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
 		.dig_out_nid = ALC883_DIGOUT_NID,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.dig_in_nid = ALC883_DIGIN_NID,
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
 		.channel_mode = alc883_3ST_6ch_modes,
@@ -7678,8 +7731,6 @@
 		.init_verbs = { alc883_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
 		.channel_mode = alc883_3ST_6ch_modes,
 		.need_dac_fix = 1,
@@ -7691,8 +7742,6 @@
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
 		.dig_out_nid = ALC883_DIGOUT_NID,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.dig_in_nid = ALC883_DIGIN_NID,
 		.num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
 		.channel_mode = alc883_sixstack_modes,
@@ -7704,8 +7753,6 @@
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
 		.dig_out_nid = ALC883_DIGOUT_NID,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
 		.channel_mode = alc883_3ST_6ch_modes,
 		.need_dac_fix = 1,
@@ -7719,8 +7766,6 @@
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
 		.dig_out_nid = ALC883_DIGOUT_NID,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
@@ -7737,8 +7782,6 @@
 		.init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
@@ -7749,8 +7792,6 @@
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
 		.dig_out_nid = ALC883_DIGOUT_NID,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
@@ -7764,8 +7805,6 @@
 				alc883_medion_eapd_verbs },
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
 		.channel_mode = alc883_sixstack_modes,
 		.input_mux = &alc883_capture_source,
@@ -7776,8 +7815,6 @@
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
 		.dig_out_nid = ALC883_DIGOUT_NID,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
@@ -7789,19 +7826,27 @@
 		.init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
 	},
+	[ALC883_CLEVO_M720] = {
+		.mixers = { alc883_clevo_m720_mixer },
+		.init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
+		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
+		.dac_nids = alc883_dac_nids,
+		.dig_out_nid = ALC883_DIGOUT_NID,
+		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+		.channel_mode = alc883_3ST_2ch_modes,
+		.input_mux = &alc883_capture_source,
+		.unsol_event = alc883_clevo_m720_unsol_event,
+		.init_hook = alc883_clevo_m720_automute,
+	},
 	[ALC883_LENOVO_101E_2ch] = {
 		.mixers = { alc883_lenovo_101e_2ch_mixer},
 		.init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_lenovo_101e_capture_source,
@@ -7813,8 +7858,6 @@
 		.init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.need_dac_fix = 1,
@@ -7828,8 +7871,6 @@
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
 		.dig_out_nid = ALC883_DIGOUT_NID,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
 		.channel_mode = alc883_3ST_6ch_modes,
 		.need_dac_fix = 1,
@@ -7843,47 +7884,28 @@
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
 		.dig_out_nid = ALC883_DIGOUT_NID,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
 		.unsol_event = alc883_haier_w66_unsol_event,
 		.init_hook = alc883_haier_w66_automute,
-	},	
-	[ALC888_6ST_HP] = {
-		.mixers = { alc888_6st_hp_mixer, alc883_chmode_mixer },
-		.init_verbs = { alc883_init_verbs, alc888_6st_hp_verbs },
-		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
-		.dac_nids = alc883_dac_nids,
-		.dig_out_nid = ALC883_DIGOUT_NID,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
-		.dig_in_nid = ALC883_DIGIN_NID,
-		.num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
-		.channel_mode = alc883_sixstack_modes,
-		.input_mux = &alc883_capture_source,
 	},
 	[ALC888_3ST_HP] = {
-		.mixers = { alc888_3st_hp_mixer, alc883_chmode_mixer },
+		.mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
 		.init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
 		.channel_mode = alc888_3st_hp_modes,
 		.need_dac_fix = 1,
 		.input_mux = &alc883_capture_source,
 	},
 	[ALC888_6ST_DELL] = {
-		.mixers = { alc888_6st_dell_mixer, alc883_chmode_mixer },
+		.mixers = { alc883_base_mixer, alc883_chmode_mixer },
 		.init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
 		.dig_out_nid = ALC883_DIGOUT_NID,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.dig_in_nid = ALC883_DIGIN_NID,
 		.num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
 		.channel_mode = alc883_sixstack_modes,
@@ -7896,14 +7918,25 @@
 		.init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
 		.unsol_event = alc883_mitac_unsol_event,
 		.init_hook = alc883_mitac_automute,
 	},
+	[ALC883_FUJITSU_PI2515] = {
+		.mixers = { alc883_2ch_fujitsu_pi2515_mixer },
+		.init_verbs = { alc883_init_verbs,
+				alc883_2ch_fujitsu_pi2515_verbs},
+		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
+		.dac_nids = alc883_dac_nids,
+		.dig_out_nid = ALC883_DIGOUT_NID,
+		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+		.channel_mode = alc883_3ST_2ch_modes,
+		.input_mux = &alc883_fujitsu_pi2515_capture_source,
+		.unsol_event = alc883_2ch_fujitsu_pi2515_unsol_event,
+		.init_hook = alc883_2ch_fujitsu_pi2515_automute,
+	},
 };
 
 
@@ -7918,15 +7951,11 @@
 	struct alc_spec *spec = codec->spec;
 	int idx;
 
+	alc_set_pin_output(codec, nid, pin_type);
 	if (spec->multiout.dac_nids[dac_idx] == 0x25)
 		idx = 4;
 	else
 		idx = spec->multiout.dac_nids[dac_idx] - 2;
-
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    pin_type);
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-			    AMP_OUT_UNMUTE);
 	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
 
 }
@@ -7955,6 +7984,9 @@
 	if (pin) /* connect to front */
 		/* use dac 0 */
 		alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+	pin = spec->autocfg.speaker_pins[0];
+	if (pin)
+		alc883_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
 }
 
 #define alc883_is_input_pin(nid)	alc880_is_input_pin(nid)
@@ -8006,9 +8038,12 @@
 /* additional initialization for auto-configuration model */
 static void alc883_auto_init(struct hda_codec *codec)
 {
+	struct alc_spec *spec = codec->spec;
 	alc883_auto_init_multi_out(codec);
 	alc883_auto_init_hp_out(codec);
 	alc883_auto_init_analog_input(codec);
+	if (spec->unsol_event)
+		alc_sku_automute(codec);
 }
 
 static int patch_alc883(struct hda_codec *codec)
@@ -8057,10 +8092,9 @@
 	spec->stream_digital_playback = &alc883_pcm_digital_playback;
 	spec->stream_digital_capture = &alc883_pcm_digital_capture;
 
-	if (!spec->adc_nids && spec->input_mux) {
-		spec->adc_nids = alc883_adc_nids;
-		spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
-	}
+	spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
+	spec->adc_nids = alc883_adc_nids;
+	spec->capsrc_nids = alc883_capsrc_nids;
 
 	spec->vmaster_nid = 0x0c;
 
@@ -8085,6 +8119,8 @@
 #define alc262_dac_nids		alc260_dac_nids
 #define alc262_adc_nids		alc882_adc_nids
 #define alc262_adc_nids_alt	alc882_adc_nids_alt
+#define alc262_capsrc_nids	alc882_capsrc_nids
+#define alc262_capsrc_nids_alt	alc882_capsrc_nids_alt
 
 #define alc262_modes		alc260_modes
 #define alc262_capture_source	alc882_capture_source
@@ -8585,7 +8621,8 @@
 
 /*
  * fujitsu model
- *  0x14 = headphone/spdif-out, 0x15 = internal speaker
+ *  0x14 = headphone/spdif-out, 0x15 = internal speaker,
+ *  0x1b = port replicator headphone out
  */
 
 #define ALC_HP_EVENT	0x37
@@ -8593,6 +8630,14 @@
 static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
 	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{}
+};
+
+static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
+	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{}
 };
 
@@ -8633,12 +8678,16 @@
 	unsigned int mute;
 
 	if (force || !spec->sense_updated) {
-		unsigned int present;
+		unsigned int present_int_hp, present_dock_hp;
 		/* need to execute and sync at first */
 		snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
-		present = snd_hda_codec_read(codec, 0x14, 0,
-				    	 AC_VERB_GET_PIN_SENSE, 0);
-		spec->jack_present = (present & 0x80000000) != 0;
+		present_int_hp = snd_hda_codec_read(codec, 0x14, 0,
+					AC_VERB_GET_PIN_SENSE, 0);
+		snd_hda_codec_read(codec, 0x1B, 0, AC_VERB_SET_PIN_SENSE, 0);
+		present_dock_hp = snd_hda_codec_read(codec, 0x1b, 0,
+					AC_VERB_GET_PIN_SENSE, 0);
+		spec->jack_present = (present_int_hp & 0x80000000) != 0;
+		spec->jack_present |= (present_dock_hp & 0x80000000) != 0;
 		spec->sense_updated = 1;
 	}
 	if (spec->jack_present) {
@@ -8672,6 +8721,46 @@
 	},
 };
 
+/* mute/unmute internal speaker according to the hp jack and mute state */
+static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
+{
+	struct alc_spec *spec = codec->spec;
+	unsigned int mute;
+
+	if (force || !spec->sense_updated) {
+		unsigned int present_int_hp;
+		/* need to execute and sync at first */
+		snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
+		present_int_hp = snd_hda_codec_read(codec, 0x1b, 0,
+					AC_VERB_GET_PIN_SENSE, 0);
+		spec->jack_present = (present_int_hp & 0x80000000) != 0;
+		spec->sense_updated = 1;
+	}
+	if (spec->jack_present) {
+		/* mute internal speaker */
+		snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+					 HDA_AMP_MUTE, HDA_AMP_MUTE);
+		snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
+					 HDA_AMP_MUTE, HDA_AMP_MUTE);
+	} else {
+		/* unmute internal speaker if necessary */
+		mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
+		snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+					 HDA_AMP_MUTE, mute);
+		snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
+					 HDA_AMP_MUTE, mute);
+	}
+}
+
+/* unsolicited event for HP jack sensing */
+static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
+				       unsigned int res)
+{
+	if ((res >> 26) != ALC_HP_EVENT)
+		return;
+	alc262_lenovo_3000_automute(codec, 1);
+}
+
 /* bind hp and internal speaker mute (with plug check) */
 static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
 					 struct snd_ctl_elem_value *ucontrol)
@@ -8680,12 +8769,13 @@
 	long *valp = ucontrol->value.integer.value;
 	int change;
 
-	change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
-					  HDA_AMP_MUTE,
-					  valp[0] ? 0 : HDA_AMP_MUTE);
-	change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
-					   HDA_AMP_MUTE,
-					   valp[1] ? 0 : HDA_AMP_MUTE);
+	change = snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+						 HDA_AMP_MUTE,
+						 valp ? 0 : HDA_AMP_MUTE);
+	change |= snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
+						 HDA_AMP_MUTE,
+						 valp ? 0 : HDA_AMP_MUTE);
+
 	if (change)
 		alc262_fujitsu_automute(codec, 0);
 	return change;
@@ -8703,6 +8793,46 @@
 	},
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
 	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_VOLUME("PC Speaker Volume", 0x0b, 0x05, HDA_INPUT),
+	HDA_CODEC_MUTE("PC Speaker Switch", 0x0b, 0x05, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+	{ } /* end */
+};
+
+/* bind hp and internal speaker mute (with plug check) */
+static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	long *valp = ucontrol->value.integer.value;
+	int change;
+
+	change = snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
+						 HDA_AMP_MUTE,
+						 valp ? 0 : HDA_AMP_MUTE);
+
+	if (change)
+		alc262_lenovo_3000_automute(codec, 0);
+	return change;
+}
+
+static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
+	HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Switch",
+		.info = snd_hda_mixer_amp_switch_info,
+		.get = snd_hda_mixer_amp_switch_get,
+		.put = alc262_lenovo_3000_master_sw_put,
+		.private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
+	},
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
@@ -8730,59 +8860,72 @@
 
 /* Samsung Q1 Ultra Vista model setup */
 static struct snd_kcontrol_new alc262_ultra_mixer[] = {
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Headphone Mic Boost", 0x15, 0, HDA_INPUT),
 	{ } /* end */
 };
 
 static struct hda_verb alc262_ultra_verbs[] = {
-	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+	/* output mixer */
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	/* speaker */
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+	/* HP */
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
-	/* Mic is on Node 0x19 */
-	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
-	{0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
-	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
-	{0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
-	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
-	{0x24, AC_VERB_SET_CONNECT_SEL, 0x01},
-	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+	/* internal mic */
+	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	/* ADC, choose mic */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
 	{}
 };
 
-static struct hda_input_mux alc262_ultra_capture_source = {
-	.num_items = 1,
-	.items = {
-		{ "Mic", 0x1 },
-	},
-};
-
 /* mute/unmute internal speaker according to the hp jack and mute state */
 static void alc262_ultra_automute(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
 	unsigned int mute;
-	unsigned int present;
 
-	/* need to execute and sync at first */
-	snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
-	present = snd_hda_codec_read(codec, 0x15, 0,
-				     AC_VERB_GET_PIN_SENSE, 0);
-	spec->jack_present = (present & 0x80000000) != 0;
-	if (spec->jack_present) {
-		/* mute internal speaker */
-		snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, HDA_AMP_MUTE);
-	} else {
-		/* unmute internal speaker if necessary */
-		mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
-		snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, mute);
+	mute = 0;
+	/* auto-mute only when HP is used as HP */
+	if (!spec->cur_mux[0]) {
+		unsigned int present;
+		/* need to execute and sync at first */
+		snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
+		present = snd_hda_codec_read(codec, 0x15, 0,
+					     AC_VERB_GET_PIN_SENSE, 0);
+		spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
+		if (spec->jack_present)
+			mute = HDA_AMP_MUTE;
 	}
+	/* mute/unmute internal speaker */
+	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+				 HDA_AMP_MUTE, mute);
+	/* mute/unmute HP */
+	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
+				 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
 }
 
 /* unsolicited event for HP jack sensing */
@@ -8794,6 +8937,45 @@
 	alc262_ultra_automute(codec);
 }
 
+static struct hda_input_mux alc262_ultra_capture_source = {
+	.num_items = 2,
+	.items = {
+		{ "Mic", 0x1 },
+		{ "Headphone", 0x7 },
+	},
+};
+
+static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+	int ret;
+
+	ret = alc882_mux_enum_put(kcontrol, ucontrol);
+	if (!ret)
+		return 0;
+	/* reprogram the HP pin as mic or HP according to the input source */
+	snd_hda_codec_write_cache(codec, 0x15, 0,
+				  AC_VERB_SET_PIN_WIDGET_CONTROL,
+				  spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
+	alc262_ultra_automute(codec); /* mute/unmute HP */
+	return ret;
+}
+
+static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
+	HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Capture Source",
+		.info = alc882_mux_enum_info,
+		.get = alc882_mux_enum_get,
+		.put = alc262_ultra_mux_enum_put,
+	},
+	{ } /* end */
+};
+
 /* add playback controls from the parsed DAC table */
 static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
 					     const struct auto_pin_cfg *cfg)
@@ -9185,9 +9367,12 @@
 /* init callback for auto-configuration model -- overriding the default init */
 static void alc262_auto_init(struct hda_codec *codec)
 {
+	struct alc_spec *spec = codec->spec;
 	alc262_auto_init_multi_out(codec);
 	alc262_auto_init_hp_out(codec);
 	alc262_auto_init_analog_input(codec);
+	if (spec->unsol_event)
+		alc_sku_automute(codec);
 }
 
 /*
@@ -9206,6 +9391,7 @@
 	[ALC262_BENQ_T31]	= "benq-t31",
 	[ALC262_SONY_ASSAMD]	= "sony-assamd",
 	[ALC262_ULTRA]		= "ultra",
+	[ALC262_LENOVO_3000]	= "lenovo-3000",
 	[ALC262_AUTO]		= "auto",
 };
 
@@ -9241,6 +9427,8 @@
 	SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
 	SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
 	SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA),
+	SND_PCI_QUIRK(0x144d, 0xc039, "Samsung Q1U EL", ALC262_ULTRA),
+	SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
 	SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
 	SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
 	SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
@@ -9390,17 +9578,31 @@
 		.init_hook = alc262_hippo_automute,
 	},	
 	[ALC262_ULTRA] = {
-		.mixers = { alc262_ultra_mixer },
-		.init_verbs = { alc262_init_verbs, alc262_ultra_verbs },
+		.mixers = { alc262_ultra_mixer, alc262_ultra_capture_mixer },
+		.init_verbs = { alc262_ultra_verbs },
+		.num_dacs = ARRAY_SIZE(alc262_dac_nids),
+		.dac_nids = alc262_dac_nids,
+		.num_channel_mode = ARRAY_SIZE(alc262_modes),
+		.channel_mode = alc262_modes,
+		.input_mux = &alc262_ultra_capture_source,
+		.adc_nids = alc262_adc_nids, /* ADC0 */
+		.capsrc_nids = alc262_capsrc_nids,
+		.num_adc_nids = 1, /* single ADC */
+		.unsol_event = alc262_ultra_unsol_event,
+		.init_hook = alc262_ultra_automute,
+	},
+	[ALC262_LENOVO_3000] = {
+		.mixers = { alc262_lenovo_3000_mixer },
+		.init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
+				alc262_lenovo_3000_unsol_verbs },
 		.num_dacs = ARRAY_SIZE(alc262_dac_nids),
 		.dac_nids = alc262_dac_nids,
 		.hp_nid = 0x03,
 		.dig_out_nid = ALC262_DIGOUT_NID,
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.channel_mode = alc262_modes,
-		.input_mux = &alc262_ultra_capture_source,
-		.unsol_event = alc262_ultra_unsol_event,
-		.init_hook = alc262_ultra_automute,
+		.input_mux = &alc262_fujitsu_capture_source,
+		.unsol_event = alc262_lenovo_3000_unsol_event,
 	},
 };
 
@@ -9472,12 +9674,14 @@
 		if (wcap != AC_WID_AUD_IN) {
 			spec->adc_nids = alc262_adc_nids_alt;
 			spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt);
+			spec->capsrc_nids = alc262_capsrc_nids_alt;
 			spec->mixers[spec->num_mixers] =
 				alc262_capture_alt_mixer;
 			spec->num_mixers++;
 		} else {
 			spec->adc_nids = alc262_adc_nids;
 			spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids);
+			spec->capsrc_nids = alc262_capsrc_nids;
 			spec->mixers[spec->num_mixers] = alc262_capture_mixer;
 			spec->num_mixers++;
 		}
@@ -9517,6 +9721,8 @@
 	0x08
 };
 
+static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
+
 static struct snd_kcontrol_new alc268_base_mixer[] = {
 	/* output mixer control */
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
@@ -9529,6 +9735,22 @@
 	{ }
 };
 
+/* bind Beep switches of both NID 0x0f and 0x10 */
+static struct hda_bind_ctls alc268_bind_beep_sw = {
+	.ops = &snd_hda_bind_sw,
+	.values = {
+		HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
+		HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
+		0
+	},
+};
+
+static struct snd_kcontrol_new alc268_beep_mixer[] = {
+	HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
+	HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
+	{ }
+};
+
 static struct hda_verb alc268_eapd_verbs[] = {
 	{0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
 	{0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
@@ -9613,8 +9835,12 @@
 };
 
 static struct hda_verb alc268_acer_verbs[] = {
+	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
+	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
 
 	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
 	{ }
@@ -9685,6 +9911,64 @@
 
 #define alc268_dell_init_hook	alc268_dell_automute
 
+static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
+	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
+	{ }
+};
+
+static struct hda_verb alc267_quanta_il1_verbs[] = {
+	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
+	{ }
+};
+
+static void alc267_quanta_il1_hp_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+
+	present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0)
+		& AC_PINSENSE_PRESENCE;
+	snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+			    present ? 0 : PIN_OUT);
+}
+
+static void alc267_quanta_il1_mic_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+
+	present = snd_hda_codec_read(codec, 0x18, 0,
+				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	snd_hda_codec_write(codec, 0x23, 0,
+			    AC_VERB_SET_CONNECT_SEL,
+			    present ? 0x00 : 0x01);
+}
+
+static void alc267_quanta_il1_automute(struct hda_codec *codec)
+{
+	alc267_quanta_il1_hp_automute(codec);
+	alc267_quanta_il1_mic_automute(codec);
+}
+
+static void alc267_quanta_il1_unsol_event(struct hda_codec *codec,
+					   unsigned int res)
+{
+	switch (res >> 26) {
+	case ALC880_HP_EVENT:
+		alc267_quanta_il1_hp_automute(codec);
+		break;
+	case ALC880_MIC_EVENT:
+		alc267_quanta_il1_mic_automute(codec);
+		break;
+	}
+}
+
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
@@ -9725,7 +10009,11 @@
 	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+
+	/* set PCBEEP vol = 0, mute connections */
+	{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
 
 	/* Unmute Selector 23h,24h and set the default input to mic-in */
 	
@@ -9764,29 +10052,17 @@
 	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 
-	/* set PCBEEP vol = 0 */
-	{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, (0xb000 | (0x00 << 8))},
+	/* set PCBEEP vol = 0, mute connections */
+	{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
 
 	{ }
 };
 
 #define alc268_mux_enum_info alc_mux_enum_info
 #define alc268_mux_enum_get alc_mux_enum_get
-
-static int alc268_mux_enum_put(struct snd_kcontrol *kcontrol,
-			       struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct alc_spec *spec = codec->spec;
-
-	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-	static hda_nid_t capture_mixers[3] = { 0x23, 0x24 };
-	hda_nid_t nid = capture_mixers[adc_idx];
-
-	return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
-				     nid,
-				     &spec->cur_mux[adc_idx]);
-}
+#define alc268_mux_enum_put alc_mux_enum_put
 
 static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
@@ -9836,13 +10112,17 @@
 	},
 };
 
+static struct hda_input_mux alc268_acer_capture_source = {
+	.num_items = 3,
+	.items = {
+		{ "Mic", 0x0 },
+		{ "Internal Mic", 0x6 },
+		{ "Line", 0x2 },
+	},
+};
+
 #ifdef CONFIG_SND_DEBUG
 static struct snd_kcontrol_new alc268_test_mixer[] = {
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-
 	/* Volume widgets */
 	HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
@@ -9981,6 +10261,10 @@
 		case 0x1c:	
 			idx1 = 3;	/* CD */
 			break;
+		case 0x12:
+		case 0x13:
+			idx1 = 6;	/* digital mics */
+			break;
 		default:
 			continue;
 		}
@@ -10073,6 +10357,9 @@
 	if (spec->kctl_alloc)
 		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
 
+	if (spec->autocfg.speaker_pins[0] != 0x1d)
+		spec->mixers[spec->num_mixers++] = alc268_beep_mixer;
+
 	spec->init_verbs[spec->num_init_verbs++] = alc268_volume_init_verbs;
 	spec->num_mux_defs = 1;
 	spec->input_mux = &spec->private_imux;
@@ -10091,20 +10378,25 @@
 /* init callback for auto-configuration model -- overriding the default init */
 static void alc268_auto_init(struct hda_codec *codec)
 {
+	struct alc_spec *spec = codec->spec;
 	alc268_auto_init_multi_out(codec);
 	alc268_auto_init_hp_out(codec);
 	alc268_auto_init_mono_speaker_out(codec);
 	alc268_auto_init_analog_input(codec);
+	if (spec->unsol_event)
+		alc_sku_automute(codec);
 }
 
 /*
  * configuration and preset
  */
 static const char *alc268_models[ALC268_MODEL_LAST] = {
+	[ALC267_QUANTA_IL1]	= "quanta-il1",
 	[ALC268_3ST]		= "3stack",
 	[ALC268_TOSHIBA]	= "toshiba",
 	[ALC268_ACER]		= "acer",
 	[ALC268_DELL]		= "dell",
+	[ALC268_ZEPTO]		= "zepto",
 #ifdef CONFIG_SND_DEBUG
 	[ALC268_TEST]		= "test",
 #endif
@@ -10112,6 +10404,7 @@
 };
 
 static struct snd_pci_quirk alc268_cfg_tbl[] = {
+	SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
 	SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
 	SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
 	SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
@@ -10122,17 +10415,36 @@
 	SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA),
 	SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA),
 	SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
+	SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
+	SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
 	{}
 };
 
 static struct alc_config_preset alc268_presets[] = {
+	[ALC267_QUANTA_IL1] = {
+		.mixers = { alc267_quanta_il1_mixer },
+		.init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
+				alc267_quanta_il1_verbs },
+		.num_dacs = ARRAY_SIZE(alc268_dac_nids),
+		.dac_nids = alc268_dac_nids,
+		.num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
+		.adc_nids = alc268_adc_nids_alt,
+		.hp_nid = 0x03,
+		.num_channel_mode = ARRAY_SIZE(alc268_modes),
+		.channel_mode = alc268_modes,
+		.input_mux = &alc268_capture_source,
+		.unsol_event = alc267_quanta_il1_unsol_event,
+		.init_hook = alc267_quanta_il1_automute,
+	},
 	[ALC268_3ST] = {
-		.mixers = { alc268_base_mixer, alc268_capture_alt_mixer },
+		.mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
+			    alc268_beep_mixer },
 		.init_verbs = { alc268_base_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc268_dac_nids),
 		.dac_nids = alc268_dac_nids,
                 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
                 .adc_nids = alc268_adc_nids_alt,
+		.capsrc_nids = alc268_capsrc_nids,
 		.hp_nid = 0x03,
 		.dig_out_nid = ALC268_DIGOUT_NID,
 		.num_channel_mode = ARRAY_SIZE(alc268_modes),
@@ -10140,13 +10452,15 @@
 		.input_mux = &alc268_capture_source,
 	},
 	[ALC268_TOSHIBA] = {
-		.mixers = { alc268_base_mixer, alc268_capture_alt_mixer },
+		.mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
+			    alc268_beep_mixer },
 		.init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
 				alc268_toshiba_verbs },
 		.num_dacs = ARRAY_SIZE(alc268_dac_nids),
 		.dac_nids = alc268_dac_nids,
 		.num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
 		.adc_nids = alc268_adc_nids_alt,
+		.capsrc_nids = alc268_capsrc_nids,
 		.hp_nid = 0x03,
 		.num_channel_mode = ARRAY_SIZE(alc268_modes),
 		.channel_mode = alc268_modes,
@@ -10155,22 +10469,24 @@
 		.init_hook = alc268_toshiba_automute,
 	},
 	[ALC268_ACER] = {
-		.mixers = { alc268_acer_mixer, alc268_capture_alt_mixer },
+		.mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
+			    alc268_beep_mixer },
 		.init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
 				alc268_acer_verbs },
 		.num_dacs = ARRAY_SIZE(alc268_dac_nids),
 		.dac_nids = alc268_dac_nids,
 		.num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
 		.adc_nids = alc268_adc_nids_alt,
+		.capsrc_nids = alc268_capsrc_nids,
 		.hp_nid = 0x02,
 		.num_channel_mode = ARRAY_SIZE(alc268_modes),
 		.channel_mode = alc268_modes,
-		.input_mux = &alc268_capture_source,
+		.input_mux = &alc268_acer_capture_source,
 		.unsol_event = alc268_acer_unsol_event,
 		.init_hook = alc268_acer_init_hook,
 	},
 	[ALC268_DELL] = {
-		.mixers = { alc268_dell_mixer },
+		.mixers = { alc268_dell_mixer, alc268_beep_mixer },
 		.init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
 				alc268_dell_verbs },
 		.num_dacs = ARRAY_SIZE(alc268_dac_nids),
@@ -10182,6 +10498,24 @@
 		.init_hook = alc268_dell_init_hook,
 		.input_mux = &alc268_capture_source,
 	},
+	[ALC268_ZEPTO] = {
+		.mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
+			    alc268_beep_mixer },
+		.init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
+				alc268_toshiba_verbs },
+		.num_dacs = ARRAY_SIZE(alc268_dac_nids),
+		.dac_nids = alc268_dac_nids,
+		.num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
+		.adc_nids = alc268_adc_nids_alt,
+		.capsrc_nids = alc268_capsrc_nids,
+		.hp_nid = 0x03,
+		.dig_out_nid = ALC268_DIGOUT_NID,
+		.num_channel_mode = ARRAY_SIZE(alc268_modes),
+		.channel_mode = alc268_modes,
+		.input_mux = &alc268_capture_source,
+		.unsol_event = alc268_toshiba_unsol_event,
+		.init_hook = alc268_toshiba_automute
+	},
 #ifdef CONFIG_SND_DEBUG
 	[ALC268_TEST] = {
 		.mixers = { alc268_test_mixer, alc268_capture_mixer },
@@ -10191,6 +10525,7 @@
 		.dac_nids = alc268_dac_nids,
 		.num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
 		.adc_nids = alc268_adc_nids_alt,
+		.capsrc_nids = alc268_capsrc_nids,
 		.hp_nid = 0x03,
 		.dig_out_nid = ALC268_DIGOUT_NID,
 		.num_channel_mode = ARRAY_SIZE(alc268_modes),
@@ -10247,13 +10582,22 @@
 	spec->stream_name_digital = "ALC268 Digital";
 	spec->stream_digital_playback = &alc268_pcm_digital_playback;
 
+	if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
+		/* override the amp caps for beep generator */
+		snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
+					  (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
+					  (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
+					  (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+					  (0 << AC_AMPCAP_MUTE_SHIFT));
+
 	if (!spec->adc_nids && spec->input_mux) {
 		/* check whether NID 0x07 is valid */
 		unsigned int wcap = get_wcaps(codec, 0x07);
+		int i;
 
 		/* get type */
 		wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
-		if (wcap != AC_WID_AUD_IN) {
+		if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
 			spec->adc_nids = alc268_adc_nids_alt;
 			spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
 			spec->mixers[spec->num_mixers] =
@@ -10266,6 +10610,12 @@
 				alc268_capture_mixer;
 			spec->num_mixers++;
 		}
+		spec->capsrc_nids = alc268_capsrc_nids;
+		/* set default input source */
+		for (i = 0; i < spec->num_adc_nids; i++)
+			snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
+				0, AC_VERB_SET_CONNECT_SEL,
+				spec->input_mux->items[0].index);
 	}
 
 	spec->vmaster_nid = 0x02;
@@ -10539,9 +10889,12 @@
 /* init callback for auto-configuration model -- overriding the default init */
 static void alc269_auto_init(struct hda_codec *codec)
 {
+	struct alc_spec *spec = codec->spec;
 	alc269_auto_init_multi_out(codec);
 	alc269_auto_init_hp_out(codec);
 	alc269_auto_init_analog_input(codec);
+	if (spec->unsol_event)
+		alc_sku_automute(codec);
 }
 
 /*
@@ -11463,13 +11816,7 @@
 					      hda_nid_t nid,
 					      int pin_type, int dac_idx)
 {
-	/* set as output */
-
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    pin_type);
-	snd_hda_codec_write(codec, dac_idx, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-			    AMP_OUT_UNMUTE);
-
+	alc_set_pin_output(codec, nid, pin_type);
 }
 
 static void alc861_auto_init_multi_out(struct hda_codec *codec)
@@ -11496,6 +11843,9 @@
 	if (pin) /* connect to front */
 		alc861_auto_set_output_and_unmute(codec, pin, PIN_HP,
 						  spec->multiout.dac_nids[0]);
+	pin = spec->autocfg.speaker_pins[0];
+	if (pin)
+		alc861_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
 }
 
 static void alc861_auto_init_analog_input(struct hda_codec *codec)
@@ -11568,9 +11918,12 @@
 /* additional initialization for auto-configuration model */
 static void alc861_auto_init(struct hda_codec *codec)
 {
+	struct alc_spec *spec = codec->spec;
 	alc861_auto_init_multi_out(codec);
 	alc861_auto_init_hp_out(codec);
 	alc861_auto_init_analog_input(codec);
+	if (spec->unsol_event)
+		alc_sku_automute(codec);
 }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -11822,6 +12175,8 @@
 	0x09,
 };
 
+static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
+
 /* input MUX */
 /* FIXME: should be a matrix-type input source selection */
 static struct hda_input_mux alc861vd_capture_source = {
@@ -11835,11 +12190,10 @@
 };
 
 static struct hda_input_mux alc861vd_dallas_capture_source = {
-	.num_items = 3,
+	.num_items = 2,
 	.items = {
-		{ "Front Mic", 0x0 },
-		{ "ATAPI Mic", 0x1 },
-		{ "Line In", 0x5 },
+		{ "Ext Mic", 0x0 },
+		{ "Int Mic", 0x1 },
 	},
 };
 
@@ -11853,33 +12207,8 @@
 
 #define alc861vd_mux_enum_info alc_mux_enum_info
 #define alc861vd_mux_enum_get alc_mux_enum_get
-
-static int alc861vd_mux_enum_put(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct alc_spec *spec = codec->spec;
-	const struct hda_input_mux *imux = spec->input_mux;
-	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-	static hda_nid_t capture_mixers[1] = { 0x22 };
-	hda_nid_t nid = capture_mixers[adc_idx];
-	unsigned int *cur_val = &spec->cur_mux[adc_idx];
-	unsigned int i, idx;
-
-	idx = ucontrol->value.enumerated.item[0];
-	if (idx >= imux->num_items)
-		idx = imux->num_items - 1;
-	if (*cur_val == idx)
-		return 0;
-	for (i = 0; i < imux->num_items; i++) {
-		unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
-		snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
-					 imux->items[i].index,
-					 HDA_AMP_MUTE, v);
-	}
-	*cur_val = idx;
-	return 1;
-}
+/* ALC861VD has the ALC882-type input selection (but has only one ADC) */
+#define alc861vd_mux_enum_put alc882_mux_enum_put
 
 /*
  * 2ch mode
@@ -12034,20 +12363,22 @@
 	{ } /* end */
 };
 
-/* Pin assignment: Front=0x14, HP = 0x15,
- *                 Front Mic=0x18, ATAPI Mic = 0x19, Line In = 0x1d
+/* Pin assignment: Speaker=0x14, HP = 0x15,
+ *                 Ext Mic=0x18, Int Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
  */
 static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-	HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x05, HDA_INPUT),
-	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x05, HDA_INPUT),
+	HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("PC Beep Volume", 0x0b, 0x05, HDA_INPUT),
+	HDA_CODEC_MUTE("PC Beep Switch", 0x0b, 0x05, HDA_INPUT),
 	{ } /* end */
 };
 
@@ -12348,6 +12679,7 @@
 	/*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
 	SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS),
 	SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
+	SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
 	SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
 	SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO),
 	SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO),
@@ -12362,8 +12694,6 @@
 				 alc861vd_3stack_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
 		.dac_nids = alc660vd_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
-		.adc_nids = alc861vd_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
 		.channel_mode = alc861vd_3stack_2ch_modes,
 		.input_mux = &alc861vd_capture_source,
@@ -12375,8 +12705,6 @@
 		.num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
 		.dac_nids = alc660vd_dac_nids,
 		.dig_out_nid = ALC861VD_DIGOUT_NID,
-		.num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
-		.adc_nids = alc861vd_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
 		.channel_mode = alc861vd_3stack_2ch_modes,
 		.input_mux = &alc861vd_capture_source,
@@ -12421,8 +12749,6 @@
 				alc861vd_lenovo_unsol_verbs },
 		.num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
 		.dac_nids = alc660vd_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
-		.adc_nids = alc861vd_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
 		.channel_mode = alc861vd_3stack_2ch_modes,
 		.input_mux = &alc861vd_capture_source,
@@ -12434,8 +12760,6 @@
 		.init_verbs = { alc861vd_dallas_verbs },
 		.num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
 		.dac_nids = alc861vd_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
-		.adc_nids = alc861vd_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
 		.channel_mode = alc861vd_3stack_2ch_modes,
 		.input_mux = &alc861vd_dallas_capture_source,
@@ -12447,9 +12771,7 @@
 		.init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
 		.num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
 		.dac_nids = alc861vd_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
 		.dig_out_nid = ALC861VD_DIGOUT_NID,
-		.adc_nids = alc861vd_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
 		.channel_mode = alc861vd_3stack_2ch_modes,
 		.input_mux = &alc861vd_hp_capture_source,
@@ -12464,11 +12786,7 @@
 static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
 				hda_nid_t nid, int pin_type, int dac_idx)
 {
-	/* set as output */
-	snd_hda_codec_write(codec, nid, 0,
-				AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
-	snd_hda_codec_write(codec, nid, 0,
-				AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+	alc_set_pin_output(codec, nid, pin_type);
 }
 
 static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
@@ -12495,6 +12813,9 @@
 	pin = spec->autocfg.hp_pins[0];
 	if (pin) /* connect to front and  use dac 0 */
 		alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+	pin = spec->autocfg.speaker_pins[0];
+	if (pin)
+		alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
 }
 
 #define alc861vd_is_input_pin(nid)	alc880_is_input_pin(nid)
@@ -12698,9 +13019,12 @@
 /* additional initialization for auto-configuration model */
 static void alc861vd_auto_init(struct hda_codec *codec)
 {
+	struct alc_spec *spec = codec->spec;
 	alc861vd_auto_init_multi_out(codec);
 	alc861vd_auto_init_hp_out(codec);
 	alc861vd_auto_init_analog_input(codec);
+	if (spec->unsol_event)
+		alc_sku_automute(codec);
 }
 
 static int patch_alc861vd(struct hda_codec *codec)
@@ -12751,6 +13075,7 @@
 
 	spec->adc_nids = alc861vd_adc_nids;
 	spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
+	spec->capsrc_nids = alc861vd_capsrc_nids;
 
 	spec->mixers[spec->num_mixers] = alc861vd_capture_mixer;
 	spec->num_mixers++;
@@ -12792,9 +13117,11 @@
 	/* ADC1-2 */
 	0x09,
 };
+
+static hda_nid_t alc662_capsrc_nids[1] = { 0x22 };
+
 /* input MUX */
 /* FIXME: should be a matrix-type input source selection */
-
 static struct hda_input_mux alc662_capture_source = {
 	.num_items = 4,
 	.items = {
@@ -12823,33 +13150,8 @@
 
 #define alc662_mux_enum_info alc_mux_enum_info
 #define alc662_mux_enum_get alc_mux_enum_get
+#define alc662_mux_enum_put alc882_mux_enum_put
 
-static int alc662_mux_enum_put(struct snd_kcontrol *kcontrol,
-			       struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct alc_spec *spec = codec->spec;
-	const struct hda_input_mux *imux = spec->input_mux;
-	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-	static hda_nid_t capture_mixers[2] = { 0x23, 0x22 };
-	hda_nid_t nid = capture_mixers[adc_idx];
-	unsigned int *cur_val = &spec->cur_mux[adc_idx];
-	unsigned int i, idx;
-
-	idx = ucontrol->value.enumerated.item[0];
-	if (idx >= imux->num_items)
-		idx = imux->num_items - 1;
-	if (*cur_val == idx)
-		return 0;
-	for (i = 0; i < imux->num_items; i++) {
-		unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
-		snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
-					 imux->items[i].index,
-					 HDA_AMP_MUTE, v);
-	}
-	*cur_val = idx;
-	return 1;
-}
 /*
  * 2ch mode
  */
@@ -12918,13 +13220,13 @@
 static struct snd_kcontrol_new alc662_base_mixer[] = {
 	/* output mixer control */
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Front Playback Switch", 0x02, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Surround Playback Switch", 0x03, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
-	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
+	HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
 
 	/*Input mixer control */
@@ -12941,7 +13243,7 @@
 
 static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
 	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
@@ -12958,13 +13260,13 @@
 
 static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT),
+	HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
-	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
+	HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
 	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
@@ -13313,6 +13615,7 @@
 };
 
 static struct snd_pci_quirk alc662_cfg_tbl[] = {
+	SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
 	SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
 	SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
 	SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
@@ -13326,8 +13629,6 @@
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.dig_out_nid = ALC662_DIGOUT_NID,
-		.num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
-		.adc_nids = alc662_adc_nids,
 		.dig_in_nid = ALC662_DIGIN_NID,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
@@ -13340,8 +13641,6 @@
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.dig_out_nid = ALC662_DIGOUT_NID,
-		.num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
-		.adc_nids = alc662_adc_nids,
 		.dig_in_nid = ALC662_DIGIN_NID,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
 		.channel_mode = alc662_3ST_6ch_modes,
@@ -13354,8 +13653,6 @@
 		.init_verbs = { alc662_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
-		.adc_nids = alc662_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
 		.channel_mode = alc662_3ST_6ch_modes,
 		.need_dac_fix = 1,
@@ -13368,8 +13665,6 @@
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.dig_out_nid = ALC662_DIGOUT_NID,
-		.num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
-		.adc_nids = alc662_adc_nids,
 		.dig_in_nid = ALC662_DIGIN_NID,
 		.num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
 		.channel_mode = alc662_5stack_modes,
@@ -13380,8 +13675,6 @@
 		.init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
-		.adc_nids = alc662_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
 		.input_mux = &alc662_lenovo_101e_capture_source,
@@ -13394,8 +13687,6 @@
 				alc662_eeepc_sue_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
-		.adc_nids = alc662_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
 		.input_mux = &alc662_eeepc_capture_source,
@@ -13409,8 +13700,6 @@
 				alc662_eeepc_ep20_sue_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
-		.adc_nids = alc662_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
 		.channel_mode = alc662_3ST_6ch_modes,
 		.input_mux = &alc662_lenovo_101e_capture_source,
@@ -13556,11 +13845,7 @@
 					      hda_nid_t nid, int pin_type,
 					      int dac_idx)
 {
-	/* set as output */
-	snd_hda_codec_write(codec, nid, 0,
-			    AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
-	snd_hda_codec_write(codec, nid, 0,
-			    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+	alc_set_pin_output(codec, nid, pin_type);
 	/* need the manual connection? */
 	if (alc880_is_multi_pin(nid)) {
 		struct alc_spec *spec = codec->spec;
@@ -13595,6 +13880,9 @@
 	if (pin) /* connect to front */
 		/* use dac 0 */
 		alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+	pin = spec->autocfg.speaker_pins[0];
+	if (pin)
+		alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
 }
 
 #define alc662_is_input_pin(nid)	alc880_is_input_pin(nid)
@@ -13672,9 +13960,12 @@
 /* additional initialization for auto-configuration model */
 static void alc662_auto_init(struct hda_codec *codec)
 {
+	struct alc_spec *spec = codec->spec;
 	alc662_auto_init_multi_out(codec);
 	alc662_auto_init_hp_out(codec);
 	alc662_auto_init_analog_input(codec);
+	if (spec->unsol_event)
+		alc_sku_automute(codec);
 }
 
 static int patch_alc662(struct hda_codec *codec)
@@ -13722,10 +14013,9 @@
 	spec->stream_digital_playback = &alc662_pcm_digital_playback;
 	spec->stream_digital_capture = &alc662_pcm_digital_capture;
 
-	if (!spec->adc_nids && spec->input_mux) {
-		spec->adc_nids = alc662_adc_nids;
-		spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
-	}
+	spec->adc_nids = alc662_adc_nids;
+	spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
+	spec->capsrc_nids = alc662_capsrc_nids;
 
 	spec->vmaster_nid = 0x02;
 
@@ -13761,6 +14051,8 @@
 	{ .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
 	{ .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
 	{ .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
+	{ .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
+	  .patch = patch_alc882 }, /* should be patch_alc883() in future */
 	{ .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
 	{ .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 },
 	{ .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 },
diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c
index d22f5a6..9332b63 100644
--- a/sound/pci/hda/patch_si3054.c
+++ b/sound/pci/hda/patch_si3054.c
@@ -28,7 +28,7 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
-
+#include "hda_patch.h"
 
 /* si3054 verbs */
 #define SI3054_VERB_READ_NODE  0x900
@@ -206,7 +206,7 @@
 	info->name = "Si3054 Modem";
 	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = si3054_pcm;
 	info->stream[SNDRV_PCM_STREAM_CAPTURE]  = si3054_pcm;
-	info->is_modem = 1;
+	info->pcm_type = HDA_PCM_TYPE_MODEM;
 	return 0;
 }
 
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index caf48ed..b3a15d6 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -32,6 +32,7 @@
 #include <sound/asoundef.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_patch.h"
 
 #define NUM_CONTROL_ALLOC	32
 #define STAC_PWR_EVENT		0x20
@@ -39,6 +40,7 @@
 
 enum {
 	STAC_REF,
+	STAC_9200_OQO,
 	STAC_9200_DELL_D21,
 	STAC_9200_DELL_D22,
 	STAC_9200_DELL_D23,
@@ -50,6 +52,7 @@
 	STAC_9200_DELL_M26,
 	STAC_9200_DELL_M27,
 	STAC_9200_GATEWAY,
+	STAC_9200_PANASONIC,
 	STAC_9200_MODELS
 };
 
@@ -63,11 +66,14 @@
 
 enum {
 	STAC_92HD73XX_REF,
+	STAC_DELL_M6,
 	STAC_92HD73XX_MODELS
 };
 
 enum {
 	STAC_92HD71BXX_REF,
+	STAC_DELL_M4_1,
+	STAC_DELL_M4_2,
 	STAC_92HD71BXX_MODELS
 };
 
@@ -123,6 +129,7 @@
 	unsigned int hp_detect: 1;
 
 	/* gpio lines */
+	unsigned int eapd_mask;
 	unsigned int gpio_mask;
 	unsigned int gpio_dir;
 	unsigned int gpio_data;
@@ -135,6 +142,7 @@
 	/* power management */
 	unsigned int num_pwrs;
 	hda_nid_t *pwr_nids;
+	hda_nid_t *dac_list;
 
 	/* playback */
 	struct hda_input_mux *mono_mux;
@@ -173,6 +181,7 @@
 	/* i/o switches */
 	unsigned int io_switch[2];
 	unsigned int clfe_swap;
+	unsigned int hp_switch;
 	unsigned int aloopback;
 
 	struct hda_pcm pcm_rec[2];	/* PCM information */
@@ -184,9 +193,6 @@
 	struct hda_input_mux private_dimux;
 	struct hda_input_mux private_imux;
 	struct hda_input_mux private_mono_mux;
-
-	/* virtual master */
-	unsigned int vmaster_tlv[4];
 };
 
 static hda_nid_t stac9200_adc_nids[1] = {
@@ -244,7 +250,7 @@
 	0x1c,
 };
 
-static hda_nid_t stac92hd71bxx_dac_nids[2] = {
+static hda_nid_t stac92hd71bxx_dac_nids[1] = {
 	0x10, /*0x11, */
 };
 
@@ -290,6 +296,10 @@
         0x15, 0x16, 0x17
 };
 
+static hda_nid_t stac927x_dac_nids[6] = {
+	0x02, 0x03, 0x04, 0x05, 0x06, 0
+};
+
 static hda_nid_t stac927x_dmux_nids[1] = {
 	0x1b,
 };
@@ -331,10 +341,10 @@
 	0x0f, 0x10, 0x11, 0x15, 0x1b,
 };
 
-static hda_nid_t stac92hd73xx_pin_nids[12] = {
+static hda_nid_t stac92hd73xx_pin_nids[13] = {
 	0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
 	0x0f, 0x10, 0x11, 0x12, 0x13,
-	0x14, 0x22
+	0x14, 0x1e, 0x22
 };
 
 static hda_nid_t stac92hd71bxx_pin_nids[10] = {
@@ -527,6 +537,43 @@
 	{}
 };
 
+static struct hda_verb dell_eq_core_init[] = {
+	/* set master volume to max value without distortion
+	 * and direct control */
+	{ 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
+	/* setup audio connections */
+	{ 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{ 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
+	/* setup adcs to point to mixer */
+	{ 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
+	{ 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
+	/* setup import muxs */
+	{ 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{ 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{ 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{ 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{}
+};
+
+static struct hda_verb dell_m6_core_init[] = {
+	/* set master volume and direct control */
+	{ 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+	/* setup audio connections */
+	{ 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{ 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
+	/* setup adcs to point to mixer */
+	{ 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
+	{ 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
+	/* setup import muxs */
+	{ 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{ 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{ 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{ 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{}
+};
+
 static struct hda_verb stac92hd73xx_8ch_core_init[] = {
 	/* set master volume and direct control */
 	{ 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
@@ -910,6 +957,11 @@
 		err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
 		if (err < 0)
 			return err;
+		err = snd_hda_create_spdif_share_sw(codec,
+						    &spec->multiout);
+		if (err < 0)
+			return err;
+		spec->multiout.share_spdif = 1;
 	}
 	if (spec->dig_in_nid) {
 		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
@@ -919,10 +971,11 @@
 
 	/* if we have no master control, let's create it */
 	if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
+		unsigned int vmaster_tlv[4];
 		snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
-					HDA_OUTPUT, spec->vmaster_tlv);
+					HDA_OUTPUT, vmaster_tlv);
 		err = snd_hda_add_vmaster(codec, "Master Playback Volume",
-					  spec->vmaster_tlv, slave_vols);
+					  vmaster_tlv, slave_vols);
 		if (err < 0)
 			return err;
 	}
@@ -1052,9 +1105,15 @@
 	0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
 };
 
+static unsigned int oqo9200_pin_configs[8] = {
+	0x40c000f0, 0x404000f1, 0x0221121f, 0x02211210,
+	0x90170111, 0x90a70120, 0x400000f2, 0x400000f3,
+};
+
 
 static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
 	[STAC_REF] = ref9200_pin_configs,
+	[STAC_9200_OQO] = oqo9200_pin_configs,
 	[STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
 	[STAC_9200_DELL_D22] = dell9200_d22_pin_configs,
 	[STAC_9200_DELL_D23] = dell9200_d23_pin_configs,
@@ -1065,10 +1124,12 @@
 	[STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
 	[STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
 	[STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
+	[STAC_9200_PANASONIC] = ref9200_pin_configs,
 };
 
 static const char *stac9200_models[STAC_9200_MODELS] = {
 	[STAC_REF] = "ref",
+	[STAC_9200_OQO] = "oqo",
 	[STAC_9200_DELL_D21] = "dell-d21",
 	[STAC_9200_DELL_D22] = "dell-d22",
 	[STAC_9200_DELL_D23] = "dell-d23",
@@ -1080,6 +1141,7 @@
 	[STAC_9200_DELL_M26] = "dell-m26",
 	[STAC_9200_DELL_M27] = "dell-m27",
 	[STAC_9200_GATEWAY] = "gateway",
+	[STAC_9200_PANASONIC] = "panasonic",
 };
 
 static struct snd_pci_quirk stac9200_cfg_tbl[] = {
@@ -1146,13 +1208,15 @@
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
 		      "unknown Dell", STAC_9200_DELL_M26),
 	/* Panasonic */
-	SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_REF),
+	SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_9200_PANASONIC),
 	/* Gateway machines needs EAPD to be set on resume */
 	SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY),
 	SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*",
 		      STAC_9200_GATEWAY),
 	SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
 		      STAC_9200_GATEWAY),
+	/* OQO Mobile */
+	SND_PCI_QUIRK(0x1106, 0x3288, "OQO Model 2", STAC_9200_OQO),
 	{} /* terminator */
 };
 
@@ -1202,24 +1266,48 @@
 	{} /* terminator */
 };
 
-static unsigned int ref92hd73xx_pin_configs[12] = {
+static unsigned int ref92hd73xx_pin_configs[13] = {
 	0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
 	0x0181302e, 0x01014010, 0x01014020, 0x01014030,
 	0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
+	0x01452050,
+};
+
+static unsigned int dell_m6_pin_configs[13] = {
+	0x0321101f, 0x4f00000f, 0x4f0000f0, 0x90170110,
+	0x03a11020, 0x0321101f, 0x4f0000f0, 0x4f0000f0,
+	0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0,
+	0x4f0000f0,
 };
 
 static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
-	[STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
+	[STAC_92HD73XX_REF]	= ref92hd73xx_pin_configs,
+	[STAC_DELL_M6]	= dell_m6_pin_configs,
 };
 
 static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
 	[STAC_92HD73XX_REF] = "ref",
+	[STAC_DELL_M6] = "dell-m6",
 };
 
 static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
 	/* SigmaTel reference board */
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
-		      "DFI LanParty", STAC_92HD73XX_REF),
+				"DFI LanParty", STAC_92HD73XX_REF),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254,
+				"unknown Dell", STAC_DELL_M6),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255,
+				"unknown Dell", STAC_DELL_M6),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0256,
+				"unknown Dell", STAC_DELL_M6),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0257,
+				"unknown Dell", STAC_DELL_M6),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025e,
+				"unknown Dell", STAC_DELL_M6),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025f,
+				"unknown Dell", STAC_DELL_M6),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0271,
+				"unknown Dell", STAC_DELL_M6),
 	{} /* terminator */
 };
 
@@ -1229,18 +1317,56 @@
 	0x90a000f0, 0x01452050,
 };
 
+static unsigned int dell_m4_1_pin_configs[13] = {
+	0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110,
+	0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0,
+	0x40f000f0, 0x4f0000f0,
+};
+
+static unsigned int dell_m4_2_pin_configs[13] = {
+	0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
+	0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0,
+	0x40f000f0, 0x044413b0,
+};
+
 static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
 	[STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
+	[STAC_DELL_M4_1]	= dell_m4_1_pin_configs,
+	[STAC_DELL_M4_2]	= dell_m4_2_pin_configs,
 };
 
 static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
 	[STAC_92HD71BXX_REF] = "ref",
+	[STAC_DELL_M4_1] = "dell-m4-1",
+	[STAC_DELL_M4_2] = "dell-m4-2",
 };
 
 static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
 	/* SigmaTel reference board */
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
 		      "DFI LanParty", STAC_92HD71BXX_REF),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
+				"unknown Dell", STAC_DELL_M4_1),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234,
+				"unknown Dell", STAC_DELL_M4_1),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0250,
+				"unknown Dell", STAC_DELL_M4_1),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024f,
+				"unknown Dell", STAC_DELL_M4_1),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024d,
+				"unknown Dell", STAC_DELL_M4_1),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0251,
+				"unknown Dell", STAC_DELL_M4_1),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0277,
+				"unknown Dell", STAC_DELL_M4_1),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0263,
+				"unknown Dell", STAC_DELL_M4_2),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0265,
+				"unknown Dell", STAC_DELL_M4_2),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0262,
+				"unknown Dell", STAC_DELL_M4_2),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0264,
+				"unknown Dell", STAC_DELL_M4_2),
 	{} /* terminator */
 };
 
@@ -1733,7 +1859,8 @@
 				      struct snd_pcm_substream *substream)
 {
 	struct sigmatel_spec *spec = codec->spec;
-	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
+					     hinfo);
 }
 
 static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
@@ -1807,7 +1934,7 @@
 {
 	struct sigmatel_spec *spec = codec->spec;
 
-	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0);
+	snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
 	return 0;
 }
 
@@ -1889,6 +2016,7 @@
 		codec->num_pcms++;
 		info++;
 		info->name = "STAC92xx Digital";
+		info->pcm_type = HDA_PCM_TYPE_SPDIF;
 		if (spec->multiout.dig_out_nid) {
 			info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
 			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
@@ -1925,6 +2053,34 @@
 				  AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
 }
 
+#define stac92xx_hp_switch_info		snd_ctl_boolean_mono_info
+
+static int stac92xx_hp_switch_get(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+
+	ucontrol->value.integer.value[0] = spec->hp_switch;
+	return 0;
+}
+
+static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+
+	spec->hp_switch = ucontrol->value.integer.value[0];
+
+	/* check to be sure that the ports are upto date with
+	 * switch changes
+	 */
+	codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
+
+	return 1;
+}
+
 #define stac92xx_io_switch_info		snd_ctl_boolean_mono_info
 
 static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1996,6 +2152,15 @@
 	return 1;
 }
 
+#define STAC_CODEC_HP_SWITCH(xname) \
+	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+	  .name = xname, \
+	  .index = 0, \
+	  .info = stac92xx_hp_switch_info, \
+	  .get = stac92xx_hp_switch_get, \
+	  .put = stac92xx_hp_switch_put, \
+	}
+
 #define STAC_CODEC_IO_SWITCH(xname, xpval) \
 	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
 	  .name = xname, \
@@ -2020,6 +2185,7 @@
 	STAC_CTL_WIDGET_VOL,
 	STAC_CTL_WIDGET_MUTE,
 	STAC_CTL_WIDGET_MONO_MUX,
+	STAC_CTL_WIDGET_HP_SWITCH,
 	STAC_CTL_WIDGET_IO_SWITCH,
 	STAC_CTL_WIDGET_CLFE_SWITCH
 };
@@ -2028,6 +2194,7 @@
 	HDA_CODEC_VOLUME(NULL, 0, 0, 0),
 	HDA_CODEC_MUTE(NULL, 0, 0, 0),
 	STAC_MONO_MUX,
+	STAC_CODEC_HP_SWITCH(NULL),
 	STAC_CODEC_IO_SWITCH(NULL, 0),
 	STAC_CODEC_CLFE_SWITCH(NULL, 0),
 };
@@ -2222,6 +2389,29 @@
 	return 0;
 }
 
+static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
+{
+	if (!spec->multiout.hp_nid)
+		spec->multiout.hp_nid = nid;
+	else if (spec->multiout.num_dacs > 4) {
+		printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
+		return 1;
+	} else {
+		spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
+		spec->multiout.num_dacs++;
+	}
+	return 0;
+}
+
+static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
+{
+	if (is_in_dac_nids(spec, nid))
+		return 1;
+	if (spec->multiout.hp_nid == nid)
+		return 1;
+	return 0;
+}
+
 /* add playback controls from the parsed DAC table */
 static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
 					       const struct auto_pin_cfg *cfg)
@@ -2236,7 +2426,7 @@
 	unsigned int wid_caps, pincap;
 
 
-	for (i = 0; i < cfg->line_outs; i++) {
+	for (i = 0; i < cfg->line_outs && i < spec->multiout.num_dacs; i++) {
 		if (!spec->multiout.dac_nids[i])
 			continue;
 
@@ -2269,6 +2459,14 @@
 		}
 	}
 
+	if (cfg->hp_outs > 1) {
+		err = stac92xx_add_control(spec,
+			STAC_CTL_WIDGET_HP_SWITCH,
+			"Headphone as Line Out Switch", 0);
+		if (err < 0)
+			return err;
+	}
+
 	if (spec->line_switch) {
 		nid = cfg->input_pins[AUTO_PIN_LINE];
 		pincap = snd_hda_param_read(codec, nid,
@@ -2284,10 +2482,11 @@
 
 	if (spec->mic_switch) {
 		unsigned int def_conf;
-		nid = cfg->input_pins[AUTO_PIN_MIC];
+		unsigned int mic_pin = AUTO_PIN_MIC;
+again:
+		nid = cfg->input_pins[mic_pin];
 		def_conf = snd_hda_codec_read(codec, nid, 0,
 						AC_VERB_GET_CONFIG_DEFAULT, 0);
-
 		/* some laptops have an internal analog microphone
 		 * which can't be used as a output */
 		if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
@@ -2297,38 +2496,22 @@
 				err = stac92xx_add_control(spec,
 					STAC_CTL_WIDGET_IO_SWITCH,
 					"Mic as Output Switch", (nid << 8) | 1);
+				nid = snd_hda_codec_read(codec, nid, 0,
+					 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
+				if (!check_in_dac_nids(spec, nid))
+					add_spec_dacs(spec, nid);
 				if (err < 0)
 					return err;
 			}
+		} else if (mic_pin == AUTO_PIN_MIC) {
+			mic_pin = AUTO_PIN_FRONT_MIC;
+			goto again;
 		}
 	}
 
 	return 0;
 }
 
-static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
-{
-	if (is_in_dac_nids(spec, nid))
-		return 1;
-	if (spec->multiout.hp_nid == nid)
-		return 1;
-	return 0;
-}
-
-static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
-{
-	if (!spec->multiout.hp_nid)
-		spec->multiout.hp_nid = nid;
-	else if (spec->multiout.num_dacs > 4) {
-		printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
-		return 1;
-	} else {
-		spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
-		spec->multiout.num_dacs++;
-	}
-	return 0;
-}
-
 /* add playback controls for Speaker and HP outputs */
 static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
 					struct auto_pin_cfg *cfg)
@@ -2378,12 +2561,8 @@
 			return err;
 	}
 	if (spec->multiout.hp_nid) {
-		const char *pfx;
-		if (old_num_dacs == spec->multiout.num_dacs)
-			pfx = "Master";
-		else
-			pfx = "Headphone";
-		err = create_controls(spec, pfx, spec->multiout.hp_nid, 3);
+		err = create_controls(spec, "Headphone",
+				      spec->multiout.hp_nid, 3);
 		if (err < 0)
 			return err;
 	}
@@ -2745,7 +2924,7 @@
 	 */
 	for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
 		hda_nid_t pin = spec->autocfg.speaker_pins[i];
-		unsigned long wcaps = get_wcaps(codec, pin);
+		unsigned int wcaps = get_wcaps(codec, pin);
 		wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
 		if (wcaps == AC_WCAP_OUT_AMP)
 			/* found a mono speaker with an amp, must be lfe */
@@ -2756,12 +2935,12 @@
 	if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
 		for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
 			hda_nid_t pin = spec->autocfg.line_out_pins[i];
-			unsigned long cfg;
-			cfg = snd_hda_codec_read(codec, pin, 0,
+			unsigned int defcfg;
+			defcfg = snd_hda_codec_read(codec, pin, 0,
 						 AC_VERB_GET_CONFIG_DEFAULT,
 						 0x00);
-			if (get_defcfg_device(cfg) == AC_JACK_SPEAKER) {
-				unsigned long wcaps = get_wcaps(codec, pin);
+			if (get_defcfg_device(defcfg) == AC_JACK_SPEAKER) {
+				unsigned int wcaps = get_wcaps(codec, pin);
 				wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
 				if (wcaps == AC_WCAP_OUT_AMP)
 					/* found a mono speaker with an amp,
@@ -2866,6 +3045,19 @@
 	return 0; /* nid is not a HP-Out */
 };
 
+static void stac92xx_power_down(struct hda_codec *codec)
+{
+	struct sigmatel_spec *spec = codec->spec;
+
+	/* power down inactive DACs */
+	hda_nid_t *dac;
+	for (dac = spec->dac_list; *dac; dac++)
+		if (!is_in_dac_nids(spec, *dac) &&
+			spec->multiout.hp_nid != *dac)
+			snd_hda_codec_write_cache(codec, *dac, 0,
+					AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+}
+
 static int stac92xx_init(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec = codec->spec;
@@ -2909,16 +3101,21 @@
 					? STAC_HP_EVENT : STAC_PWR_EVENT;
 		int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i],
 					0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+		int def_conf = snd_hda_codec_read(codec, spec->pwr_nids[i],
+					0, AC_VERB_GET_CONFIG_DEFAULT, 0);
 		/* outputs are only ports capable of power management
 		 * any attempts on powering down a input port cause the
 		 * referenced VREF to act quirky.
 		 */
 		if (pinctl & AC_PINCTL_IN_EN)
 			continue;
+		if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED)
+			continue;
 		enable_pin_detect(codec, spec->pwr_nids[i], event | i);
 		codec->patch_ops.unsol_event(codec, (event | i) << 26);
 	}
-
+	if (spec->dac_list)
+		stac92xx_power_down(codec);
 	if (cfg->dig_out_pin)
 		stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
 					 AC_PINCTL_OUT_EN);
@@ -3014,6 +3211,7 @@
 {
 	struct sigmatel_spec *spec = codec->spec;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
+	int nid = cfg->hp_pins[cfg->hp_outs - 1];
 	int i, presence;
 
 	presence = 0;
@@ -3024,26 +3222,42 @@
 	for (i = 0; i < cfg->hp_outs; i++) {
 		if (presence)
 			break;
+		if (spec->hp_switch && cfg->hp_pins[i] == nid)
+			break;
 		presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
 	}
 
 	if (presence) {
 		/* disable lineouts, enable hp */
+		if (spec->hp_switch)
+			stac92xx_reset_pinctl(codec, nid, AC_PINCTL_OUT_EN);
 		for (i = 0; i < cfg->line_outs; i++)
 			stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
 						AC_PINCTL_OUT_EN);
 		for (i = 0; i < cfg->speaker_outs; i++)
 			stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
 						AC_PINCTL_OUT_EN);
+		if (spec->eapd_mask)
+			stac_gpio_set(codec, spec->gpio_mask,
+				spec->gpio_dir, spec->gpio_data &
+				~spec->eapd_mask);
 	} else {
 		/* enable lineouts, disable hp */
+		if (spec->hp_switch)
+			stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
 		for (i = 0; i < cfg->line_outs; i++)
 			stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
 						AC_PINCTL_OUT_EN);
 		for (i = 0; i < cfg->speaker_outs; i++)
 			stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
 						AC_PINCTL_OUT_EN);
+		if (spec->eapd_mask)
+			stac_gpio_set(codec, spec->gpio_mask,
+				spec->gpio_dir, spec->gpio_data |
+				spec->eapd_mask);
 	}
+	if (!spec->hp_switch && cfg->hp_outs > 1 && presence)
+		stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
 } 
 
 static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
@@ -3091,6 +3305,9 @@
 		spec->gpio_dir, spec->gpio_data);
 	snd_hda_codec_resume_amp(codec);
 	snd_hda_codec_resume_cache(codec);
+	/* power down inactive DACs */
+	if (spec->dac_list)
+		stac92xx_power_down(codec);
 	/* invoke unsolicited event to reset the HP state */
 	if (spec->hp_detect)
 		codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
@@ -3147,12 +3364,18 @@
 	spec->num_adcs = 1;
 	spec->num_pwrs = 0;
 
-	if (spec->board_config == STAC_9200_GATEWAY)
+	if (spec->board_config == STAC_9200_GATEWAY ||
+	    spec->board_config == STAC_9200_OQO)
 		spec->init = stac9200_eapd_init;
 	else
 		spec->init = stac9200_core_init;
 	spec->mixer = stac9200_mixer;
 
+	if (spec->board_config == STAC_9200_PANASONIC) {
+		spec->gpio_mask = spec->gpio_dir = 0x09;
+		spec->gpio_data = 0x00;
+	}
+
 	err = stac9200_parse_auto_config(codec);
 	if (err < 0) {
 		stac92xx_free(codec);
@@ -3293,6 +3516,7 @@
 
 	switch (spec->multiout.num_dacs) {
 	case 0x3: /* 6 Channel */
+		spec->multiout.hp_nid = 0x17;
 		spec->mixer = stac92hd73xx_6ch_mixer;
 		spec->init = stac92hd73xx_6ch_core_init;
 		break;
@@ -3318,13 +3542,42 @@
 
 	spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
 	spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
-	spec->num_dmics = STAC92HD73XX_NUM_DMICS;
 	spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
 	spec->dinput_mux = &stac92hd73xx_dmux;
 	/* GPIO0 High = Enable EAPD */
-	spec->gpio_mask = spec->gpio_dir = 0x1;
+	spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
 	spec->gpio_data = 0x01;
 
+	switch (spec->board_config) {
+	case STAC_DELL_M6:
+		spec->init = dell_eq_core_init;
+		switch (codec->subsystem_id) {
+		case 0x1028025e: /* Analog Mics */
+		case 0x1028025f:
+			stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
+			spec->num_dmics = 0;
+			break;
+		case 0x10280271: /* Digital Mics */
+		case 0x10280272:
+			spec->init = dell_m6_core_init;
+			/* fall-through */
+		case 0x10280254:
+		case 0x10280255:
+			stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
+			spec->num_dmics = 1;
+			break;
+		case 0x10280256: /* Both */
+		case 0x10280057:
+			stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
+			stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
+			spec->num_dmics = 1;
+			break;
+		}
+		break;
+	default:
+		spec->num_dmics = STAC92HD73XX_NUM_DMICS;
+	}
+
 	spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
 	spec->pwr_nids = stac92hd73xx_pwr_nids;
 
@@ -3398,7 +3651,10 @@
 	spec->aloopback_shift = 0;
 
 	/* GPIO0 High = EAPD */
-	spec->gpio_mask = spec->gpio_dir = spec->gpio_data = 0x1;
+	spec->gpio_mask = 0x01;
+	spec->gpio_dir = 0x01;
+	spec->gpio_mask = 0x01;
+	spec->gpio_data = 0x01;
 
 	spec->mux_nids = stac92hd71bxx_mux_nids;
 	spec->adc_nids = stac92hd71bxx_adc_nids;
@@ -3413,7 +3669,7 @@
 	spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
 	spec->pwr_nids = stac92hd71bxx_pwr_nids;
 
-	spec->multiout.num_dacs = 2;
+	spec->multiout.num_dacs = 1;
 	spec->multiout.hp_nid = 0x11;
 	spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
 
@@ -3577,13 +3833,14 @@
 	spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
 	spec->mux_nids = stac927x_mux_nids;
 	spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
+	spec->dac_list = stac927x_dac_nids;
 	spec->multiout.dac_nids = spec->dac_nids;
 
 	switch (spec->board_config) {
 	case STAC_D965_3ST:
 	case STAC_D965_5ST:
 		/* GPIO0 High = Enable EAPD */
-		spec->gpio_mask = spec->gpio_dir = 0x01;
+		spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x01;
 		spec->gpio_data = 0x01;
 		spec->num_dmics = 0;
 
@@ -3591,14 +3848,23 @@
 		spec->mixer = stac927x_mixer;
 		break;
 	case STAC_DELL_BIOS:
+		switch (codec->subsystem_id) {
+		case 0x10280209:
+		case 0x1028022e:
+			/* correct the device field to SPDIF out */
+			stac92xx_set_config_reg(codec, 0x21, 0x01442070);
+			break;
+		};
+		/* configure the analog microphone on some laptops */
+		stac92xx_set_config_reg(codec, 0x0c, 0x90a79130);
 		/* correct the front output jack as a hp out */
-		stac92xx_set_config_reg(codec, 0x0f, 0x02270110);
+		stac92xx_set_config_reg(codec, 0x0f, 0x0227011f);
 		/* correct the front input jack as a mic */
 		stac92xx_set_config_reg(codec, 0x0e, 0x02a79130);
 		/* fallthru */
 	case STAC_DELL_3ST:
 		/* GPIO2 High = Enable EAPD */
-		spec->gpio_mask = spec->gpio_dir = 0x04;
+		spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x04;
 		spec->gpio_data = 0x04;
 		spec->dmic_nids = stac927x_dmic_nids;
 		spec->num_dmics = STAC927X_NUM_DMICS;
@@ -3610,7 +3876,7 @@
 		break;
 	default:
 		/* GPIO0 High = Enable EAPD */
-		spec->gpio_mask = spec->gpio_dir = 0x1;
+		spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
 		spec->gpio_data = 0x01;
 		spec->num_dmics = 0;
 
@@ -3714,6 +3980,7 @@
 					  (AC_USRSP_EN | STAC_HP_EVENT));
 
 		spec->gpio_dir = 0x0b;
+		spec->eapd_mask = 0x01;
 		spec->gpio_mask = 0x1b;
 		spec->gpio_mute = 0x10;
 		/* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute,
@@ -3723,7 +3990,7 @@
 		break;
 	default:
 		/* GPIO0 High = EAPD */
-		spec->gpio_mask = spec->gpio_dir = 0x1;
+		spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
 		spec->gpio_data = 0x01;
 		break;
 	}
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index 4e5dd4c..52b1d81 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -39,7 +39,7 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
-
+#include "hda_patch.h"
 
 /* amp values */
 #define AMP_VAL_IDX_SHIFT	19
@@ -357,7 +357,8 @@
 				 struct snd_pcm_substream *substream)
 {
 	struct via_spec *spec = codec->spec;
-	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
+					     hinfo);
 }
 
 static int via_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
@@ -430,8 +431,7 @@
 				   struct snd_pcm_substream *substream)
 {
 	struct via_spec *spec = codec->spec;
-	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
-				   0, 0, 0);
+	snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
 	return 0;
 }
 
@@ -493,6 +493,11 @@
 						    spec->multiout.dig_out_nid);
 		if (err < 0)
 			return err;
+		err = snd_hda_create_spdif_share_sw(codec,
+						    &spec->multiout);
+		if (err < 0)
+			return err;
+		spec->multiout.share_spdif = 1;
 	}
 	if (spec->dig_in_nid) {
 		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
@@ -523,6 +528,7 @@
 		codec->num_pcms++;
 		info++;
 		info->name = spec->stream_name_digital;
+		info->pcm_type = HDA_PCM_TYPE_SPDIF;
 		if (spec->multiout.dig_out_nid) {
 			info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
 				*(spec->stream_digital_playback);
diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c
index efd180b..0ed96c1 100644
--- a/sound/pci/ice1712/delta.c
+++ b/sound/pci/ice1712/delta.c
@@ -1,8 +1,8 @@
 /*
  *   ALSA driver for ICEnsemble ICE1712 (Envy24)
  *
- *   Lowlevel functions for M-Audio Delta 1010, 44, 66, Dio2496, Audiophile
- *                          Digigram VX442
+ *   Lowlevel functions for M-Audio Delta 1010, 1010E, 44, 66, 66E, Dio2496,
+ *			    Audiophile, Digigram VX442
  *
  *	Copyright (c) 2000 Jaroslav Kysela <perex@perex.cz>
  *
@@ -86,6 +86,7 @@
 	unsigned char tmp;
 	tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
 	switch (ice->eeprom.subvendor) {
+	case ICE1712_SUBDEVICE_DELTA1010E:
 	case ICE1712_SUBDEVICE_DELTA1010LT:
 		tmp &= ~ICE1712_DELTA_1010LT_CS;
 		tmp |= ICE1712_DELTA_1010LT_CCLK | ICE1712_DELTA_1010LT_CS_CS8427;
@@ -109,6 +110,7 @@
 static void ap_cs8427_codec_deassert(struct snd_ice1712 *ice, unsigned char tmp)
 {
 	switch (ice->eeprom.subvendor) {
+	case ICE1712_SUBDEVICE_DELTA1010E:
 	case ICE1712_SUBDEVICE_DELTA1010LT:
 		tmp &= ~ICE1712_DELTA_1010LT_CS;
 		tmp |= ICE1712_DELTA_1010LT_CS_NONE;
@@ -534,6 +536,14 @@
 	int err;
 	struct snd_akm4xxx *ak;
 
+	if (ice->eeprom.subvendor == ICE1712_SUBDEVICE_DELTA1010 &&
+	    ice->eeprom.gpiodir == 0x7b)
+		ice->eeprom.subvendor = ICE1712_SUBDEVICE_DELTA1010E;
+
+	if (ice->eeprom.subvendor == ICE1712_SUBDEVICE_DELTA66 &&
+	    ice->eeprom.gpiodir == 0xfb)
+	    	ice->eeprom.subvendor = ICE1712_SUBDEVICE_DELTA66E;
+
 	/* determine I2C, DACs and ADCs */
 	switch (ice->eeprom.subvendor) {
 	case ICE1712_SUBDEVICE_AUDIOPHILE:
@@ -550,6 +560,7 @@
 		ice->num_total_adcs = ice->omni ? 8 : 4;
 		break;
 	case ICE1712_SUBDEVICE_DELTA1010:
+	case ICE1712_SUBDEVICE_DELTA1010E:
 	case ICE1712_SUBDEVICE_DELTA1010LT:
 	case ICE1712_SUBDEVICE_MEDIASTATION:
 		ice->num_total_dacs = 8;
@@ -559,6 +570,7 @@
 		ice->num_total_dacs = 4;	/* two AK4324 codecs */
 		break;
 	case ICE1712_SUBDEVICE_VX442:
+	case ICE1712_SUBDEVICE_DELTA66E:	/* omni not suported yet */
 		ice->num_total_dacs = 4;
 		ice->num_total_adcs = 4;
 		break;
@@ -568,8 +580,10 @@
 	switch (ice->eeprom.subvendor) {
 	case ICE1712_SUBDEVICE_AUDIOPHILE:
 	case ICE1712_SUBDEVICE_DELTA410:
+	case ICE1712_SUBDEVICE_DELTA1010E:
 	case ICE1712_SUBDEVICE_DELTA1010LT:
 	case ICE1712_SUBDEVICE_VX442:
+	case ICE1712_SUBDEVICE_DELTA66E:
 		if ((err = snd_i2c_bus_create(ice->card, "ICE1712 GPIO 1", NULL, &ice->i2c)) < 0) {
 			snd_printk(KERN_ERR "unable to create I2C bus\n");
 			return err;
@@ -601,6 +615,7 @@
 	/* no analog? */
 	switch (ice->eeprom.subvendor) {
 	case ICE1712_SUBDEVICE_DELTA1010:
+	case ICE1712_SUBDEVICE_DELTA1010E:
 	case ICE1712_SUBDEVICE_DELTADIO2496:
 	case ICE1712_SUBDEVICE_MEDIASTATION:
 		return 0;
@@ -627,6 +642,7 @@
 		err = snd_ice1712_akm4xxx_init(ak, &akm_delta44, &akm_delta44_priv, ice);
 		break;
 	case ICE1712_SUBDEVICE_VX442:
+	case ICE1712_SUBDEVICE_DELTA66E:
 		err = snd_ice1712_akm4xxx_init(ak, &akm_vx442, &akm_vx442_priv, ice);
 		break;
 	default:
@@ -674,6 +690,7 @@
 		if (err < 0)
 			return err;
 		break;
+	case ICE1712_SUBDEVICE_DELTA1010E:
 	case ICE1712_SUBDEVICE_DELTA1010LT:
 		err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_delta1010lt_wordclock_select, ice));
 		if (err < 0)
@@ -716,6 +733,7 @@
 	case ICE1712_SUBDEVICE_DELTA44:
 	case ICE1712_SUBDEVICE_DELTA66:
 	case ICE1712_SUBDEVICE_VX442:
+	case ICE1712_SUBDEVICE_DELTA66E:
 		err = snd_ice1712_akm4xxx_build_controls(ice);
 		if (err < 0)
 			return err;
diff --git a/sound/pci/ice1712/delta.h b/sound/pci/ice1712/delta.h
index 26ea05a..ea7116c 100644
--- a/sound/pci/ice1712/delta.h
+++ b/sound/pci/ice1712/delta.h
@@ -36,8 +36,10 @@
 		"{Lionstracs,Mediastation},"
 
 #define ICE1712_SUBDEVICE_DELTA1010	0x121430d6
+#define ICE1712_SUBDEVICE_DELTA1010E	0xff1430d6
 #define ICE1712_SUBDEVICE_DELTADIO2496	0x121431d6
 #define ICE1712_SUBDEVICE_DELTA66	0x121432d6
+#define ICE1712_SUBDEVICE_DELTA66E	0xff1432d6
 #define ICE1712_SUBDEVICE_DELTA44	0x121433d6
 #define ICE1712_SUBDEVICE_AUDIOPHILE	0x121434d6
 #define ICE1712_SUBDEVICE_DELTA410	0x121438d6
diff --git a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c
index 064760d..013fc4f 100644
--- a/sound/pci/ice1712/ews.c
+++ b/sound/pci/ice1712/ews.c
@@ -238,6 +238,7 @@
 	case ICE1712_SUBDEVICE_EWS88MT:
 	case ICE1712_SUBDEVICE_EWS88MT_NEW:
 	case ICE1712_SUBDEVICE_PHASE88:
+	case ICE1712_SUBDEVICE_TS88:
 		if (snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_CS8404], &bits, 1)
 		    != 1)
 			goto _error;
@@ -433,6 +434,7 @@
 	case ICE1712_SUBDEVICE_EWS88MT:
 	case ICE1712_SUBDEVICE_EWS88MT_NEW:
 	case ICE1712_SUBDEVICE_PHASE88:
+	case ICE1712_SUBDEVICE_TS88:
 		ice->num_total_dacs = 8;
 		ice->num_total_adcs = 8;
 		break;
@@ -475,6 +477,8 @@
 	case ICE1712_SUBDEVICE_EWS88MT:
 	case ICE1712_SUBDEVICE_EWS88MT_NEW:
 	case ICE1712_SUBDEVICE_PHASE88:
+	case ICE1712_SUBDEVICE_TS88:
+
 		err = snd_i2c_device_create(ice->i2c, "CS8404",
 					    ICE1712_EWS88MT_CS8404_ADDR,
 					    &spec->i2cdevs[EWS_I2C_CS8404]);
@@ -518,6 +522,7 @@
 	case ICE1712_SUBDEVICE_EWS88MT:
 	case ICE1712_SUBDEVICE_EWS88MT_NEW:
 	case ICE1712_SUBDEVICE_PHASE88:
+	case ICE1712_SUBDEVICE_TS88:
 	case ICE1712_SUBDEVICE_EWS88D:
 		/* set up CS8404 */
 		ice->spdif.ops.open = ews88_open_spdif;
@@ -547,6 +552,7 @@
 	case ICE1712_SUBDEVICE_EWS88MT:
 	case ICE1712_SUBDEVICE_EWS88MT_NEW:
 	case ICE1712_SUBDEVICE_PHASE88:
+	case ICE1712_SUBDEVICE_TS88:
 		err = snd_ice1712_akm4xxx_init(ak, &akm_ews88mt, &akm_ews88mt_priv, ice);
 		break;
 	case ICE1712_SUBDEVICE_EWX2496:
@@ -973,6 +979,7 @@
 	case ICE1712_SUBDEVICE_EWS88MT:
 	case ICE1712_SUBDEVICE_EWS88MT_NEW:
 	case ICE1712_SUBDEVICE_PHASE88:
+	case ICE1712_SUBDEVICE_TS88:
 	case ICE1712_SUBDEVICE_DMX6FIRE:
 		err = snd_ice1712_akm4xxx_build_controls(ice);
 		if (err < 0)
@@ -992,6 +999,7 @@
 	case ICE1712_SUBDEVICE_EWS88MT:
 	case ICE1712_SUBDEVICE_EWS88MT_NEW:
 	case ICE1712_SUBDEVICE_PHASE88:
+	case ICE1712_SUBDEVICE_TS88:
 		err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_ews88mt_input_sense, ice));
 		if (err < 0)
 			return err;
@@ -1049,6 +1057,13 @@
 		.build_controls = snd_ice1712_ews_add_controls,
 	},
 	{
+		.subvendor = ICE1712_SUBDEVICE_TS88,
+		.name = "terrasoniq TS88",
+		.model = "phase88",
+		.chip_init = snd_ice1712_ews_init,
+		.build_controls = snd_ice1712_ews_add_controls,
+	},
+	{
 		.subvendor = ICE1712_SUBDEVICE_EWS88D,
 		.name = "TerraTec EWS88D",
 		.model = "ews88d",
diff --git a/sound/pci/ice1712/ews.h b/sound/pci/ice1712/ews.h
index e4ed1b4..1c44371 100644
--- a/sound/pci/ice1712/ews.h
+++ b/sound/pci/ice1712/ews.h
@@ -30,7 +30,8 @@
 		"{TerraTec,EWS 88MT},"\
 		"{TerraTec,EWS 88D},"\
 		"{TerraTec,DMX 6Fire},"\
-		"{TerraTec,Phase 88},"
+		"{TerraTec,Phase 88}," \
+		"{terrasoniq,TS 88},"
 
 #define ICE1712_SUBDEVICE_EWX2496	0x3b153011
 #define ICE1712_SUBDEVICE_EWS88MT	0x3b151511
@@ -38,6 +39,7 @@
 #define ICE1712_SUBDEVICE_EWS88D	0x3b152b11
 #define ICE1712_SUBDEVICE_DMX6FIRE	0x3b153811
 #define ICE1712_SUBDEVICE_PHASE88	0x3b155111
+#define ICE1712_SUBDEVICE_TS88   	0x3b157c11
 
 /* entry point */
 extern struct snd_ice1712_card_info snd_ice1712_ews_cards[];
diff --git a/sound/pci/ice1712/hoontech.c b/sound/pci/ice1712/hoontech.c
index cf5c7c08..6914189 100644
--- a/sound/pci/ice1712/hoontech.c
+++ b/sound/pci/ice1712/hoontech.c
@@ -208,6 +208,19 @@
 			    /* ICE1712_STDSP24_MUTE |
 			       ICE1712_STDSP24_INSEL |
 			       ICE1712_STDSP24_DAREAR; */
+	/*  These boxconfigs have caused problems in the past.
+	 *  The code is not optimal, but should now enable a working config to
+	 *  be achieved.
+	 *  ** MIDI IN can only be configured on one box **
+	 *  ICE1712_STDSP24_BOX_MIDI1 needs to be set for that box.
+	 *  Tests on a ADAC2000 box suggest the box config flags do not
+	 *  work as would be expected, and the inputs are crossed.
+	 *  Setting ICE1712_STDSP24_BOX_MIDI1 and ICE1712_STDSP24_BOX_MIDI2
+	 *  on the same box connects MIDI-In to both 401 uarts; both outputs
+	 *  are then active on all boxes.
+	 *  The default config here sets up everything on the first box.
+	 *  Alan Horstmann  5.2.2008
+	 */
 	spec->boxconfig[0] = ICE1712_STDSP24_BOX_CHN1 |
 				     ICE1712_STDSP24_BOX_CHN2 |
 				     ICE1712_STDSP24_BOX_CHN3 |
@@ -223,14 +236,14 @@
 		(spec->config & ICE1712_STDSP24_MUTE) ? 1 : 0);
 	snd_ice1712_stdsp24_insel(ice,
 		(spec->config & ICE1712_STDSP24_INSEL) ? 1 : 0);
-	for (box = 0; box < 1; box++) {
+	for (box = 0; box < 4; box++) {
 		if (spec->boxconfig[box] & ICE1712_STDSP24_BOX_MIDI2)
                         snd_ice1712_stdsp24_midi2(ice, 1);
 		for (chn = 0; chn < 4; chn++)
 			snd_ice1712_stdsp24_box_channel(ice, box, chn,
 				(spec->boxconfig[box] & (1 << chn)) ? 1 : 0);
-		snd_ice1712_stdsp24_box_midi(ice, box,
-				(spec->boxconfig[box] & ICE1712_STDSP24_BOX_MIDI1) ? 1 : 0);
+		if (spec->boxconfig[box] & ICE1712_STDSP24_BOX_MIDI1)
+			snd_ice1712_stdsp24_box_midi(ice, box, 1);
 	}
 
 	return 0;
@@ -322,6 +335,8 @@
 		.name = "Hoontech SoundTrack Audio DSP24",
 		.model = "dsp24",
 		.chip_init = snd_ice1712_hoontech_init,
+		.mpu401_1_name = "MIDI-1 Hoontech/STA DSP24",
+		.mpu401_2_name = "MIDI-2 Hoontech/STA DSP24",
 	},
 	{
 		.subvendor = ICE1712_SUBDEVICE_STDSP24_VALUE,	/* a dummy id */
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index df292af..29d449d 100644
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -1297,11 +1297,14 @@
 static int snd_ice1712_pro_mixer_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-	int index = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + kcontrol->private_value;
+	int priv_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) +
+		kcontrol->private_value;
 	
 	spin_lock_irq(&ice->reg_lock);
-	ucontrol->value.integer.value[0] = !((ice->pro_volumes[index] >> 15) & 1);
-	ucontrol->value.integer.value[1] = !((ice->pro_volumes[index] >> 31) & 1);
+	ucontrol->value.integer.value[0] =
+		!((ice->pro_volumes[priv_idx] >> 15) & 1);
+	ucontrol->value.integer.value[1] =
+		!((ice->pro_volumes[priv_idx] >> 31) & 1);
 	spin_unlock_irq(&ice->reg_lock);
 	return 0;
 }
@@ -1309,16 +1312,17 @@
 static int snd_ice1712_pro_mixer_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-	int index = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + kcontrol->private_value;
+	int priv_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) +
+		kcontrol->private_value;
 	unsigned int nval, change;
 
 	nval = (ucontrol->value.integer.value[0] ? 0 : 0x00008000) |
 	       (ucontrol->value.integer.value[1] ? 0 : 0x80000000);
 	spin_lock_irq(&ice->reg_lock);
-	nval |= ice->pro_volumes[index] & ~0x80008000;
-	change = nval != ice->pro_volumes[index];
-	ice->pro_volumes[index] = nval;
-	snd_ice1712_update_volume(ice, index);
+	nval |= ice->pro_volumes[priv_idx] & ~0x80008000;
+	change = nval != ice->pro_volumes[priv_idx];
+	ice->pro_volumes[priv_idx] = nval;
+	snd_ice1712_update_volume(ice, priv_idx);
 	spin_unlock_irq(&ice->reg_lock);
 	return change;
 }
@@ -1335,11 +1339,14 @@
 static int snd_ice1712_pro_mixer_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-	int index = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + kcontrol->private_value;
+	int priv_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) +
+		kcontrol->private_value;
 	
 	spin_lock_irq(&ice->reg_lock);
-	ucontrol->value.integer.value[0] = (ice->pro_volumes[index] >> 0) & 127;
-	ucontrol->value.integer.value[1] = (ice->pro_volumes[index] >> 16) & 127;
+	ucontrol->value.integer.value[0] =
+		(ice->pro_volumes[priv_idx] >> 0) & 127;
+	ucontrol->value.integer.value[1] =
+		(ice->pro_volumes[priv_idx] >> 16) & 127;
 	spin_unlock_irq(&ice->reg_lock);
 	return 0;
 }
@@ -1347,16 +1354,17 @@
 static int snd_ice1712_pro_mixer_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-	int index = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + kcontrol->private_value;
+	int priv_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) +
+		kcontrol->private_value;
 	unsigned int nval, change;
 
 	nval = (ucontrol->value.integer.value[0] & 127) |
 	       ((ucontrol->value.integer.value[1] & 127) << 16);
 	spin_lock_irq(&ice->reg_lock);
-	nval |= ice->pro_volumes[index] & ~0x007f007f;
-	change = nval != ice->pro_volumes[index];
-	ice->pro_volumes[index] = nval;
-	snd_ice1712_update_volume(ice, index);
+	nval |= ice->pro_volumes[priv_idx] & ~0x007f007f;
+	change = nval != ice->pro_volumes[priv_idx];
+	ice->pro_volumes[priv_idx] = nval;
+	snd_ice1712_update_volume(ice, priv_idx);
 	spin_unlock_irq(&ice->reg_lock);
 	return change;
 }
@@ -2482,10 +2490,9 @@
 	outb(0xff, ICEREG(ice, IRQMASK));
 	/* --- */
       __hw_end:
-	if (ice->irq >= 0) {
-		synchronize_irq(ice->irq);
+	if (ice->irq >= 0)
 		free_irq(ice->irq, ice);
-	}
+
 	if (ice->port)
 		pci_release_regions(ice->pci);
 	snd_ice1712_akm4xxx_free(ice);
diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h
index 303cffe..3208901 100644
--- a/sound/pci/ice1712/ice1712.h
+++ b/sound/pci/ice1712/ice1712.h
@@ -367,6 +367,15 @@
 
 	/* other board-specific data */
 	void *spec;
+
+	/* VT172x specific */
+	int pro_rate_default;
+	int (*is_spdif_master)(struct snd_ice1712 *ice);
+	unsigned int (*get_rate)(struct snd_ice1712 *ice);
+	void (*set_rate)(struct snd_ice1712 *ice, unsigned int rate);
+	unsigned char (*set_mclk)(struct snd_ice1712 *ice, unsigned int rate);
+	void (*set_spdif_clock)(struct snd_ice1712 *ice);
+
 };
 
 
@@ -429,10 +438,14 @@
 static inline void snd_ice1712_gpio_write_bits(struct snd_ice1712 *ice,
 					       unsigned int mask, unsigned int bits)
 {
+	unsigned val;
+
 	ice->gpio.direction |= mask;
 	snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
-	snd_ice1712_gpio_set_mask(ice, ~mask);
-	snd_ice1712_gpio_write(ice, mask & bits);
+	val = snd_ice1712_gpio_read(ice);
+	val &= ~mask;
+	val |= mask & bits;
+	snd_ice1712_gpio_write(ice, val);
 }
 
 static inline int snd_ice1712_gpio_read_bits(struct snd_ice1712 *ice,
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index f533850..4490422 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -106,15 +106,19 @@
  *  Basic I/O
  */
  
+/*
+ *  default rates, default clock routines
+ */
+
 /* check whether the clock mode is spdif-in */
-static inline int is_spdif_master(struct snd_ice1712 *ice)
+static inline int stdclock_is_spdif_master(struct snd_ice1712 *ice)
 {
 	return (inb(ICEMT1724(ice, RATE)) & VT1724_SPDIF_MASTER) ? 1 : 0;
 }
 
 static inline int is_pro_rate_locked(struct snd_ice1712 *ice)
 {
-	return is_spdif_master(ice) || PRO_RATE_LOCKED;
+	return ice->is_spdif_master(ice) || PRO_RATE_LOCKED;
 }
 
 /*
@@ -219,6 +223,32 @@
 }
 
 /*
+ * MPU401 accessor
+ */
+static unsigned char snd_vt1724_mpu401_read(struct snd_mpu401 *mpu,
+					    unsigned long addr)
+{
+	/* fix status bits to the standard position */
+	/* only RX_EMPTY and TX_FULL are checked */
+	if (addr == MPU401C(mpu))
+		return (inb(addr) & 0x0c) << 4;
+	else
+		return inb(addr);
+}
+
+static void snd_vt1724_mpu401_write(struct snd_mpu401 *mpu,
+				    unsigned char data, unsigned long addr)
+{
+	if (addr == MPU401C(mpu)) {
+		if (data == MPU401_ENTER_UART)
+			outb(0x01, addr);
+		/* what else? */
+	} else
+		outb(data, addr);
+}
+
+
+/*
  *  Interrupt handler
  */
 
@@ -226,24 +256,53 @@
 {
 	struct snd_ice1712 *ice = dev_id;
 	unsigned char status;
+	unsigned char status_mask =
+		VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX | VT1724_IRQ_MTPCM;
 	int handled = 0;
+#ifdef CONFIG_SND_DEBUG
+	int timeout = 0;
+#endif
 
 	while (1) {
 		status = inb(ICEREG1724(ice, IRQSTAT));
+		status &= status_mask;
 		if (status == 0)
 			break;
-
-		handled = 1;		
-		/* these should probably be separated at some point, 
-		 * but as we don't currently have MPU support on the board
-		 * I will leave it
-		 */
-		if ((status & VT1724_IRQ_MPU_RX)||(status & VT1724_IRQ_MPU_TX)) {
-			if (ice->rmidi[0])
-				snd_mpu401_uart_interrupt(irq, ice->rmidi[0]->private_data);
-			outb(status & (VT1724_IRQ_MPU_RX|VT1724_IRQ_MPU_TX), ICEREG1724(ice, IRQSTAT));
-			status &= ~(VT1724_IRQ_MPU_RX|VT1724_IRQ_MPU_TX);
+#ifdef CONFIG_SND_DEBUG
+		if (++timeout > 10) {
+			printk(KERN_ERR
+			       "ice1724: Too long irq loop, status = 0x%x\n",
+			       status);
+			break;
 		}
+#endif
+		handled = 1;		
+		if (status & VT1724_IRQ_MPU_TX) {
+			if (ice->rmidi[0])
+				snd_mpu401_uart_interrupt_tx(irq,
+					ice->rmidi[0]->private_data);
+			else /* disable TX to be sure */
+				outb(inb(ICEREG1724(ice, IRQMASK)) |
+				     VT1724_IRQ_MPU_TX,
+				     ICEREG1724(ice, IRQMASK));
+			/* Due to mysterical reasons, MPU_TX is always
+			 * generated (and can't be cleared) when a PCM
+			 * playback is going.  So let's ignore at the
+			 * next loop.
+			 */
+			status_mask &= ~VT1724_IRQ_MPU_TX;
+		}
+		if (status & VT1724_IRQ_MPU_RX) {
+			if (ice->rmidi[0])
+				snd_mpu401_uart_interrupt(irq,
+					ice->rmidi[0]->private_data);
+			else /* disable RX to be sure */
+				outb(inb(ICEREG1724(ice, IRQMASK)) |
+				     VT1724_IRQ_MPU_RX,
+				     ICEREG1724(ice, IRQMASK));
+		}
+		/* ack MPU irq */
+		outb(status, ICEREG1724(ice, IRQSTAT));
 		if (status & VT1724_IRQ_MTPCM) {
 			/*
 			 * Multi-track PCM
@@ -391,51 +450,61 @@
 #define DMA_PAUSES	(VT1724_RDMA0_PAUSE|VT1724_PDMA0_PAUSE|VT1724_RDMA1_PAUSE|\
 	VT1724_PDMA1_PAUSE|VT1724_PDMA2_PAUSE|VT1724_PDMA3_PAUSE|VT1724_PDMA4_PAUSE)
 
-static int get_max_rate(struct snd_ice1712 *ice)
+static const unsigned int stdclock_rate_list[16] = {
+	48000, 24000, 12000, 9600, 32000, 16000, 8000, 96000, 44100,
+	22050, 11025, 88200, 176400, 0, 192000, 64000
+};
+
+static unsigned int stdclock_get_rate(struct snd_ice1712 *ice)
 {
+	unsigned int rate;
+	rate = stdclock_rate_list[inb(ICEMT1724(ice, RATE)) & 15];
+	return rate;
+}
+
+static void stdclock_set_rate(struct snd_ice1712 *ice, unsigned int rate)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(stdclock_rate_list); i++) {
+		if (stdclock_rate_list[i] == rate) {
+			outb(i, ICEMT1724(ice, RATE));
+			return;
+		}
+	}
+}
+
+static unsigned char stdclock_set_mclk(struct snd_ice1712 *ice,
+				       unsigned int rate)
+{
+	unsigned char val, old;
+	/* check MT02 */
 	if (ice->eeprom.data[ICE_EEP2_ACLINK] & VT1724_CFG_PRO_I2S) {
-		if ((ice->eeprom.data[ICE_EEP2_I2S] & 0x08) && !ice->vt1720)
-			return 192000;
+		val = old = inb(ICEMT1724(ice, I2S_FORMAT));
+		if (rate > 96000)
+			val |= VT1724_MT_I2S_MCLK_128X; /* 128x MCLK */
 		else
-			return 96000;
-	} else
-		return 48000;
+			val &= ~VT1724_MT_I2S_MCLK_128X; /* 256x MCLK */
+		if (val != old) {
+			outb(val, ICEMT1724(ice, I2S_FORMAT));
+			/* master clock changed */
+			return 1;
+		}
+	}
+	/* no change in master clock */
+	return 0;
 }
 
 static void snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate,
 				    int force)
 {
 	unsigned long flags;
-	unsigned char val, old;
-	unsigned int i, mclk_change;
+	unsigned char mclk_change;
+	unsigned int i, old_rate;
 
-	if (rate > get_max_rate(ice))
+	if (rate > ice->hw_rates->list[ice->hw_rates->count - 1])
 		return;
-
-	switch (rate) {
-	case 8000: val = 6; break;
-	case 9600: val = 3; break;
-	case 11025: val = 10; break;
-	case 12000: val = 2; break;
-	case 16000: val = 5; break;
-	case 22050: val = 9; break;
-	case 24000: val = 1; break;
-	case 32000: val = 4; break;
-	case 44100: val = 8; break;
-	case 48000: val = 0; break;
-	case 64000: val = 15; break;
-	case 88200: val = 11; break;
-	case 96000: val = 7; break;
-	case 176400: val = 12; break;
-	case 192000: val = 14; break;
-	default:
-		snd_BUG();
-		val = 0;
-		break;
-	}
-
 	spin_lock_irqsave(&ice->reg_lock, flags);
-	if ((inb(ICEMT1724(ice, DMA_CONTROL)) & DMA_STARTS) || 
+	if ((inb(ICEMT1724(ice, DMA_CONTROL)) & DMA_STARTS) ||
 	    (inb(ICEMT1724(ice, DMA_PAUSE)) & DMA_PAUSES)) {
 		/* running? we cannot change the rate now... */
 		spin_unlock_irqrestore(&ice->reg_lock, flags);
@@ -446,9 +515,9 @@
 		return;
 	}
 
-	old = inb(ICEMT1724(ice, RATE));
-	if (force || old != val)
-		outb(val, ICEMT1724(ice, RATE));
+	old_rate = ice->get_rate(ice);
+	if (force || (old_rate != rate))
+		ice->set_rate(ice, rate);
 	else if (rate == ice->cur_rate) {
 		spin_unlock_irqrestore(&ice->reg_lock, flags);
 		return;
@@ -456,19 +525,9 @@
 
 	ice->cur_rate = rate;
 
-	/* check MT02 */
-	mclk_change = 0;
-	if (ice->eeprom.data[ICE_EEP2_ACLINK] & VT1724_CFG_PRO_I2S) {
-		val = old = inb(ICEMT1724(ice, I2S_FORMAT));
-		if (rate > 96000)
-			val |= VT1724_MT_I2S_MCLK_128X; /* 128x MCLK */
-		else
-			val &= ~VT1724_MT_I2S_MCLK_128X; /* 256x MCLK */
-		if (val != old) {
-			outb(val, ICEMT1724(ice, I2S_FORMAT));
-			mclk_change = 1;
-		}
-	}
+	/* setting master clock */
+	mclk_change = ice->set_mclk(ice, rate);
+
 	spin_unlock_irqrestore(&ice->reg_lock, flags);
 
 	if (mclk_change && ice->gpio.i2s_mclk_changed)
@@ -727,43 +786,32 @@
 /*
  * set rate constraints
  */
-static int set_rate_constraints(struct snd_ice1712 *ice,
-				struct snd_pcm_substream *substream)
+static void set_std_hw_rates(struct snd_ice1712 *ice)
 {
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	if (ice->hw_rates) {
-		/* hardware specific */
-		runtime->hw.rate_min = ice->hw_rates->list[0];
-		runtime->hw.rate_max = ice->hw_rates->list[ice->hw_rates->count - 1];
-		runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
-		return snd_pcm_hw_constraint_list(runtime, 0,
-						  SNDRV_PCM_HW_PARAM_RATE,
-						  ice->hw_rates);
-	}
 	if (ice->eeprom.data[ICE_EEP2_ACLINK] & VT1724_CFG_PRO_I2S) {
 		/* I2S */
 		/* VT1720 doesn't support more than 96kHz */
 		if ((ice->eeprom.data[ICE_EEP2_I2S] & 0x08) && !ice->vt1720)
-			return snd_pcm_hw_constraint_list(runtime, 0,
-							  SNDRV_PCM_HW_PARAM_RATE,
-							  &hw_constraints_rates_192);
-		else {
-			runtime->hw.rates = SNDRV_PCM_RATE_KNOT |
-				SNDRV_PCM_RATE_8000_96000;
-			runtime->hw.rate_max = 96000;
-			return snd_pcm_hw_constraint_list(runtime, 0,
-							  SNDRV_PCM_HW_PARAM_RATE,
-							  &hw_constraints_rates_96);
-		}
-	} else if (ice->ac97) {
+			ice->hw_rates = &hw_constraints_rates_192;
+		else
+			ice->hw_rates = &hw_constraints_rates_96;
+	} else {
 		/* ACLINK */
-		runtime->hw.rate_max = 48000;
-		runtime->hw.rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000;
-		return snd_pcm_hw_constraint_list(runtime, 0,
-						  SNDRV_PCM_HW_PARAM_RATE,
-						  &hw_constraints_rates_48);
+		ice->hw_rates = &hw_constraints_rates_48;
 	}
-	return 0;
+}
+
+static int set_rate_constraints(struct snd_ice1712 *ice,
+				struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	runtime->hw.rate_min = ice->hw_rates->list[0];
+	runtime->hw.rate_max = ice->hw_rates->list[ice->hw_rates->count - 1];
+	runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
+	return snd_pcm_hw_constraint_list(runtime, 0,
+					  SNDRV_PCM_HW_PARAM_RATE,
+					  ice->hw_rates);
 }
 
 /* multi-channel playback needs alignment 8x32bit regardless of the channels
@@ -824,7 +872,7 @@
 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
 
 	if (PRO_RATE_RESET)
-		snd_vt1724_set_pro_rate(ice, PRO_RATE_DEFAULT, 0);
+		snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 0);
 	ice->playback_pro_substream = NULL;
 
 	return 0;
@@ -835,7 +883,7 @@
 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
 
 	if (PRO_RATE_RESET)
-		snd_vt1724_set_pro_rate(ice, PRO_RATE_DEFAULT, 0);
+		snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 0);
 	ice->capture_pro_substream = NULL;
 	return 0;
 }
@@ -970,6 +1018,8 @@
 				   VT1724_BUFFER_ALIGN);
 	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
 				   VT1724_BUFFER_ALIGN);
+	if (ice->spdif.ops.open)
+		ice->spdif.ops.open(ice, substream);
 	return 0;
 }
 
@@ -978,8 +1028,10 @@
 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
 
 	if (PRO_RATE_RESET)
-		snd_vt1724_set_pro_rate(ice, PRO_RATE_DEFAULT, 0);
+		snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 0);
 	ice->playback_con_substream = NULL;
+	if (ice->spdif.ops.close)
+		ice->spdif.ops.close(ice, substream);
 
 	return 0;
 }
@@ -1002,6 +1054,8 @@
 				   VT1724_BUFFER_ALIGN);
 	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
 				   VT1724_BUFFER_ALIGN);
+	if (ice->spdif.ops.open)
+		ice->spdif.ops.open(ice, substream);
 	return 0;
 }
 
@@ -1010,8 +1064,10 @@
 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
 
 	if (PRO_RATE_RESET)
-		snd_vt1724_set_pro_rate(ice, PRO_RATE_DEFAULT, 0);
+		snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 0);
 	ice->capture_con_substream = NULL;
+	if (ice->spdif.ops.close)
+		ice->spdif.ops.close(ice, substream);
 
 	return 0;
 }
@@ -1154,7 +1210,7 @@
 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
 
 	if (PRO_RATE_RESET)
-		snd_vt1724_set_pro_rate(ice, PRO_RATE_DEFAULT, 0);
+		snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 0);
 	ice->playback_con_substream_ds[substream->number] = NULL;
 	ice->pcm_reserved[substream->number] = NULL;
 
@@ -1572,50 +1628,18 @@
 static int snd_vt1724_pro_internal_clock_info(struct snd_kcontrol *kcontrol,
 					      struct snd_ctl_elem_info *uinfo)
 {
-	static const char * const texts_1724[] = {
-		"8000",		/* 0: 6 */
-		"9600",		/* 1: 3 */
-		"11025",	/* 2: 10 */
-		"12000",	/* 3: 2 */
-		"16000",	/* 4: 5 */
-		"22050",	/* 5: 9 */
-		"24000",	/* 6: 1 */
-		"32000",	/* 7: 4 */
-		"44100",	/* 8: 8 */
-		"48000",	/* 9: 0 */
-		"64000",	/* 10: 15 */
-		"88200",	/* 11: 11 */
-		"96000",	/* 12: 7 */
-		"176400",	/* 13: 12 */
-		"192000",	/* 14: 14 */
-		"IEC958 Input",	/* 15: -- */
-	};
-	static const char * const texts_1720[] = {
-		"8000",		/* 0: 6 */
-		"9600",		/* 1: 3 */
-		"11025",	/* 2: 10 */
-		"12000",	/* 3: 2 */
-		"16000",	/* 4: 5 */
-		"22050",	/* 5: 9 */
-		"24000",	/* 6: 1 */
-		"32000",	/* 7: 4 */
-		"44100",	/* 8: 8 */
-		"48000",	/* 9: 0 */
-		"64000",	/* 10: 15 */
-		"88200",	/* 11: 11 */
-		"96000",	/* 12: 7 */
-		"IEC958 Input",	/* 13: -- */
-	};
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->count = 1;
-	uinfo->value.enumerated.items = ice->vt1720 ? 14 : 16;
+	uinfo->value.enumerated.items = ice->hw_rates->count + 1;
 	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
 		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
-	strcpy(uinfo->value.enumerated.name,
-	       ice->vt1720 ? texts_1720[uinfo->value.enumerated.item] :
-	       texts_1724[uinfo->value.enumerated.item]);
+	if (uinfo->value.enumerated.item == uinfo->value.enumerated.items - 1)
+		strcpy(uinfo->value.enumerated.name, "IEC958 Input");
+	else
+		sprintf(uinfo->value.enumerated.name, "%d",
+			ice->hw_rates->list[uinfo->value.enumerated.item]);
 	return 0;
 }
 
@@ -1623,68 +1647,79 @@
 					     struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-	static const unsigned char xlate[16] = {
-		9, 6, 3, 1, 7, 4, 0, 12, 8, 5, 2, 11, 13, 255, 14, 10
-	};
-	unsigned char val;
+	unsigned int i, rate;
 	
 	spin_lock_irq(&ice->reg_lock);
-	if (is_spdif_master(ice)) {
-		ucontrol->value.enumerated.item[0] = ice->vt1720 ? 13 : 15;
+	if (ice->is_spdif_master(ice)) {
+		ucontrol->value.enumerated.item[0] = ice->hw_rates->count;
 	} else {
-		val = xlate[inb(ICEMT1724(ice, RATE)) & 15];
-		if (val == 255) {
-			snd_BUG();
-			val = 0;
+		rate = ice->get_rate(ice);
+		ucontrol->value.enumerated.item[0] = 0;
+		for (i = 0; i < ice->hw_rates->count; i++) {
+			if (ice->hw_rates->list[i] == rate) {
+				ucontrol->value.enumerated.item[0] = i;
+				break;
+			}
 		}
-		ucontrol->value.enumerated.item[0] = val;
 	}
 	spin_unlock_irq(&ice->reg_lock);
 	return 0;
 }
 
+/* setting clock to external - SPDIF */
+static void stdclock_set_spdif_clock(struct snd_ice1712 *ice)
+{
+	unsigned char oval;
+	unsigned char i2s_oval;
+	oval = inb(ICEMT1724(ice, RATE));
+	outb(oval | VT1724_SPDIF_MASTER, ICEMT1724(ice, RATE));
+	/* setting 256fs */
+	i2s_oval = inb(ICEMT1724(ice, I2S_FORMAT));
+	outb(i2s_oval & ~VT1724_MT_I2S_MCLK_128X, ICEMT1724(ice, I2S_FORMAT));
+}
+
 static int snd_vt1724_pro_internal_clock_put(struct snd_kcontrol *kcontrol,
 					     struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-	unsigned char oval;
-	int rate;
-	int change = 0;
-	int spdif = ice->vt1720 ? 13 : 15;
+	unsigned int old_rate, new_rate;
+	unsigned int item = ucontrol->value.enumerated.item[0];
+	unsigned int spdif = ice->hw_rates->count;
+
+	if (item > spdif)
+		return -EINVAL;
 
 	spin_lock_irq(&ice->reg_lock);
-	oval = inb(ICEMT1724(ice, RATE));
-	if (ucontrol->value.enumerated.item[0] == spdif) {
-		unsigned char i2s_oval;
-		outb(oval | VT1724_SPDIF_MASTER, ICEMT1724(ice, RATE));
-		/* setting 256fs */
-		i2s_oval = inb(ICEMT1724(ice, I2S_FORMAT));
-		outb(i2s_oval & ~VT1724_MT_I2S_MCLK_128X,
-		     ICEMT1724(ice, I2S_FORMAT));
+	if (ice->is_spdif_master(ice))
+		old_rate = 0;
+	else
+		old_rate = ice->get_rate(ice);
+	if (item == spdif) {
+		/* switching to external clock via SPDIF */
+		ice->set_spdif_clock(ice);
+		new_rate = 0;
 	} else {
-		rate = rates[ucontrol->value.integer.value[0] % 15];
-		if (rate <= get_max_rate(ice)) {
-			PRO_RATE_DEFAULT = rate;
-			spin_unlock_irq(&ice->reg_lock);
-			snd_vt1724_set_pro_rate(ice, PRO_RATE_DEFAULT, 1);
-			spin_lock_irq(&ice->reg_lock);
-		}
+		/* internal on-card clock */
+		new_rate = ice->hw_rates->list[item];
+		ice->pro_rate_default = new_rate;
+		spin_unlock_irq(&ice->reg_lock);
+		snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 1);
+		spin_lock_irq(&ice->reg_lock);
 	}
-	change = inb(ICEMT1724(ice, RATE)) != oval;
 	spin_unlock_irq(&ice->reg_lock);
 
-	if ((oval & VT1724_SPDIF_MASTER) !=
-	    (inb(ICEMT1724(ice, RATE)) & VT1724_SPDIF_MASTER)) {
+	/* the first reset to the SPDIF master mode? */
+	if (old_rate != new_rate && !new_rate) {
 		/* notify akm chips as well */
-		if (is_spdif_master(ice)) {
-			unsigned int i;
-			for (i = 0; i < ice->akm_codecs; i++) {
-				if (ice->akm[i].ops.set_rate_val)
-					ice->akm[i].ops.set_rate_val(&ice->akm[i], 0);
-			}
+		unsigned int i;
+		if (ice->gpio.set_pro_rate)
+			ice->gpio.set_pro_rate(ice, 0);
+		for (i = 0; i < ice->akm_codecs; i++) {
+			if (ice->akm[i].ops.set_rate_val)
+				ice->akm[i].ops.set_rate_val(&ice->akm[i], 0);
 		}
 	}
-	return change;
+	return old_rate != new_rate;
 }
 
 static struct snd_kcontrol_new snd_vt1724_pro_internal_clock __devinitdata = {
@@ -2065,12 +2100,16 @@
 
 
 
-static int __devinit snd_vt1724_chip_init(struct snd_ice1712 *ice)
+static void __devinit snd_vt1724_chip_reset(struct snd_ice1712 *ice)
 {
 	outb(VT1724_RESET , ICEREG1724(ice, CONTROL));
-	udelay(200);
+	msleep(10);
 	outb(0, ICEREG1724(ice, CONTROL));
-	udelay(200);
+	msleep(10);
+}
+
+static int __devinit snd_vt1724_chip_init(struct snd_ice1712 *ice)
+{
 	outb(ice->eeprom.data[ICE_EEP2_SYSCONF], ICEREG1724(ice, SYS_CFG));
 	outb(ice->eeprom.data[ICE_EEP2_ACLINK], ICEREG1724(ice, AC97_CFG));
 	outb(ice->eeprom.data[ICE_EEP2_I2S], ICEREG1724(ice, I2S_FEATURES));
@@ -2169,10 +2208,8 @@
 	outb(0xff, ICEREG1724(ice, IRQMASK));
 	/* --- */
       __hw_end:
-	if (ice->irq >= 0) {
-		synchronize_irq(ice->irq);
+	if (ice->irq >= 0)
 		free_irq(ice->irq, ice);
-	}
 	pci_release_regions(ice->pci);
 	snd_ice1712_akm4xxx_free(ice);
 	pci_disable_device(ice->pci);
@@ -2243,6 +2280,7 @@
 
 	ice->irq = pci->irq;
 
+	snd_vt1724_chip_reset(ice);
 	if (snd_vt1724_read_eeprom(ice, modelname) < 0) {
 		snd_vt1724_free(ice);
 		return -EIO;
@@ -2253,10 +2291,7 @@
 	}
 
 	/* unmask used interrupts */
-	if (! (ice->eeprom.data[ICE_EEP2_SYSCONF] & VT1724_CFG_MPU401))
-		mask = VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX;
-	else
-		mask = 0;
+	mask = VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX;
 	outb(mask, ICEREG1724(ice, IRQMASK));
 	/* don't handle FIFO overrun/underruns (just yet),
 	 * since they cause machine lockups
@@ -2335,6 +2370,19 @@
         * was called so in ice1712 driver, and vt1724 driver is derived from
         * ice1712 driver.
         */
+	ice->pro_rate_default = PRO_RATE_DEFAULT;
+	if (!ice->is_spdif_master)
+		ice->is_spdif_master = stdclock_is_spdif_master;
+	if (!ice->get_rate)
+		ice->get_rate = stdclock_get_rate;
+	if (!ice->set_rate)
+		ice->set_rate = stdclock_set_rate;
+	if (!ice->set_mclk)
+		ice->set_mclk = stdclock_set_mclk;
+	if (!ice->set_spdif_clock)
+		ice->set_spdif_clock = stdclock_set_spdif_clock;
+	if (!ice->hw_rates)
+		set_std_hw_rates(ice);
 
 	if ((err = snd_vt1724_pcm_profi(ice, pcm_dev++)) < 0) {
 		snd_card_free(card);
@@ -2377,14 +2425,29 @@
 
 	if (! c->no_mpu401) {
 		if (ice->eeprom.data[ICE_EEP2_SYSCONF] & VT1724_CFG_MPU401) {
+			struct snd_mpu401 *mpu;
 			if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712,
 						       ICEREG1724(ice, MPU_CTRL),
-						       MPU401_INFO_INTEGRATED,
+						       (MPU401_INFO_INTEGRATED |
+							MPU401_INFO_TX_IRQ),
 						       ice->irq, 0,
 						       &ice->rmidi[0])) < 0) {
 				snd_card_free(card);
 				return err;
 			}
+			mpu = ice->rmidi[0]->private_data;
+			mpu->read = snd_vt1724_mpu401_read;
+			mpu->write = snd_vt1724_mpu401_write;
+			/* unmask MPU RX/TX irqs */
+			outb(inb(ICEREG1724(ice, IRQMASK)) &
+			     ~(VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX),
+			     ICEREG1724(ice, IRQMASK));
+#if 0 /* for testing */
+			/* set watermarks */
+			outb(VT1724_MPU_RX_FIFO | 0x1,
+			     ICEREG1724(ice, MPU_FIFO_WM));
+			outb(0x1, ICEREG1724(ice, MPU_FIFO_WM));
+#endif
 		}
 	}
 
diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c
index e8038c0..b4e0c16 100644
--- a/sound/pci/ice1712/juli.c
+++ b/sound/pci/ice1712/juli.c
@@ -4,6 +4,8 @@
  *   Lowlevel functions for ESI Juli@ cards
  *
  *	Copyright (c) 2004 Jaroslav Kysela <perex@perex.cz>
+ *	              2008 Pavel Hofman <dustin@seznam.cz>
+ *
  *
  *   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
@@ -27,11 +29,11 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <sound/core.h>
+#include <sound/tlv.h>
 
 #include "ice1712.h"
 #include "envy24ht.h"
 #include "juli.h"
-
 struct juli_spec {
 	struct ak4114 *ak4114;
 	unsigned int analog: 1;
@@ -44,6 +46,32 @@
 #define AK4358_ADDR		0x22		/* DAC */
 
 /*
+ * Juli does not use the standard ICE1724 clock scheme. Juli's ice1724 chip is
+ * supplied by external clock provided by Xilinx array and MK73-1 PLL frequency
+ * multiplier. Actual frequency is set by ice1724 GPIOs hooked to the Xilinx.
+ *
+ * The clock circuitry is supplied by the two ice1724 crystals. This
+ * arrangement allows to generate independent clock signal for AK4114's input
+ * rate detection circuit. As a result, Juli, unlike most other
+ * ice1724+ak4114-based cards, detects spdif input rate correctly.
+ * This fact is applied in the driver, allowing to modify PCM stream rate
+ * parameter according to the actual input rate.
+ *
+ * Juli uses the remaining three stereo-channels of its DAC to optionally
+ * monitor analog input, digital input, and digital output. The corresponding
+ * I2S signals are routed by Xilinx, controlled by GPIOs.
+ *
+ * The master mute is implemented using output muting transistors (GPIO) in
+ * combination with smuting the DAC.
+ *
+ * The card itself has no HW master volume control, implemented using the
+ * vmaster control.
+ *
+ * TODO:
+ * researching and fixing the input monitors
+ */
+
+/*
  * GPIO pins
  */
 #define GPIO_FREQ_MASK		(3<<0)
@@ -55,17 +83,82 @@
 #define GPIO_MULTI_2X		(1<<2)
 #define GPIO_MULTI_1X		(2<<2)		/* also external */
 #define GPIO_MULTI_HALF		(3<<2)
-#define GPIO_INTERNAL_CLOCK	(1<<4)
+#define GPIO_INTERNAL_CLOCK	(1<<4)		/* 0 = external, 1 = internal */
+#define GPIO_CLOCK_MASK		(1<<4)
 #define GPIO_ANALOG_PRESENT	(1<<5)		/* RO only: 0 = present */
 #define GPIO_RXMCLK_SEL		(1<<7)		/* must be 0 */
 #define GPIO_AK5385A_CKS0	(1<<8)
-#define GPIO_AK5385A_DFS0	(1<<9)		/* swapped with DFS1 according doc? */
-#define GPIO_AK5385A_DFS1	(1<<10)
+#define GPIO_AK5385A_DFS1	(1<<9)
+#define GPIO_AK5385A_DFS0	(1<<10)
 #define GPIO_DIGOUT_MONITOR	(1<<11)		/* 1 = active */
 #define GPIO_DIGIN_MONITOR	(1<<12)		/* 1 = active */
 #define GPIO_ANAIN_MONITOR	(1<<13)		/* 1 = active */
-#define GPIO_AK5385A_MCLK	(1<<14)		/* must be 0 */
-#define GPIO_MUTE_CONTROL	(1<<15)		/* 0 = off, 1 = on */
+#define GPIO_AK5385A_CKS1	(1<<14)		/* must be 0 */
+#define GPIO_MUTE_CONTROL	(1<<15)		/* output mute, 1 = muted */
+
+#define GPIO_RATE_MASK		(GPIO_FREQ_MASK | GPIO_MULTI_MASK | \
+		GPIO_CLOCK_MASK)
+#define GPIO_AK5385A_MASK	(GPIO_AK5385A_CKS0 | GPIO_AK5385A_DFS0 | \
+		GPIO_AK5385A_DFS1 | GPIO_AK5385A_CKS1)
+
+#define JULI_PCM_RATE	(SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
+		SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+		SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \
+		SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \
+		SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
+
+#define GPIO_RATE_16000		(GPIO_FREQ_32KHZ | GPIO_MULTI_HALF | \
+		GPIO_INTERNAL_CLOCK)
+#define GPIO_RATE_22050		(GPIO_FREQ_44KHZ | GPIO_MULTI_HALF | \
+		GPIO_INTERNAL_CLOCK)
+#define GPIO_RATE_24000		(GPIO_FREQ_48KHZ | GPIO_MULTI_HALF | \
+		GPIO_INTERNAL_CLOCK)
+#define GPIO_RATE_32000		(GPIO_FREQ_32KHZ | GPIO_MULTI_1X | \
+		GPIO_INTERNAL_CLOCK)
+#define GPIO_RATE_44100		(GPIO_FREQ_44KHZ | GPIO_MULTI_1X | \
+		GPIO_INTERNAL_CLOCK)
+#define GPIO_RATE_48000		(GPIO_FREQ_48KHZ | GPIO_MULTI_1X | \
+		GPIO_INTERNAL_CLOCK)
+#define GPIO_RATE_64000		(GPIO_FREQ_32KHZ | GPIO_MULTI_2X | \
+		GPIO_INTERNAL_CLOCK)
+#define GPIO_RATE_88200		(GPIO_FREQ_44KHZ | GPIO_MULTI_2X | \
+		GPIO_INTERNAL_CLOCK)
+#define GPIO_RATE_96000		(GPIO_FREQ_48KHZ | GPIO_MULTI_2X | \
+		GPIO_INTERNAL_CLOCK)
+#define GPIO_RATE_176400	(GPIO_FREQ_44KHZ | GPIO_MULTI_4X | \
+		GPIO_INTERNAL_CLOCK)
+#define GPIO_RATE_192000	(GPIO_FREQ_48KHZ | GPIO_MULTI_4X | \
+		GPIO_INTERNAL_CLOCK)
+
+/*
+ * Initial setup of the conversion array GPIO <-> rate
+ */
+static unsigned int juli_rates[] = {
+	16000, 22050, 24000, 32000,
+	44100, 48000, 64000, 88200,
+	96000, 176400, 192000,
+};
+
+static unsigned int gpio_vals[] = {
+	GPIO_RATE_16000, GPIO_RATE_22050, GPIO_RATE_24000, GPIO_RATE_32000,
+	GPIO_RATE_44100, GPIO_RATE_48000, GPIO_RATE_64000, GPIO_RATE_88200,
+	GPIO_RATE_96000, GPIO_RATE_176400, GPIO_RATE_192000,
+};
+
+static struct snd_pcm_hw_constraint_list juli_rates_info = {
+	.count = ARRAY_SIZE(juli_rates),
+	.list = juli_rates,
+	.mask = 0,
+};
+
+static int get_gpio_val(int rate)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(juli_rates); i++)
+		if (juli_rates[i] == rate)
+			return gpio_vals[i];
+	return 0;
+}
 
 static void juli_ak4114_write(void *private_data, unsigned char reg, unsigned char val)
 {
@@ -78,6 +171,27 @@
 }
 
 /*
+ * If SPDIF capture and slaved to SPDIF-IN, setting runtime rate
+ * to the external rate
+ */
+static void juli_spdif_in_open(struct snd_ice1712 *ice,
+			       struct snd_pcm_substream *substream)
+{
+	struct juli_spec *spec = ice->spec;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int rate;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+			!ice->is_spdif_master(ice))
+		return;
+	rate = snd_ak4114_external_rate(spec->ak4114);
+	if (rate >= runtime->hw.rate_min && rate <= runtime->hw.rate_max) {
+		runtime->hw.rate_min = rate;
+		runtime->hw.rate_max = rate;
+	}
+}
+
+/*
  * AK4358 section
  */
 
@@ -99,57 +213,285 @@
 }
 
 /*
- * change the rate of envy24HT, AK4358
+ * change the rate of envy24HT, AK4358, AK5385
  */
 static void juli_akm_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate)
 {
-	unsigned char old, tmp, dfs;
+	unsigned char old, tmp, ak4358_dfs;
+	unsigned int ak5385_pins, old_gpio, new_gpio;
+	struct snd_ice1712 *ice = ak->private_data[0];
+	struct juli_spec *spec = ice->spec;
 
-	if (rate == 0)  /* no hint - S/PDIF input is master, simply return */
+	if (rate == 0)  /* no hint - S/PDIF input is master or the new spdif
+			   input rate undetected, simply return */
 		return;
-	
+
 	/* adjust DFS on codecs */
-	if (rate > 96000) 
-		dfs = 2;
-	else if (rate > 48000)
-		dfs = 1;
-	else
-		dfs = 0;
-	
+	if (rate > 96000)  {
+		ak4358_dfs = 2;
+		ak5385_pins = GPIO_AK5385A_DFS1 | GPIO_AK5385A_CKS0;
+	} else if (rate > 48000) {
+		ak4358_dfs = 1;
+		ak5385_pins = GPIO_AK5385A_DFS0;
+	} else {
+		ak4358_dfs = 0;
+		ak5385_pins = 0;
+	}
+	/* AK5385 first, since it requires cold reset affecting both codecs */
+	old_gpio = ice->gpio.get_data(ice);
+	new_gpio =  (old_gpio & ~GPIO_AK5385A_MASK) | ak5385_pins;
+	/* printk(KERN_DEBUG "JULI - ak5385 set_rate_val: new gpio 0x%x\n",
+		new_gpio); */
+	ice->gpio.set_data(ice, new_gpio);
+
+	/* cold reset */
+	old = inb(ICEMT1724(ice, AC97_CMD));
+	outb(old | VT1724_AC97_COLD, ICEMT1724(ice, AC97_CMD));
+	udelay(1);
+	outb(old & ~VT1724_AC97_COLD, ICEMT1724(ice, AC97_CMD));
+
+	/* AK4358 */
+	/* set new value, reset DFS */
 	tmp = snd_akm4xxx_get(ak, 0, 2);
-	old = (tmp >> 4) & 0x03;
-	if (old == dfs)
-		return;
-	/* reset DFS */
 	snd_akm4xxx_reset(ak, 1);
 	tmp = snd_akm4xxx_get(ak, 0, 2);
 	tmp &= ~(0x03 << 4);
-	tmp |= dfs << 4;
+	tmp |= ak4358_dfs << 4;
 	snd_akm4xxx_set(ak, 0, 2, tmp);
 	snd_akm4xxx_reset(ak, 0);
+
+	/* reinit ak4114 */
+	snd_ak4114_reinit(spec->ak4114);
 }
 
+#define AK_DAC(xname, xch)	{ .name = xname, .num_channels = xch }
+#define PCM_VOLUME		"PCM Playback Volume"
+#define MONITOR_AN_IN_VOLUME	"Monitor Analog In Volume"
+#define MONITOR_DIG_IN_VOLUME	"Monitor Digital In Volume"
+#define MONITOR_DIG_OUT_VOLUME	"Monitor Digital Out Volume"
+
+static const struct snd_akm4xxx_dac_channel juli_dac[] = {
+	AK_DAC(PCM_VOLUME, 2),
+	AK_DAC(MONITOR_AN_IN_VOLUME, 2),
+	AK_DAC(MONITOR_DIG_OUT_VOLUME, 2),
+	AK_DAC(MONITOR_DIG_IN_VOLUME, 2),
+};
+
+
 static struct snd_akm4xxx akm_juli_dac __devinitdata = {
 	.type = SND_AK4358,
-	.num_dacs = 2,
+	.num_dacs = 8,	/* DAC1 - analog out
+			   DAC2 - analog in monitor
+			   DAC3 - digital out monitor
+			   DAC4 - digital in monitor
+			 */
 	.ops = {
 		.lock = juli_akm_lock,
 		.unlock = juli_akm_unlock,
 		.write = juli_akm_write,
 		.set_rate_val = juli_akm_set_rate_val
-	}
+	},
+	.dac_info = juli_dac,
 };
 
+#define juli_mute_info		snd_ctl_boolean_mono_info
+
+static int juli_mute_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+	unsigned int val;
+	val = ice->gpio.get_data(ice) & (unsigned int) kcontrol->private_value;
+	if (kcontrol->private_value == GPIO_MUTE_CONTROL)
+		/* val 0 = signal on */
+		ucontrol->value.integer.value[0] = (val) ? 0 : 1;
+	else
+		/* val 1 = signal on */
+		ucontrol->value.integer.value[0] = (val) ? 1 : 0;
+	return 0;
+}
+
+static int juli_mute_put(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+	unsigned int old_gpio, new_gpio;
+	old_gpio = ice->gpio.get_data(ice);
+	if (ucontrol->value.integer.value[0]) {
+		/* unmute */
+		if (kcontrol->private_value == GPIO_MUTE_CONTROL) {
+			/* 0 = signal on */
+			new_gpio = old_gpio & ~GPIO_MUTE_CONTROL;
+			/* un-smuting DAC */
+			snd_akm4xxx_write(ice->akm, 0, 0x01, 0x01);
+		} else
+			/* 1 = signal on */
+			new_gpio =  old_gpio |
+				(unsigned int) kcontrol->private_value;
+	} else {
+		/* mute */
+		if (kcontrol->private_value == GPIO_MUTE_CONTROL) {
+			/* 1 = signal off */
+			new_gpio = old_gpio | GPIO_MUTE_CONTROL;
+			/* smuting DAC */
+			snd_akm4xxx_write(ice->akm, 0, 0x01, 0x03);
+		} else
+			/* 0 = signal off */
+			new_gpio =  old_gpio &
+				~((unsigned int) kcontrol->private_value);
+	}
+	/* printk("JULI - mute/unmute: control_value: 0x%x, old_gpio: 0x%x, \
+		new_gpio 0x%x\n",
+		(unsigned int)ucontrol->value.integer.value[0], old_gpio,
+		new_gpio); */
+	if (old_gpio != new_gpio) {
+		ice->gpio.set_data(ice, new_gpio);
+		return 1;
+	}
+	/* no change */
+	return 0;
+}
+
+static struct snd_kcontrol_new juli_mute_controls[] __devinitdata = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Switch",
+		.info = juli_mute_info,
+		.get = juli_mute_get,
+		.put = juli_mute_put,
+		.private_value = GPIO_MUTE_CONTROL,
+	},
+	/* Although the following functionality respects the succint NDA'd
+	 * documentation from the card manufacturer, and the same way of
+	 * operation is coded in OSS Juli driver, only Digital Out monitor
+	 * seems to work. Surprisingly, Analog input monitor outputs Digital
+	 * output data. The two are independent, as enabling both doubles
+	 * volume of the monitor sound.
+	 *
+	 * Checking traces on the board suggests the functionality described
+	 * by the manufacturer is correct - I2S from ADC and AK4114
+	 * go to ICE as well as to Xilinx, I2S inputs of DAC2,3,4 (the monitor
+	 * inputs) are fed from Xilinx.
+	 *
+	 * I even checked traces on board and coded a support in driver for
+	 * an alternative possiblity - the unused I2S ICE output channels
+	 * switched to HW-IN/SPDIF-IN and providing the monitoring signal to
+	 * the DAC - to no avail. The I2S outputs seem to be unconnected.
+	 *
+	 * The windows driver supports the monitoring correctly.
+	 */
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Monitor Analog In Switch",
+		.info = juli_mute_info,
+		.get = juli_mute_get,
+		.put = juli_mute_put,
+		.private_value = GPIO_ANAIN_MONITOR,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Monitor Digital Out Switch",
+		.info = juli_mute_info,
+		.get = juli_mute_get,
+		.put = juli_mute_put,
+		.private_value = GPIO_DIGOUT_MONITOR,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Monitor Digital In Switch",
+		.info = juli_mute_info,
+		.get = juli_mute_get,
+		.put = juli_mute_put,
+		.private_value = GPIO_DIGIN_MONITOR,
+	},
+};
+
+
+static void ak4358_proc_regs_read(struct snd_info_entry *entry,
+		struct snd_info_buffer *buffer)
+{
+	struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
+	int reg, val;
+	for (reg = 0; reg <= 0xf; reg++) {
+		val =  snd_akm4xxx_get(ice->akm, 0, reg);
+		snd_iprintf(buffer, "0x%02x = 0x%02x\n", reg, val);
+	}
+}
+
+static void ak4358_proc_init(struct snd_ice1712 *ice)
+{
+	struct snd_info_entry *entry;
+	if (!snd_card_proc_new(ice->card, "ak4358_codec", &entry))
+		snd_info_set_text_ops(entry, ice, ak4358_proc_regs_read);
+}
+
+static char *slave_vols[] __devinitdata = {
+	PCM_VOLUME,
+	MONITOR_AN_IN_VOLUME,
+	MONITOR_DIG_IN_VOLUME,
+	MONITOR_DIG_OUT_VOLUME,
+	NULL
+};
+
+static __devinitdata
+DECLARE_TLV_DB_SCALE(juli_master_db_scale, -6350, 50, 1);
+
+static struct snd_kcontrol __devinit *ctl_find(struct snd_card *card,
+		const char *name)
+{
+	struct snd_ctl_elem_id sid;
+	memset(&sid, 0, sizeof(sid));
+	/* FIXME: strcpy is bad. */
+	strcpy(sid.name, name);
+	sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	return snd_ctl_find_id(card, &sid);
+}
+
+static void __devinit add_slaves(struct snd_card *card,
+				 struct snd_kcontrol *master, char **list)
+{
+	for (; *list; list++) {
+		struct snd_kcontrol *slave = ctl_find(card, *list);
+		/* printk(KERN_DEBUG "add_slaves - %s\n", *list); */
+		if (slave) {
+			/* printk(KERN_DEBUG "slave %s found\n", *list); */
+			snd_ctl_add_slave(master, slave);
+		}
+	}
+}
+
 static int __devinit juli_add_controls(struct snd_ice1712 *ice)
 {
 	struct juli_spec *spec = ice->spec;
 	int err;
+	unsigned int i;
+	struct snd_kcontrol *vmaster;
+
 	err = snd_ice1712_akm4xxx_build_controls(ice);
 	if (err < 0)
 		return err;
+
+	for (i = 0; i < ARRAY_SIZE(juli_mute_controls); i++) {
+		err = snd_ctl_add(ice->card,
+				snd_ctl_new1(&juli_mute_controls[i], ice));
+		if (err < 0)
+			return err;
+	}
+	/* Create virtual master control */
+	vmaster = snd_ctl_make_virtual_master("Master Playback Volume",
+					      juli_master_db_scale);
+	if (!vmaster)
+		return -ENOMEM;
+	add_slaves(ice->card, vmaster, slave_vols);
+	err = snd_ctl_add(ice->card, vmaster);
+	if (err < 0)
+		return err;
+
 	/* only capture SPDIF over AK4114 */
 	err = snd_ak4114_build(spec->ak4114, NULL,
-			       ice->pcm_pro->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
+			ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
+
+	ak4358_proc_init(ice);
 	if (err < 0)
 		return err;
 	return 0;
@@ -158,6 +500,74 @@
 /*
  * initialize the chip
  */
+
+static inline int juli_is_spdif_master(struct snd_ice1712 *ice)
+{
+	return (ice->gpio.get_data(ice) & GPIO_INTERNAL_CLOCK) ? 0 : 1;
+}
+
+static unsigned int juli_get_rate(struct snd_ice1712 *ice)
+{
+	int i;
+	unsigned char result;
+
+	result =  ice->gpio.get_data(ice) & GPIO_RATE_MASK;
+	for (i = 0; i < ARRAY_SIZE(gpio_vals); i++)
+		if (gpio_vals[i] == result)
+			return juli_rates[i];
+	return 0;
+}
+
+/* setting new rate */
+static void juli_set_rate(struct snd_ice1712 *ice, unsigned int rate)
+{
+	unsigned int old, new;
+	unsigned char val;
+
+	old = ice->gpio.get_data(ice);
+	new =  (old & ~GPIO_RATE_MASK) | get_gpio_val(rate);
+	/* printk(KERN_DEBUG "JULI - set_rate: old %x, new %x\n",
+			old & GPIO_RATE_MASK,
+			new & GPIO_RATE_MASK); */
+
+	ice->gpio.set_data(ice, new);
+	/* switching to external clock - supplied by external circuits */
+	val = inb(ICEMT1724(ice, RATE));
+	outb(val | VT1724_SPDIF_MASTER, ICEMT1724(ice, RATE));
+}
+
+static inline unsigned char juli_set_mclk(struct snd_ice1712 *ice,
+					  unsigned int rate)
+{
+	/* no change in master clock */
+	return 0;
+}
+
+/* setting clock to external - SPDIF */
+static void juli_set_spdif_clock(struct snd_ice1712 *ice)
+{
+	unsigned int old;
+	old = ice->gpio.get_data(ice);
+	/* external clock (= 0), multiply 1x, 48kHz */
+	ice->gpio.set_data(ice, (old & ~GPIO_RATE_MASK) | GPIO_MULTI_1X |
+			GPIO_FREQ_48KHZ);
+}
+
+/* Called when ak4114 detects change in the input SPDIF stream */
+static void juli_ak4114_change(struct ak4114 *ak4114, unsigned char c0,
+			       unsigned char c1)
+{
+	struct snd_ice1712 *ice = ak4114->change_callback_private;
+	int rate;
+	if (ice->is_spdif_master(ice) && c1) {
+		/* only for SPDIF master mode, rate was changed */
+		rate = snd_ak4114_external_rate(ak4114);
+		/* printk(KERN_DEBUG "ak4114 - input rate changed to %d\n",
+				rate); */
+		juli_akm_set_rate_val(ice->akm, rate);
+	}
+}
+
 static int __devinit juli_init(struct snd_ice1712 *ice)
 {
 	static const unsigned char ak4114_init_vals[] = {
@@ -187,6 +597,11 @@
 				ice, &spec->ak4114);
 	if (err < 0)
 		return err;
+	/* callback for codecs rate setting */
+	spec->ak4114->change_callback = juli_ak4114_change;
+	spec->ak4114->change_callback_private = ice;
+	/* AK4114 in Juli can detect external rate correctly */
+	spec->ak4114->check_flags = 0;
 
 #if 0
         /* it seems that the analog doughter board detection does not work
@@ -210,6 +625,15 @@
 			return err;
 	}
 	
+	/* juli is clocked by Xilinx array */
+	ice->hw_rates = &juli_rates_info;
+	ice->is_spdif_master = juli_is_spdif_master;
+	ice->get_rate = juli_get_rate;
+	ice->set_rate = juli_set_rate;
+	ice->set_mclk = juli_set_mclk;
+	ice->set_spdif_clock = juli_set_spdif_clock;
+
+	ice->spdif.ops.open = juli_spdif_in_open;
 	return 0;
 }
 
@@ -220,18 +644,20 @@
  */
 
 static unsigned char juli_eeprom[] __devinitdata = {
-	[ICE_EEP2_SYSCONF]     = 0x20,	/* clock 512, mpu401, 1xADC, 1xDACs */
+	[ICE_EEP2_SYSCONF]     = 0x2b,	/* clock 512, mpu401, 1xADC, 1xDACs,
+					   SPDIF in */
 	[ICE_EEP2_ACLINK]      = 0x80,	/* I2S */
 	[ICE_EEP2_I2S]         = 0xf8,	/* vol, 96k, 24bit, 192k */
 	[ICE_EEP2_SPDIF]       = 0xc3,	/* out-en, out-int, spdif-in */
-	[ICE_EEP2_GPIO_DIR]    = 0x9f,
+	[ICE_EEP2_GPIO_DIR]    = 0x9f,	/* 5, 6:inputs; 7, 4-0 outputs*/
 	[ICE_EEP2_GPIO_DIR1]   = 0xff,
 	[ICE_EEP2_GPIO_DIR2]   = 0x7f,
-	[ICE_EEP2_GPIO_MASK]   = 0x9f,
-	[ICE_EEP2_GPIO_MASK1]  = 0xff,
+	[ICE_EEP2_GPIO_MASK]   = 0x60,	/* 5, 6: locked; 7, 4-0 writable */
+	[ICE_EEP2_GPIO_MASK1]  = 0x00,  /* 0-7 writable */
 	[ICE_EEP2_GPIO_MASK2]  = 0x7f,
-	[ICE_EEP2_GPIO_STATE]  = 0x16,	/* internal clock, multiple 1x, 48kHz */
-	[ICE_EEP2_GPIO_STATE1] = 0x80,	/* mute */
+	[ICE_EEP2_GPIO_STATE]  = GPIO_FREQ_48KHZ | GPIO_MULTI_1X |
+	       GPIO_INTERNAL_CLOCK,	/* internal clock, multiple 1x, 48kHz*/
+	[ICE_EEP2_GPIO_STATE1] = 0x00,	/* unmuted */
 	[ICE_EEP2_GPIO_STATE2] = 0x00,
 };
 
diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c
index 4945c81..203cdc1bf 100644
--- a/sound/pci/ice1712/pontis.c
+++ b/sound/pci/ice1712/pontis.c
@@ -246,7 +246,7 @@
 		wm_put(ice, WM_ADC_MUX, nval);
 	}
 	mutex_unlock(&ice->gpio_mutex);
-	return 0;
+	return change;
 }
 
 /*
@@ -450,7 +450,7 @@
 		change = 1;
 	}
 	mutex_unlock(&ice->gpio_mutex);
-	return 0;
+	return change;
 }
 
 
diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c
index 48cf40a..48d3679 100644
--- a/sound/pci/ice1712/prodigy192.c
+++ b/sound/pci/ice1712/prodigy192.c
@@ -319,12 +319,11 @@
 /*
  * Handler for setting correct codec rate - called when rate change is detected
  */
-static void stac9460_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate)
+static void stac9460_set_rate_val(struct snd_ice1712 *ice, unsigned int rate)
 {
 	unsigned char old, new;
 	int idx;
 	unsigned char changed[7];
-	struct snd_ice1712 *ice = ak->private_data[0];
 	struct prodigy192_spec *spec = ice->spec;
 
 	if (rate == 0)  /* no hint - S/PDIF input is master, simply return */
@@ -357,16 +356,6 @@
 	mutex_unlock(&spec->mute_mutex);
 }
 
-/* using akm infrastructure for setting rate of the codec */
-static struct snd_akm4xxx akmlike_stac9460 __devinitdata = {
-	.type = NON_AKM,	/* special value */
-	.num_adcs = 6,		/* not used in any way, just for completeness */
-	.num_dacs = 2,
-	.ops = {
-		.set_rate_val = stac9460_set_rate_val
-	}
-};
-
 
 static const DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0);
 static const DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0);
@@ -642,12 +631,19 @@
 		0x41, 0x02, 0x2c, 0x00, 0x00
 	};
 	struct prodigy192_spec *spec = ice->spec;
+	int err;
 
-	return snd_ak4114_create(ice->card,
+	err = snd_ak4114_create(ice->card,
 				 prodigy192_ak4114_read,
 				 prodigy192_ak4114_write,
 				 ak4114_init_vals, ak4114_init_txcsb,
 				 ice, &spec->ak4114);
+	if (err < 0)
+		return err;
+	/* AK4114 in Prodigy192 cannot detect external rate correctly.
+	 * No reason to stop capture stream due to incorrect checks */
+	spec->ak4114->check_flags = AK4114_CHECK_NO_RATE;
+	return 0;
 }
 
 static void stac9460_proc_regs_read(struct snd_info_entry *entry,
@@ -743,7 +739,6 @@
 	};
 	const unsigned short *p;
 	int err = 0;
-	struct snd_akm4xxx *ak;
 	struct prodigy192_spec *spec;
 
 	/* prodigy 192 */
@@ -761,15 +756,7 @@
 	p = stac_inits_prodigy;
 	for (; *p != (unsigned short)-1; p += 2)
 		stac9460_put(ice, p[0], p[1]);
-	/* reusing the akm codecs infrastructure,
-	 * for setting rate on stac9460 */
-	ak = ice->akm = kmalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
-	if (!ak)
-		return -ENOMEM;
-	ice->akm_codecs = 1;
-	err = snd_ice1712_akm4xxx_init(ak, &akmlike_stac9460, NULL, ice);
-	if (err < 0)
-		return err;
+	ice->gpio.set_pro_rate = stac9460_set_rate_val;
 
 	/* MI/ODI/O add on card with AK4114 */
 	if (prodigy192_miodio_exists(ice)) {
@@ -825,10 +812,6 @@
 		.build_controls = prodigy192_add_controls,
 		.eeprom_size = sizeof(prodigy71_eeprom),
 		.eeprom_data = prodigy71_eeprom,
-		/* the current MPU401 code loops infinitely
-		 * when opening midi device
-		 */
-		.no_mpu401 = 1,
 	},
 	{ } /* terminator */
 };
diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c
index 301bf92..4d26314 100644
--- a/sound/pci/ice1712/revo.c
+++ b/sound/pci/ice1712/revo.c
@@ -322,17 +322,23 @@
 static void ap192_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate)
 {
 	struct snd_ice1712 *ice = ak->private_data[0];
+	int dfs;
 
 	revo_set_rate_val(ak, rate);
 
-#if 1 /* FIXME: do we need this procedure? */
-	/* reset DFS pin of AK5385A for ADC, too */
-	/* DFS0 (pin 18) -- GPIO10 pin 77 */
-	snd_ice1712_save_gpio_status(ice);
-	snd_ice1712_gpio_write_bits(ice, 1 << 10,
-				    rate > 48000 ? (1 << 10) : 0);
-	snd_ice1712_restore_gpio_status(ice);
-#endif
+	/* reset CKS */
+	snd_ice1712_gpio_write_bits(ice, 1 << 8, rate > 96000 ? 1 << 8 : 0);
+	/* reset DFS pins of AK5385A for ADC, too */
+	if (rate > 96000)
+		dfs = 2;
+	else if (rate > 48000)
+		dfs = 1;
+	else
+		dfs = 0;
+	snd_ice1712_gpio_write_bits(ice, 3 << 9, dfs << 9);
+	/* reset ADC */
+	snd_ice1712_gpio_write_bits(ice, 1 << 11, 0);
+	snd_ice1712_gpio_write_bits(ice, 1 << 11, 1 << 11);
 }
 
 static const struct snd_akm4xxx_dac_channel ap192_dac[] = {
@@ -353,28 +359,20 @@
 	.cif = 0,
 	.data_mask = VT1724_REVO_CDOUT,
 	.clk_mask = VT1724_REVO_CCLK,
-	.cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS3,
-	.cs_addr = VT1724_REVO_CS3,
-	.cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS3,
+	.cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1,
+	.cs_addr = VT1724_REVO_CS1,
+	.cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1,
 	.add_flags = VT1724_REVO_CCLK, /* high at init */
 	.mask_flags = 0,
 };
 
-#if 0
-/* FIXME: ak4114 makes the sound much lower due to some confliction,
- *        so let's disable it right now...
- */
-#define BUILD_AK4114_AP192
-#endif
-
-#ifdef BUILD_AK4114_AP192
 /* AK4114 support on Audiophile 192 */
 /* CDTO (pin 32) -- GPIO2 pin 52
  * CDTI (pin 33) -- GPIO3 pin 53 (shared with AK4358)
  * CCLK (pin 34) -- GPIO1 pin 51 (shared with AK4358)
  * CSN  (pin 35) -- GPIO7 pin 59
  */
-#define AK4114_ADDR	0x00
+#define AK4114_ADDR	0x02
 
 static void write_data(struct snd_ice1712 *ice, unsigned int gpio,
 		       unsigned int data, int idx)
@@ -428,7 +426,7 @@
 	tmp = snd_ice1712_gpio_read(ice);
 	tmp |= VT1724_REVO_CCLK; /* high at init */
 	tmp |= VT1724_REVO_CS0;
-	tmp &= ~VT1724_REVO_CS3;
+	tmp &= ~VT1724_REVO_CS1;
 	snd_ice1712_gpio_write(ice, tmp);
 	udelay(1);
 	return tmp;
@@ -436,7 +434,7 @@
 
 static void ap192_4wire_finish(struct snd_ice1712 *ice, unsigned int tmp)
 {
-	tmp |= VT1724_REVO_CS3;
+	tmp |= VT1724_REVO_CS1;
 	tmp |= VT1724_REVO_CS0;
 	snd_ice1712_gpio_write(ice, tmp);
 	udelay(1);
@@ -485,13 +483,17 @@
 	struct ak4114 *ak;
 	int err;
 
-	return snd_ak4114_create(ice->card,
+	err = snd_ak4114_create(ice->card,
 				 ap192_ak4114_read,
 				 ap192_ak4114_write,
 				 ak4114_init_vals, ak4114_init_txcsb,
 				 ice, &ak);
+	/* AK4114 in Revo cannot detect external rate correctly.
+	 * No reason to stop capture stream due to incorrect checks */
+	ak->check_flags = AK4114_CHECK_NO_RATE;
+
+	return 0; /* error ignored; it's no fatal error */
 }
-#endif /* BUILD_AK4114_AP192 */
 
 static int __devinit revo_init(struct snd_ice1712 *ice)
 {
@@ -557,6 +559,9 @@
 		if (err < 0)
 			return err;
 		
+		/* unmute all codecs */
+		snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE,
+					    VT1724_REVO_MUTE);
 		break;
 	}
 
@@ -588,11 +593,9 @@
 		err = snd_ice1712_akm4xxx_build_controls(ice);
 		if (err < 0)
 			return err;
-#ifdef BUILD_AK4114_AP192
 		err = ap192_ak4114_init(ice);
 		if (err < 0)
 			return err;
-#endif
 		break;
 	}
 	return 0;
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index c52abd0..048d99e 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -155,7 +155,8 @@
 #define   ICH_PCM_SPDIF_69	0x80000000	/* s/pdif pcm on slots 6&9 */
 #define   ICH_PCM_SPDIF_1011	0xc0000000	/* s/pdif pcm on slots 10&11 */
 #define   ICH_PCM_20BIT		0x00400000	/* 20-bit samples (ICH4) */
-#define   ICH_PCM_246_MASK	0x00300000	/* 6 channels (not all chips) */
+#define   ICH_PCM_246_MASK	0x00300000	/* chan mask (not all chips) */
+#define   ICH_PCM_8		0x00300000      /* 8 channels (not all chips) */
 #define   ICH_PCM_6		0x00200000	/* 6 channels (not all chips) */
 #define   ICH_PCM_4		0x00100000	/* 4 channels (not all chips) */
 #define   ICH_PCM_2		0x00000000	/* 2 channels (stereo) */
@@ -382,6 +383,7 @@
 
 	unsigned multi4: 1,
 		 multi6: 1,
+		 multi8 :1,
 		 dra: 1,
 		 smp20bit: 1;
 	unsigned in_ac97_init: 1,
@@ -997,6 +999,8 @@
 			cnt |= ICH_PCM_4;
 		else if (runtime->channels == 6)
 			cnt |= ICH_PCM_6;
+		else if (runtime->channels == 8)
+			cnt |= ICH_PCM_8;
 		if (chip->device_type == DEVICE_NFORCE) {
 			/* reset to 2ch once to keep the 6 channel data in alignment,
 			 * to start from Front Left always
@@ -1106,6 +1110,16 @@
 	.mask = 0,
 };
 
+static unsigned int channels8[] = {
+	2, 4, 6, 8,
+};
+
+static struct snd_pcm_hw_constraint_list hw_constraints_channels8 = {
+	.count = ARRAY_SIZE(channels8),
+	.list = channels8,
+	.mask = 0,
+};
+
 static int snd_intel8x0_pcm_open(struct snd_pcm_substream *substream, struct ichdev *ichdev)
 {
 	struct intel8x0 *chip = snd_pcm_substream_chip(substream);
@@ -1136,7 +1150,12 @@
 	if (err < 0)
 		return err;
 
-	if (chip->multi6) {
+	if (chip->multi8) {
+		runtime->hw.channels_max = 8;
+		snd_pcm_hw_constraint_list(runtime, 0,
+						SNDRV_PCM_HW_PARAM_CHANNELS,
+						&hw_constraints_channels8);
+	} else if (chip->multi6) {
 		runtime->hw.channels_max = 6;
 		snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
 					   &hw_constraints_channels6);
@@ -2203,8 +2222,11 @@
 	}
 	if (pbus->pcms[0].r[0].slots & (1 << AC97_SLOT_PCM_SLEFT)) {
 		chip->multi4 = 1;
-		if (pbus->pcms[0].r[0].slots & (1 << AC97_SLOT_LFE))
+		if (pbus->pcms[0].r[0].slots & (1 << AC97_SLOT_LFE)) {
 			chip->multi6 = 1;
+			if (chip->ac97[0]->flags & AC97_HAS_8CH)
+				chip->multi8 = 1;
+		}
 	}
 	if (pbus->pcms[0].r[1].rslots[0]) {
 		chip->dra = 1;
@@ -2446,7 +2468,7 @@
 		pci_write_config_dword(chip->pci, 0x4c, val);
 	}
 	/* --- */
-	synchronize_irq(chip->irq);
+
       __hw_end:
 	if (chip->irq >= 0)
 		free_irq(chip->irq, chip);
@@ -2495,7 +2517,6 @@
 		chip->sdm_saved = igetbyte(chip, ICHREG(SDM));
 
 	if (chip->irq >= 0) {
-		synchronize_irq(chip->irq);
 		free_irq(chip->irq, chip);
 		chip->irq = -1;
 	}
@@ -2648,7 +2669,7 @@
 	t = stop_time.tv_sec - start_time.tv_sec;
 	t *= 1000000;
 	t += stop_time.tv_usec - start_time.tv_usec;
-	printk(KERN_INFO "%s: measured %lu usecs\n", __FUNCTION__, t);
+	printk(KERN_INFO "%s: measured %lu usecs\n", __func__, t);
 	if (t == 0) {
 		snd_printk(KERN_ERR "?? calculation error..\n");
 		return;
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c
index cadda8d..faf674e 100644
--- a/sound/pci/intel8x0m.c
+++ b/sound/pci/intel8x0m.c
@@ -985,17 +985,15 @@
 	/* reset channels */
 	for (i = 0; i < chip->bdbars_count; i++)
 		iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, ICH_RESETREGS);
-	/* --- */
-	synchronize_irq(chip->irq);
-      __hw_end:
+ __hw_end:
+	if (chip->irq >= 0)
+		free_irq(chip->irq, chip);
 	if (chip->bdbars.area)
 		snd_dma_free_pages(&chip->bdbars);
 	if (chip->addr)
 		pci_iounmap(chip->pci, chip->addr);
 	if (chip->bmaddr)
 		pci_iounmap(chip->pci, chip->bmaddr);
-	if (chip->irq >= 0)
-		free_irq(chip->irq, chip);
 	pci_release_regions(chip->pci);
 	pci_disable_device(chip->pci);
 	kfree(chip);
@@ -1017,7 +1015,6 @@
 		snd_pcm_suspend_all(chip->pcm[i]);
 	snd_ac97_suspend(chip->ac97);
 	if (chip->irq >= 0) {
-		synchronize_irq(chip->irq);
 		free_irq(chip->irq, chip);
 		chip->irq = -1;
 	}
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
index 10c713d..f4c85b5 100644
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -2102,7 +2102,6 @@
         snd_korg1212_TurnOffIdleMonitor(korg1212);
 
         if (korg1212->irq >= 0) {
-                synchronize_irq(korg1212->irq);                
                 snd_korg1212_DisableCardInterrupts(korg1212);
                 free_irq(korg1212->irq, korg1212);
                 korg1212->irq = -1;
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index 04fa0a6..a536c59 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -2068,7 +2068,7 @@
 {
 	struct snd_ac97_bus *pbus;
 	struct snd_ac97_template ac97;
-	struct snd_ctl_elem_id id;
+	struct snd_ctl_elem_id elem_id;
 	int err;
 	static struct snd_ac97_bus_ops ops = {
 		.write = snd_m3_ac97_write,
@@ -2088,14 +2088,14 @@
 	schedule_timeout_uninterruptible(msecs_to_jiffies(100));
 	snd_ac97_write(chip->ac97, AC97_PCM, 0);
 
-	memset(&id, 0, sizeof(id));
-	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-	strcpy(id.name, "Master Playback Switch");
-	chip->master_switch = snd_ctl_find_id(chip->card, &id);
-	memset(&id, 0, sizeof(id));
-	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-	strcpy(id.name, "Master Playback Volume");
-	chip->master_volume = snd_ctl_find_id(chip->card, &id);
+	memset(&elem_id, 0, sizeof(elem_id));
+	elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	strcpy(elem_id.name, "Master Playback Switch");
+	chip->master_switch = snd_ctl_find_id(chip->card, &elem_id);
+	memset(&elem_id, 0, sizeof(elem_id));
+	elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	strcpy(elem_id.name, "Master Playback Volume");
+	chip->master_volume = snd_ctl_find_id(chip->card, &elem_id);
 
 	return 0;
 }
@@ -2542,10 +2542,8 @@
 	vfree(chip->suspend_mem);
 #endif
 
-	if (chip->irq >= 0) {
-		synchronize_irq(chip->irq);
+	if (chip->irq >= 0)
 		free_irq(chip->irq, chip);
-	}
 
 	if (chip->iobase)
 		pci_release_regions(chip->pci);
@@ -2569,7 +2567,7 @@
 {
 	struct snd_card *card = pci_get_drvdata(pci);
 	struct snd_m3 *chip = card->private_data;
-	int i, index;
+	int i, dsp_index;
 
 	if (chip->suspend_mem == NULL)
 		return 0;
@@ -2583,12 +2581,12 @@
 	snd_m3_assp_halt(chip);
 
 	/* save dsp image */
-	index = 0;
+	dsp_index = 0;
 	for (i = REV_B_CODE_MEMORY_BEGIN; i <= REV_B_CODE_MEMORY_END; i++)
-		chip->suspend_mem[index++] = 
+		chip->suspend_mem[dsp_index++] =
 			snd_m3_assp_read(chip, MEMTYPE_INTERNAL_CODE, i);
 	for (i = REV_B_DATA_MEMORY_BEGIN ; i <= REV_B_DATA_MEMORY_END; i++)
-		chip->suspend_mem[index++] = 
+		chip->suspend_mem[dsp_index++] =
 			snd_m3_assp_read(chip, MEMTYPE_INTERNAL_DATA, i);
 
 	pci_disable_device(pci);
@@ -2601,7 +2599,7 @@
 {
 	struct snd_card *card = pci_get_drvdata(pci);
 	struct snd_m3 *chip = card->private_data;
-	int i, index;
+	int i, dsp_index;
 
 	if (chip->suspend_mem == NULL)
 		return 0;
@@ -2625,13 +2623,13 @@
 	snd_m3_ac97_reset(chip);
 
 	/* restore dsp image */
-	index = 0;
+	dsp_index = 0;
 	for (i = REV_B_CODE_MEMORY_BEGIN; i <= REV_B_CODE_MEMORY_END; i++)
 		snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE, i, 
-				  chip->suspend_mem[index++]);
+				  chip->suspend_mem[dsp_index++]);
 	for (i = REV_B_DATA_MEMORY_BEGIN ; i <= REV_B_DATA_MEMORY_END; i++)
 		snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, i, 
-				  chip->suspend_mem[index++]);
+				  chip->suspend_mem[dsp_index++]);
 
 	/* tell the dma engine to restart itself */
 	snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
index 7ac654e..7efb838 100644
--- a/sound/pci/nm256/nm256.c
+++ b/sound/pci/nm256/nm256.c
@@ -1439,7 +1439,7 @@
 		snd_nm256_capture_stop(chip);
 
 	if (chip->irq >= 0)
-		synchronize_irq(chip->irq);
+		free_irq(chip->irq, chip);
 
 	if (chip->cport)
 		iounmap(chip->cport);
@@ -1447,8 +1447,6 @@
 		iounmap(chip->buffer);
 	release_and_free_resource(chip->res_cport);
 	release_and_free_resource(chip->res_buffer);
-	if (chip->irq >= 0)
-		free_irq(chip->irq, chip);
 
 	pci_disable_device(chip->pci);
 	kfree(chip->ac97_regs);
diff --git a/sound/pci/oxygen/cs4362a.h b/sound/pci/oxygen/cs4362a.h
new file mode 100644
index 0000000..6a4fedf
--- /dev/null
+++ b/sound/pci/oxygen/cs4362a.h
@@ -0,0 +1,69 @@
+/* register 01h */
+#define CS4362A_PDN		0x01
+#define CS4362A_DAC1_DIS	0x02
+#define CS4362A_DAC2_DIS	0x04
+#define CS4362A_DAC3_DIS	0x08
+#define CS4362A_MCLKDIV		0x20
+#define CS4362A_FREEZE		0x40
+#define CS4362A_CPEN		0x80
+/* register 02h */
+#define CS4362A_DIF_MASK	0x70
+#define CS4362A_DIF_LJUST	0x00
+#define CS4362A_DIF_I2S		0x10
+#define CS4362A_DIF_RJUST_16	0x20
+#define CS4362A_DIF_RJUST_24	0x30
+#define CS4362A_DIF_RJUST_20	0x40
+#define CS4362A_DIF_RJUST_18	0x50
+/* register 03h */
+#define CS4362A_MUTEC_MASK	0x03
+#define CS4362A_MUTEC_6		0x00
+#define CS4362A_MUTEC_1		0x01
+#define CS4362A_MUTEC_3		0x03
+#define CS4362A_AMUTE		0x04
+#define CS4362A_MUTEC_POL	0x08
+#define CS4362A_RMP_UP		0x10
+#define CS4362A_SNGLVOL		0x20
+#define CS4362A_ZERO_CROSS	0x40
+#define CS4362A_SOFT_RAMP	0x80
+/* register 04h */
+#define CS4362A_RMP_DN		0x01
+#define CS4362A_DEM_MASK	0x06
+#define CS4362A_DEM_NONE	0x00
+#define CS4362A_DEM_44100	0x02
+#define CS4362A_DEM_48000	0x04
+#define CS4362A_DEM_32000	0x06
+#define CS4362A_FILT_SEL	0x10
+/* register 05h */
+#define CS4362A_INV_A1		0x01
+#define CS4362A_INV_B1		0x02
+#define CS4362A_INV_A2		0x04
+#define CS4362A_INV_B2		0x08
+#define CS4362A_INV_A3		0x10
+#define CS4362A_INV_B3		0x20
+/* register 06h */
+#define CS4362A_FM_MASK		0x03
+#define CS4362A_FM_SINGLE	0x00
+#define CS4362A_FM_DOUBLE	0x01
+#define CS4362A_FM_QUAD		0x02
+#define CS4362A_FM_DSD		0x03
+#define CS4362A_ATAPI_MASK	0x7c
+#define CS4362A_ATAPI_B_MUTE	0x00
+#define CS4362A_ATAPI_B_R	0x04
+#define CS4362A_ATAPI_B_L	0x08
+#define CS4362A_ATAPI_B_LR	0x0c
+#define CS4362A_ATAPI_A_MUTE	0x00
+#define CS4362A_ATAPI_A_R	0x10
+#define CS4362A_ATAPI_A_L	0x20
+#define CS4362A_ATAPI_A_LR	0x30
+#define CS4362A_ATAPI_MIX_LR_VOL 0x40
+#define CS4362A_A_EQ_B		0x80
+/* register 07h */
+#define CS4362A_VOL_MASK		0x7f
+#define CS4362A_MUTE			0x80
+/* register 08h: like 07h */
+/* registers 09h..0Bh: like 06h..08h */
+/* registers 0Ch..0Eh: like 06h..08h */
+/* register 12h */
+#define CS4362A_REV_MASK	0x07
+#define CS4362A_PART_MASK	0xf8
+#define CS4362A_PART_CS4362A	0x50
diff --git a/sound/pci/oxygen/cs4398.h b/sound/pci/oxygen/cs4398.h
new file mode 100644
index 0000000..5faf5ef
--- /dev/null
+++ b/sound/pci/oxygen/cs4398.h
@@ -0,0 +1,69 @@
+/* register 1 */
+#define CS4398_REV_MASK		0x07
+#define CS4398_PART_MASK	0xf8
+#define CS4398_PART_CS4398	0x70
+/* register 2 */
+#define CS4398_FM_MASK		0x03
+#define CS4398_FM_SINGLE	0x00
+#define CS4398_FM_DOUBLE	0x01
+#define CS4398_FM_QUAD		0x02
+#define CS4398_FM_DSD		0x03
+#define CS4398_DEM_MASK		0x0c
+#define CS4398_DEM_NONE		0x00
+#define CS4398_DEM_44100	0x04
+#define CS4398_DEM_48000	0x08
+#define CS4398_DEM_32000	0x0c
+#define CS4398_DIF_MASK		0x70
+#define CS4398_DIF_LJUST	0x00
+#define CS4398_DIF_I2S		0x10
+#define CS4398_DIF_RJUST_16	0x20
+#define CS4398_DIF_RJUST_24	0x30
+#define CS4398_DIF_RJUST_20	0x40
+#define CS4398_DIF_RJUST_18	0x50
+#define CS4398_DSD_SRC		0x80
+/* register 3 */
+#define CS4398_ATAPI_MASK	0x1f
+#define CS4398_ATAPI_B_MUTE	0x00
+#define CS4398_ATAPI_B_R	0x01
+#define CS4398_ATAPI_B_L	0x02
+#define CS4398_ATAPI_B_LR	0x03
+#define CS4398_ATAPI_A_MUTE	0x00
+#define CS4398_ATAPI_A_R	0x04
+#define CS4398_ATAPI_A_L	0x08
+#define CS4398_ATAPI_A_LR	0x0c
+#define CS4398_ATAPI_MIX_LR_VOL	0x10
+#define CS4398_INVERT_B		0x20
+#define CS4398_INVERT_A		0x40
+#define CS4398_VOL_B_EQ_A	0x80
+/* register 4 */
+#define CS4398_MUTEP_MASK	0x03
+#define CS4398_MUTEP_AUTO	0x00
+#define CS4398_MUTEP_LOW	0x02
+#define CS4398_MUTEP_HIGH	0x03
+#define CS4398_MUTE_B		0x08
+#define CS4398_MUTE_A		0x10
+#define CS4398_MUTEC_A_EQ_B	0x20
+#define CS4398_DAMUTE		0x40
+#define CS4398_PAMUTE		0x80
+/* register 5 */
+#define CS4398_VOL_A_MASK	0xff
+/* register 6 */
+#define CS4398_VOL_B_MASK	0xff
+/* register 7 */
+#define CS4398_DIR_DSD		0x01
+#define CS4398_FILT_SEL		0x04
+#define CS4398_RMP_DN		0x10
+#define CS4398_RMP_UP		0x20
+#define CS4398_ZERO_CROSS	0x40
+#define CS4398_SOFT_RAMP	0x80
+/* register 8 */
+#define CS4398_MCLKDIV3		0x08
+#define CS4398_MCLKDIV2		0x10
+#define CS4398_FREEZE		0x20
+#define CS4398_CPEN		0x40
+#define CS4398_PDN		0x80
+/* register 9 */
+#define CS4398_DSD_PM_EN	0x01
+#define CS4398_DSD_PM_MODE	0x02
+#define CS4398_INVALID_DSD	0x04
+#define CS4398_STATIC_DSD	0x08
diff --git a/sound/pci/oxygen/hifier.c b/sound/pci/oxygen/hifier.c
index 666f69a..090dd43 100644
--- a/sound/pci/oxygen/hifier.c
+++ b/sound/pci/oxygen/hifier.c
@@ -66,12 +66,12 @@
 {
 	struct hifier_data *data = chip->model_data;
 
-	data->ak4396_ctl2 = AK4396_DEM_OFF | AK4396_DFS_NORMAL;
+	data->ak4396_ctl2 = AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL;
 	ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN);
 	ak4396_write(chip, AK4396_CONTROL_2, data->ak4396_ctl2);
 	ak4396_write(chip, AK4396_CONTROL_3, AK4396_PCM);
-	ak4396_write(chip, AK4396_LCH_ATT, 0xff);
-	ak4396_write(chip, AK4396_RCH_ATT, 0xff);
+	ak4396_write(chip, AK4396_LCH_ATT, 0);
+	ak4396_write(chip, AK4396_RCH_ATT, 0);
 
 	snd_component_add(chip->card, "AK4396");
 	snd_component_add(chip->card, "CS5340");
@@ -127,22 +127,8 @@
 
 static int hifier_control_filter(struct snd_kcontrol_new *template)
 {
-	if (!strcmp(template->name, "Master Playback Volume")) {
-		template->access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
-		template->tlv.p = ak4396_db_scale;
-	} else if (!strcmp(template->name, "Stereo Upmixing")) {
+	if (!strcmp(template->name, "Stereo Upmixing"))
 		return 1; /* stereo only - we don't need upmixing */
-	} else if (!strcmp(template->name,
-			   SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK)) ||
-		   !strcmp(template->name,
-			   SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT))) {
-		return 1; /* no digital input */
-	}
-	return 0;
-}
-
-static int hifier_mixer_init(struct oxygen *chip)
-{
 	return 0;
 }
 
@@ -153,18 +139,20 @@
 	.owner = THIS_MODULE,
 	.init = hifier_init,
 	.control_filter = hifier_control_filter,
-	.mixer_init = hifier_mixer_init,
 	.cleanup = hifier_cleanup,
 	.set_dac_params = set_ak4396_params,
 	.set_adc_params = set_cs5340_params,
 	.update_dac_volume = update_ak4396_volume,
 	.update_dac_mute = update_ak4396_mute,
+	.dac_tlv = ak4396_db_scale,
 	.model_data_size = sizeof(struct hifier_data),
+	.pcm_dev_cfg = PLAYBACK_0_TO_I2S |
+		       PLAYBACK_1_TO_SPDIF |
+		       CAPTURE_0_FROM_I2S_1,
 	.dac_channels = 2,
-	.used_channels = OXYGEN_CHANNEL_A |
-			 OXYGEN_CHANNEL_SPDIF |
-			 OXYGEN_CHANNEL_MULTICH,
-	.function_flags = 0,
+	.dac_volume_min = 0,
+	.dac_volume_max = 255,
+	.function_flags = OXYGEN_FUNCTION_SPI,
 	.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
 	.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
 };
@@ -181,7 +169,7 @@
 		++dev;
 		return -ENOENT;
 	}
-	err = oxygen_pci_probe(pci, index[dev], id[dev], 0, &model_hifier);
+	err = oxygen_pci_probe(pci, index[dev], id[dev], &model_hifier);
 	if (err >= 0)
 		++dev;
 	return err;
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c
index 9a9941b..63f185c 100644
--- a/sound/pci/oxygen/oxygen.c
+++ b/sound/pci/oxygen/oxygen.c
@@ -39,7 +39,7 @@
 #include <sound/tlv.h>
 #include "oxygen.h"
 #include "ak4396.h"
-#include "cm9780.h"
+#include "wm8785.h"
 
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
 MODULE_DESCRIPTION("C-Media CMI8788 driver");
@@ -78,49 +78,6 @@
 #define GPIO_AK5385_DFS_DOUBLE	0x0001
 #define GPIO_AK5385_DFS_QUAD	0x0002
 
-#define GPIO_LINE_MUTE		CM9780_GPO0
-
-#define WM8785_R0	0
-#define WM8785_R1	1
-#define WM8785_R2	2
-#define WM8785_R7	7
-
-/* R0 */
-#define WM8785_MCR_MASK		0x007
-#define WM8785_MCR_SLAVE	0x000
-#define WM8785_MCR_MASTER_128	0x001
-#define WM8785_MCR_MASTER_192	0x002
-#define WM8785_MCR_MASTER_256	0x003
-#define WM8785_MCR_MASTER_384	0x004
-#define WM8785_MCR_MASTER_512	0x005
-#define WM8785_MCR_MASTER_768	0x006
-#define WM8785_OSR_MASK		0x018
-#define WM8785_OSR_SINGLE	0x000
-#define WM8785_OSR_DOUBLE	0x008
-#define WM8785_OSR_QUAD		0x010
-#define WM8785_FORMAT_MASK	0x060
-#define WM8785_FORMAT_RJUST	0x000
-#define WM8785_FORMAT_LJUST	0x020
-#define WM8785_FORMAT_I2S	0x040
-#define WM8785_FORMAT_DSP	0x060
-/* R1 */
-#define WM8785_WL_MASK		0x003
-#define WM8785_WL_16		0x000
-#define WM8785_WL_20		0x001
-#define WM8785_WL_24		0x002
-#define WM8785_WL_32		0x003
-#define WM8785_LRP		0x004
-#define WM8785_BCLKINV		0x008
-#define WM8785_LRSWAP		0x010
-#define WM8785_DEVNO_MASK	0x0e0
-/* R2 */
-#define WM8785_HPFR		0x001
-#define WM8785_HPFL		0x002
-#define WM8785_SDODIS		0x004
-#define WM8785_PWRDNR		0x008
-#define WM8785_PWRDNL		0x010
-#define WM8785_TDM_MASK		0x1c0
-
 struct generic_data {
 	u8 ak4396_ctl2;
 };
@@ -155,7 +112,7 @@
 	struct generic_data *data = chip->model_data;
 	unsigned int i;
 
-	data->ak4396_ctl2 = AK4396_DEM_OFF | AK4396_DFS_NORMAL;
+	data->ak4396_ctl2 = AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL;
 	for (i = 0; i < 4; ++i) {
 		ak4396_write(chip, i,
 			     AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN);
@@ -163,8 +120,8 @@
 			     AK4396_CONTROL_2, data->ak4396_ctl2);
 		ak4396_write(chip, i,
 			     AK4396_CONTROL_3, AK4396_PCM);
-		ak4396_write(chip, i, AK4396_LCH_ATT, 0xff);
-		ak4396_write(chip, i, AK4396_RCH_ATT, 0xff);
+		ak4396_write(chip, i, AK4396_LCH_ATT, 0);
+		ak4396_write(chip, i, AK4396_RCH_ATT, 0);
 	}
 	snd_component_add(chip->card, "AK4396");
 }
@@ -185,23 +142,16 @@
 	snd_component_add(chip->card, "WM8785");
 }
 
-static void cmi9780_init(struct oxygen *chip)
-{
-	oxygen_ac97_clear_bits(chip, 0, CM9780_GPIO_STATUS, GPIO_LINE_MUTE);
-}
-
 static void generic_init(struct oxygen *chip)
 {
 	ak4396_init(chip);
 	wm8785_init(chip);
-	cmi9780_init(chip);
 }
 
 static void meridian_init(struct oxygen *chip)
 {
 	ak4396_init(chip);
 	ak5385_init(chip);
-	cmi9780_init(chip);
 }
 
 static void generic_cleanup(struct oxygen *chip)
@@ -297,59 +247,32 @@
 			      value, GPIO_AK5385_DFS_MASK);
 }
 
-static void cmi9780_switch_hook(struct oxygen *chip, unsigned int codec,
-				unsigned int reg, int mute)
-{
-	if (codec != 0)
-		return;
-	switch (reg) {
-	case AC97_LINE:
-		oxygen_write_ac97_masked(chip, 0, CM9780_GPIO_STATUS,
-					 mute ? GPIO_LINE_MUTE : 0,
-					 GPIO_LINE_MUTE);
-		break;
-	case AC97_MIC:
-	case AC97_CD:
-	case AC97_AUX:
-		if (!mute)
-			oxygen_ac97_set_bits(chip, 0, CM9780_GPIO_STATUS,
-					     GPIO_LINE_MUTE);
-		break;
-	}
-}
-
 static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0);
 
-static int ak4396_control_filter(struct snd_kcontrol_new *template)
-{
-	if (!strcmp(template->name, "Master Playback Volume")) {
-		template->access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
-		template->tlv.p = ak4396_db_scale;
-	}
-	return 0;
-}
-
 static const struct oxygen_model model_generic = {
 	.shortname = "C-Media CMI8788",
 	.longname = "C-Media Oxygen HD Audio",
 	.chip = "CMI8788",
 	.owner = THIS_MODULE,
 	.init = generic_init,
-	.control_filter = ak4396_control_filter,
 	.cleanup = generic_cleanup,
 	.set_dac_params = set_ak4396_params,
 	.set_adc_params = set_wm8785_params,
 	.update_dac_volume = update_ak4396_volume,
 	.update_dac_mute = update_ak4396_mute,
-	.ac97_switch_hook = cmi9780_switch_hook,
+	.dac_tlv = ak4396_db_scale,
 	.model_data_size = sizeof(struct generic_data),
+	.pcm_dev_cfg = PLAYBACK_0_TO_I2S |
+		       PLAYBACK_1_TO_SPDIF |
+		       PLAYBACK_2_TO_AC97_1 |
+		       CAPTURE_0_FROM_I2S_1 |
+		       CAPTURE_1_FROM_SPDIF |
+		       CAPTURE_2_FROM_AC97_1,
 	.dac_channels = 8,
-	.used_channels = OXYGEN_CHANNEL_A |
-			 OXYGEN_CHANNEL_C |
-			 OXYGEN_CHANNEL_SPDIF |
-			 OXYGEN_CHANNEL_MULTICH |
-			 OXYGEN_CHANNEL_AC97,
-	.function_flags = OXYGEN_FUNCTION_ENABLE_SPI_4_5,
+	.dac_volume_min = 0,
+	.dac_volume_max = 255,
+	.function_flags = OXYGEN_FUNCTION_SPI |
+			  OXYGEN_FUNCTION_ENABLE_SPI_4_5,
 	.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
 	.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
 };
@@ -359,21 +282,25 @@
 	.chip = "CMI8788",
 	.owner = THIS_MODULE,
 	.init = meridian_init,
-	.control_filter = ak4396_control_filter,
 	.cleanup = generic_cleanup,
 	.set_dac_params = set_ak4396_params,
 	.set_adc_params = set_ak5385_params,
 	.update_dac_volume = update_ak4396_volume,
 	.update_dac_mute = update_ak4396_mute,
-	.ac97_switch_hook = cmi9780_switch_hook,
+	.dac_tlv = ak4396_db_scale,
 	.model_data_size = sizeof(struct generic_data),
+	.pcm_dev_cfg = PLAYBACK_0_TO_I2S |
+		       PLAYBACK_1_TO_SPDIF |
+		       PLAYBACK_2_TO_AC97_1 |
+		       CAPTURE_0_FROM_I2S_2 |
+		       CAPTURE_1_FROM_SPDIF |
+		       CAPTURE_2_FROM_AC97_1,
 	.dac_channels = 8,
-	.used_channels = OXYGEN_CHANNEL_B |
-			 OXYGEN_CHANNEL_C |
-			 OXYGEN_CHANNEL_SPDIF |
-			 OXYGEN_CHANNEL_MULTICH |
-			 OXYGEN_CHANNEL_AC97,
-	.function_flags = OXYGEN_FUNCTION_ENABLE_SPI_4_5,
+	.dac_volume_min = 0,
+	.dac_volume_max = 255,
+	.misc_flags = OXYGEN_MISC_MIDI,
+	.function_flags = OXYGEN_FUNCTION_SPI |
+			  OXYGEN_FUNCTION_ENABLE_SPI_4_5,
 	.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
 	.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
 };
@@ -392,7 +319,7 @@
 		return -ENOENT;
 	}
 	is_meridian = pci_id->driver_data;
-	err = oxygen_pci_probe(pci, index[dev], id[dev], is_meridian,
+	err = oxygen_pci_probe(pci, index[dev], id[dev],
 			       is_meridian ? &model_meridian : &model_generic);
 	if (err >= 0)
 		++dev;
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h
index ad50fb8..a71c6e0 100644
--- a/sound/pci/oxygen/oxygen.h
+++ b/sound/pci/oxygen/oxygen.h
@@ -16,6 +16,16 @@
 #define PCM_AC97	5
 #define PCM_COUNT	6
 
+/* model-specific configuration of outputs/inputs */
+#define PLAYBACK_0_TO_I2S	0x001
+#define PLAYBACK_1_TO_SPDIF	0x004
+#define PLAYBACK_2_TO_AC97_1	0x008
+#define CAPTURE_0_FROM_I2S_1	0x010
+#define CAPTURE_0_FROM_I2S_2	0x020
+#define CAPTURE_1_FROM_SPDIF	0x080
+#define CAPTURE_2_FROM_I2S_2	0x100
+#define CAPTURE_2_FROM_AC97_1	0x200
+
 enum {
 	CONTROL_SPDIF_PCM,
 	CONTROL_SPDIF_INPUT_BITS,
@@ -87,12 +97,16 @@
 			       struct snd_pcm_hw_params *params);
 	void (*update_dac_volume)(struct oxygen *chip);
 	void (*update_dac_mute)(struct oxygen *chip);
-	void (*ac97_switch_hook)(struct oxygen *chip, unsigned int codec,
-				 unsigned int reg, int mute);
 	void (*gpio_changed)(struct oxygen *chip);
+	void (*ac97_switch)(struct oxygen *chip,
+			    unsigned int reg, unsigned int mute);
+	const unsigned int *dac_tlv;
 	size_t model_data_size;
+	unsigned int pcm_dev_cfg;
 	u8 dac_channels;
-	u8 used_channels;
+	u8 dac_volume_min;
+	u8 dac_volume_max;
+	u8 misc_flags;
 	u8 function_flags;
 	u16 dac_i2s_format;
 	u16 adc_i2s_format;
@@ -100,7 +114,7 @@
 
 /* oxygen_lib.c */
 
-int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, int midi,
+int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
 		     const struct oxygen_model *model);
 void oxygen_pci_remove(struct pci_dev *pci);
 
@@ -137,6 +151,7 @@
 			      unsigned int index, u16 data, u16 mask);
 
 void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data);
+void oxygen_write_i2c(struct oxygen *chip, u8 device, u8 map, u8 data);
 
 static inline void oxygen_set_bits8(struct oxygen *chip,
 				    unsigned int reg, u8 value)
diff --git a/sound/pci/oxygen/oxygen_io.c b/sound/pci/oxygen/oxygen_io.c
index 74e23ef..5569606 100644
--- a/sound/pci/oxygen/oxygen_io.c
+++ b/sound/pci/oxygen/oxygen_io.c
@@ -190,12 +190,31 @@
 		--count;
 	}
 
-	spin_lock_irq(&chip->reg_lock);
 	oxygen_write8(chip, OXYGEN_SPI_DATA1, data);
 	oxygen_write8(chip, OXYGEN_SPI_DATA2, data >> 8);
 	if (control & OXYGEN_SPI_DATA_LENGTH_3)
 		oxygen_write8(chip, OXYGEN_SPI_DATA3, data >> 16);
 	oxygen_write8(chip, OXYGEN_SPI_CONTROL, control);
-	spin_unlock_irq(&chip->reg_lock);
 }
 EXPORT_SYMBOL(oxygen_write_spi);
+
+void oxygen_write_i2c(struct oxygen *chip, u8 device, u8 map, u8 data)
+{
+	unsigned long timeout;
+
+	/* should not need more than about 300 us */
+	timeout = jiffies + msecs_to_jiffies(1);
+	do {
+		if (!(oxygen_read16(chip, OXYGEN_2WIRE_BUS_STATUS)
+		      & OXYGEN_2WIRE_BUSY))
+			break;
+		udelay(1);
+		cond_resched();
+	} while (time_after_eq(timeout, jiffies));
+
+	oxygen_write8(chip, OXYGEN_2WIRE_MAP, map);
+	oxygen_write8(chip, OXYGEN_2WIRE_DATA, data);
+	oxygen_write8(chip, OXYGEN_2WIRE_CONTROL,
+		      device | OXYGEN_2WIRE_DIR_WRITE);
+}
+EXPORT_SYMBOL(oxygen_write_i2c);
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c
index 78c2115..897697d 100644
--- a/sound/pci/oxygen/oxygen_lib.c
+++ b/sound/pci/oxygen/oxygen_lib.c
@@ -221,7 +221,8 @@
 
 	chip->dac_routing = 1;
 	for (i = 0; i < 8; ++i)
-		chip->dac_volume[i] = 0xff;
+		chip->dac_volume[i] = chip->model->dac_volume_min;
+	chip->dac_mute = 1;
 	chip->spdif_playback_enable = 1;
 	chip->spdif_bits = OXYGEN_SPDIF_C | OXYGEN_SPDIF_ORIGINAL |
 		(IEC958_AES1_CON_PCM_CODER << OXYGEN_SPDIF_CATEGORY_SHIFT);
@@ -240,12 +241,12 @@
 	chip->has_ac97_0 = (i & OXYGEN_AC97_CODEC_0) != 0;
 	chip->has_ac97_1 = (i & OXYGEN_AC97_CODEC_1) != 0;
 
-	oxygen_set_bits8(chip, OXYGEN_FUNCTION,
-			 OXYGEN_FUNCTION_RESET_CODEC |
-			 chip->model->function_flags);
 	oxygen_write8_masked(chip, OXYGEN_FUNCTION,
-			     OXYGEN_FUNCTION_SPI,
-			     OXYGEN_FUNCTION_2WIRE_SPI_MASK);
+			     OXYGEN_FUNCTION_RESET_CODEC |
+			     chip->model->function_flags,
+			     OXYGEN_FUNCTION_RESET_CODEC |
+			     OXYGEN_FUNCTION_2WIRE_SPI_MASK |
+			     OXYGEN_FUNCTION_ENABLE_SPI_4_5);
 	oxygen_write8(chip, OXYGEN_DMA_STATUS, 0);
 	oxygen_write8(chip, OXYGEN_DMA_PAUSE, 0);
 	oxygen_write8(chip, OXYGEN_PLAY_CHANNELS,
@@ -253,11 +254,13 @@
 		      OXYGEN_DMA_A_BURST_8 |
 		      OXYGEN_DMA_MULTICH_BURST_8);
 	oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0);
-	oxygen_write8_masked(chip, OXYGEN_MISC, 0,
+	oxygen_write8_masked(chip, OXYGEN_MISC,
+			     chip->model->misc_flags,
 			     OXYGEN_MISC_WRITE_PCI_SUBID |
 			     OXYGEN_MISC_REC_C_FROM_SPDIF |
 			     OXYGEN_MISC_REC_B_FROM_AC97 |
-			     OXYGEN_MISC_REC_A_FROM_MULTICH);
+			     OXYGEN_MISC_REC_A_FROM_MULTICH |
+			     OXYGEN_MISC_MIDI);
 	oxygen_write8(chip, OXYGEN_REC_FORMAT,
 		      (OXYGEN_FORMAT_16 << OXYGEN_REC_FORMAT_A_SHIFT) |
 		      (OXYGEN_FORMAT_16 << OXYGEN_REC_FORMAT_B_SHIFT) |
@@ -267,35 +270,49 @@
 		      (OXYGEN_FORMAT_16 << OXYGEN_MULTICH_FORMAT_SHIFT));
 	oxygen_write8(chip, OXYGEN_REC_CHANNELS, OXYGEN_REC_CHANNELS_2_2_2);
 	oxygen_write16(chip, OXYGEN_I2S_MULTICH_FORMAT,
-		       OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_LJUST |
-		       OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 |
+		       OXYGEN_RATE_48000 | chip->model->dac_i2s_format |
+		       OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 |
 		       OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
-	oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,
-		       OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_LJUST |
-		       OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 |
-		       OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
-	oxygen_write16(chip, OXYGEN_I2S_B_FORMAT,
-		       OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_LJUST |
-		       OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 |
-		       OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
+	if (chip->model->pcm_dev_cfg & CAPTURE_0_FROM_I2S_1)
+		oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,
+			       OXYGEN_RATE_48000 | chip->model->adc_i2s_format |
+			       OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 |
+			       OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
+	else
+		oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,
+			       OXYGEN_I2S_MASTER | OXYGEN_I2S_MUTE_MCLK);
+	if (chip->model->pcm_dev_cfg & (CAPTURE_0_FROM_I2S_2 |
+					CAPTURE_2_FROM_I2S_2))
+		oxygen_write16(chip, OXYGEN_I2S_B_FORMAT,
+			       OXYGEN_RATE_48000 | chip->model->adc_i2s_format |
+			       OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 |
+			       OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
+	else
+		oxygen_write16(chip, OXYGEN_I2S_B_FORMAT,
+			       OXYGEN_I2S_MASTER | OXYGEN_I2S_MUTE_MCLK);
 	oxygen_write16(chip, OXYGEN_I2S_C_FORMAT,
-		       OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_LJUST |
-		       OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 |
-		       OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
-	oxygen_write32_masked(chip, OXYGEN_SPDIF_CONTROL,
-			      OXYGEN_SPDIF_SENSE_MASK |
-			      OXYGEN_SPDIF_LOCK_MASK |
-			      OXYGEN_SPDIF_RATE_MASK |
-			      OXYGEN_SPDIF_LOCK_PAR |
-			      OXYGEN_SPDIF_IN_CLOCK_96,
-			      OXYGEN_SPDIF_OUT_ENABLE |
-			      OXYGEN_SPDIF_LOOPBACK |
-			      OXYGEN_SPDIF_SENSE_MASK |
-			      OXYGEN_SPDIF_LOCK_MASK |
-			      OXYGEN_SPDIF_RATE_MASK |
-			      OXYGEN_SPDIF_SENSE_PAR |
-			      OXYGEN_SPDIF_LOCK_PAR |
-			      OXYGEN_SPDIF_IN_CLOCK_MASK);
+		       OXYGEN_I2S_MASTER | OXYGEN_I2S_MUTE_MCLK);
+	oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL,
+			    OXYGEN_SPDIF_OUT_ENABLE |
+			    OXYGEN_SPDIF_LOOPBACK);
+	if (chip->model->pcm_dev_cfg & CAPTURE_1_FROM_SPDIF)
+		oxygen_write32_masked(chip, OXYGEN_SPDIF_CONTROL,
+				      OXYGEN_SPDIF_SENSE_MASK |
+				      OXYGEN_SPDIF_LOCK_MASK |
+				      OXYGEN_SPDIF_RATE_MASK |
+				      OXYGEN_SPDIF_LOCK_PAR |
+				      OXYGEN_SPDIF_IN_CLOCK_96,
+				      OXYGEN_SPDIF_SENSE_MASK |
+				      OXYGEN_SPDIF_LOCK_MASK |
+				      OXYGEN_SPDIF_RATE_MASK |
+				      OXYGEN_SPDIF_SENSE_PAR |
+				      OXYGEN_SPDIF_LOCK_PAR |
+				      OXYGEN_SPDIF_IN_CLOCK_MASK);
+	else
+		oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL,
+				    OXYGEN_SPDIF_SENSE_MASK |
+				    OXYGEN_SPDIF_LOCK_MASK |
+				    OXYGEN_SPDIF_RATE_MASK);
 	oxygen_write32(chip, OXYGEN_SPDIF_OUTPUT_BITS, chip->spdif_bits);
 	oxygen_clear_bits8(chip, OXYGEN_MPU401_CONTROL, OXYGEN_MPU401_LOOPBACK);
 	oxygen_write8(chip, OXYGEN_GPI_INTERRUPT_MASK, 0);
@@ -318,9 +335,12 @@
 		      (2 << OXYGEN_A_MONITOR_ROUTE_2_SHIFT) |
 		      (3 << OXYGEN_A_MONITOR_ROUTE_3_SHIFT));
 
-	oxygen_write8(chip, OXYGEN_AC97_INTERRUPT_MASK,
-		      OXYGEN_AC97_INT_READ_DONE |
-		      OXYGEN_AC97_INT_WRITE_DONE);
+	if (chip->has_ac97_0 | chip->has_ac97_1)
+		oxygen_write8(chip, OXYGEN_AC97_INTERRUPT_MASK,
+			      OXYGEN_AC97_INT_READ_DONE |
+			      OXYGEN_AC97_INT_WRITE_DONE);
+	else
+		oxygen_write8(chip, OXYGEN_AC97_INTERRUPT_MASK, 0);
 	oxygen_write32(chip, OXYGEN_AC97_OUT_CONFIG, 0);
 	oxygen_write32(chip, OXYGEN_AC97_IN_CONFIG, 0);
 	if (!(chip->has_ac97_0 | chip->has_ac97_1))
@@ -351,6 +371,8 @@
 		oxygen_write_ac97(chip, 0, AC97_REC_GAIN, 0x8000);
 		oxygen_write_ac97(chip, 0, AC97_CENTER_LFE_MASTER, 0x8080);
 		oxygen_write_ac97(chip, 0, AC97_SURROUND_MASTER, 0x8080);
+		oxygen_ac97_clear_bits(chip, 0, CM9780_GPIO_STATUS,
+				       CM9780_GPO0);
 		/* power down unused ADCs and DACs */
 		oxygen_ac97_set_bits(chip, 0, AC97_POWERDOWN,
 				     AC97_PD_PR0 | AC97_PD_PR1);
@@ -388,10 +410,8 @@
 	oxygen_write16(chip, OXYGEN_DMA_STATUS, 0);
 	oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0);
 	spin_unlock_irq(&chip->reg_lock);
-	if (chip->irq >= 0) {
+	if (chip->irq >= 0)
 		free_irq(chip->irq, chip);
-		synchronize_irq(chip->irq);
-	}
 	flush_scheduled_work();
 	chip->model->cleanup(chip);
 	mutex_destroy(&chip->mutex);
@@ -400,7 +420,7 @@
 }
 
 int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
-		     int midi, const struct oxygen_model *model)
+		     const struct oxygen_model *model)
 {
 	struct snd_card *card;
 	struct oxygen *chip;
@@ -472,9 +492,7 @@
 	if (err < 0)
 		goto err_card;
 
-	oxygen_write8_masked(chip, OXYGEN_MISC,
-			     midi ? OXYGEN_MISC_MIDI : 0, OXYGEN_MISC_MIDI);
-	if (midi) {
+	if (model->misc_flags & OXYGEN_MISC_MIDI) {
 		err = snd_mpu401_uart_new(card, 0, MPU401_HW_CMIPCI,
 					  chip->addr + OXYGEN_MPU401,
 					  MPU401_INFO_INTEGRATED, 0, 0,
@@ -486,7 +504,10 @@
 	oxygen_proc_init(chip);
 
 	spin_lock_irq(&chip->reg_lock);
-	chip->interrupt_mask |= OXYGEN_INT_SPDIF_IN_DETECT | OXYGEN_INT_AC97;
+	if (chip->model->pcm_dev_cfg & CAPTURE_1_FROM_SPDIF)
+		chip->interrupt_mask |= OXYGEN_INT_SPDIF_IN_DETECT;
+	if (chip->has_ac97_0 | chip->has_ac97_1)
+		chip->interrupt_mask |= OXYGEN_INT_AC97;
 	oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask);
 	spin_unlock_irq(&chip->reg_lock);
 
diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c
index a8e4623..cc0cdda 100644
--- a/sound/pci/oxygen/oxygen_mixer.c
+++ b/sound/pci/oxygen/oxygen_mixer.c
@@ -32,8 +32,8 @@
 
 	info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 	info->count = chip->model->dac_channels;
-	info->value.integer.min = 0;
-	info->value.integer.max = 0xff;
+	info->value.integer.min = chip->model->dac_volume_min;
+	info->value.integer.max = chip->model->dac_volume_max;
 	return 0;
 }
 
@@ -446,6 +446,50 @@
 	return changed;
 }
 
+static int monitor_volume_info(struct snd_kcontrol *ctl,
+			       struct snd_ctl_elem_info *info)
+{
+	info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	info->count = 1;
+	info->value.integer.min = 0;
+	info->value.integer.max = 1;
+	return 0;
+}
+
+static int monitor_get(struct snd_kcontrol *ctl,
+		       struct snd_ctl_elem_value *value)
+{
+	struct oxygen *chip = ctl->private_data;
+	u8 bit = ctl->private_value;
+	int invert = ctl->private_value & (1 << 8);
+
+	value->value.integer.value[0] =
+		!!invert ^ !!(oxygen_read8(chip, OXYGEN_ADC_MONITOR) & bit);
+	return 0;
+}
+
+static int monitor_put(struct snd_kcontrol *ctl,
+		       struct snd_ctl_elem_value *value)
+{
+	struct oxygen *chip = ctl->private_data;
+	u8 bit = ctl->private_value;
+	int invert = ctl->private_value & (1 << 8);
+	u8 oldreg, newreg;
+	int changed;
+
+	spin_lock_irq(&chip->reg_lock);
+	oldreg = oxygen_read8(chip, OXYGEN_ADC_MONITOR);
+	if ((!!value->value.integer.value[0] ^ !!invert) != 0)
+		newreg = oldreg | bit;
+	else
+		newreg = oldreg & ~bit;
+	changed = newreg != oldreg;
+	if (changed)
+		oxygen_write8(chip, OXYGEN_ADC_MONITOR, newreg);
+	spin_unlock_irq(&chip->reg_lock);
+	return changed;
+}
+
 static int ac97_switch_get(struct snd_kcontrol *ctl,
 			   struct snd_ctl_elem_value *value)
 {
@@ -466,6 +510,21 @@
 	return 0;
 }
 
+static void mute_ac97_ctl(struct oxygen *chip, unsigned int control)
+{
+	unsigned int priv_idx = chip->controls[control]->private_value & 0xff;
+	u16 value;
+
+	value = oxygen_read_ac97(chip, 0, priv_idx);
+	if (!(value & 0x8000)) {
+		oxygen_write_ac97(chip, 0, priv_idx, value | 0x8000);
+		if (chip->model->ac97_switch)
+			chip->model->ac97_switch(chip, priv_idx, 0x8000);
+		snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
+			       &chip->controls[control]->id);
+	}
+}
+
 static int ac97_switch_put(struct snd_kcontrol *ctl,
 			   struct snd_ctl_elem_value *value)
 {
@@ -487,9 +546,24 @@
 	change = newreg != oldreg;
 	if (change) {
 		oxygen_write_ac97(chip, codec, index, newreg);
-		if (bitnr == 15 && chip->model->ac97_switch_hook)
-			chip->model->ac97_switch_hook(chip, codec, index,
-						      newreg & 0x8000);
+		if (codec == 0 && chip->model->ac97_switch)
+			chip->model->ac97_switch(chip, index, newreg & 0x8000);
+		if (index == AC97_LINE) {
+			oxygen_write_ac97_masked(chip, 0, CM9780_GPIO_STATUS,
+						 newreg & 0x8000 ?
+						 CM9780_GPO0 : 0, CM9780_GPO0);
+			if (!(newreg & 0x8000)) {
+				mute_ac97_ctl(chip, CONTROL_MIC_CAPTURE_SWITCH);
+				mute_ac97_ctl(chip, CONTROL_CD_CAPTURE_SWITCH);
+				mute_ac97_ctl(chip, CONTROL_AUX_CAPTURE_SWITCH);
+			}
+		} else if ((index == AC97_MIC || index == AC97_CD ||
+			    index == AC97_VIDEO || index == AC97_AUX) &&
+			   bitnr == 15 && !(newreg & 0x8000)) {
+			mute_ac97_ctl(chip, CONTROL_LINE_CAPTURE_SWITCH);
+			oxygen_write_ac97_masked(chip, 0, CM9780_GPIO_STATUS,
+						 CM9780_GPO0, CM9780_GPO0);
+		}
 	}
 	mutex_unlock(&chip->mutex);
 	return change;
@@ -608,6 +682,7 @@
 		.private_value = ((codec) << 24) | (index), \
 	}
 
+static DECLARE_TLV_DB_SCALE(monitor_db_scale, -1000, 1000, 0);
 static DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0);
 static DECLARE_TLV_DB_SCALE(ac97_rec_db_scale, 0, 150, 0);
 
@@ -667,6 +742,9 @@
 		.get = spdif_pcm_get,
 		.put = spdif_pcm_put,
 	},
+};
+
+static const struct snd_kcontrol_new spdif_input_controls[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
 		.device = 1,
@@ -692,11 +770,118 @@
 	},
 };
 
+static const struct {
+	unsigned int pcm_dev;
+	struct snd_kcontrol_new controls[2];
+} monitor_controls[] = {
+	{
+		.pcm_dev = CAPTURE_0_FROM_I2S_1,
+		.controls = {
+			{
+				.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+				.name = "Analog Input Monitor Switch",
+				.info = snd_ctl_boolean_mono_info,
+				.get = monitor_get,
+				.put = monitor_put,
+				.private_value = OXYGEN_ADC_MONITOR_A,
+			},
+			{
+				.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+				.name = "Analog Input Monitor Volume",
+				.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+					  SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+				.info = monitor_volume_info,
+				.get = monitor_get,
+				.put = monitor_put,
+				.private_value = OXYGEN_ADC_MONITOR_A_HALF_VOL
+						| (1 << 8),
+				.tlv = { .p = monitor_db_scale, },
+			},
+		},
+	},
+	{
+		.pcm_dev = CAPTURE_0_FROM_I2S_2,
+		.controls = {
+			{
+				.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+				.name = "Analog Input Monitor Switch",
+				.info = snd_ctl_boolean_mono_info,
+				.get = monitor_get,
+				.put = monitor_put,
+				.private_value = OXYGEN_ADC_MONITOR_B,
+			},
+			{
+				.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+				.name = "Analog Input Monitor Volume",
+				.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+					  SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+				.info = monitor_volume_info,
+				.get = monitor_get,
+				.put = monitor_put,
+				.private_value = OXYGEN_ADC_MONITOR_B_HALF_VOL
+						| (1 << 8),
+				.tlv = { .p = monitor_db_scale, },
+			},
+		},
+	},
+	{
+		.pcm_dev = CAPTURE_2_FROM_I2S_2,
+		.controls = {
+			{
+				.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+				.name = "Analog Input Monitor Switch",
+				.index = 1,
+				.info = snd_ctl_boolean_mono_info,
+				.get = monitor_get,
+				.put = monitor_put,
+				.private_value = OXYGEN_ADC_MONITOR_B,
+			},
+			{
+				.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+				.name = "Analog Input Monitor Volume",
+				.index = 1,
+				.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+					  SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+				.info = monitor_volume_info,
+				.get = monitor_get,
+				.put = monitor_put,
+				.private_value = OXYGEN_ADC_MONITOR_B_HALF_VOL
+						| (1 << 8),
+				.tlv = { .p = monitor_db_scale, },
+			},
+		},
+	},
+	{
+		.pcm_dev = CAPTURE_1_FROM_SPDIF,
+		.controls = {
+			{
+				.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+				.name = "Digital Input Monitor Switch",
+				.info = snd_ctl_boolean_mono_info,
+				.get = monitor_get,
+				.put = monitor_put,
+				.private_value = OXYGEN_ADC_MONITOR_C,
+			},
+			{
+				.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+				.name = "Digital Input Monitor Volume",
+				.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+					  SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+				.info = monitor_volume_info,
+				.get = monitor_get,
+				.put = monitor_put,
+				.private_value = OXYGEN_ADC_MONITOR_C_HALF_VOL
+						| (1 << 8),
+				.tlv = { .p = monitor_db_scale, },
+			},
+		},
+	},
+};
+
 static const struct snd_kcontrol_new ac97_controls[] = {
 	AC97_VOLUME("Mic Capture Volume", 0, AC97_MIC),
 	AC97_SWITCH("Mic Capture Switch", 0, AC97_MIC, 15, 1),
 	AC97_SWITCH("Mic Boost (+20dB)", 0, AC97_MIC, 6, 0),
-	AC97_VOLUME("Line Capture Volume", 0, AC97_LINE),
 	AC97_SWITCH("Line Capture Switch", 0, AC97_LINE, 15, 1),
 	AC97_VOLUME("CD Capture Volume", 0, AC97_CD),
 	AC97_SWITCH("CD Capture Switch", 0, AC97_CD, 15, 1),
@@ -756,6 +941,11 @@
 			return err;
 		if (err == 1)
 			continue;
+		if (!strcmp(template.name, "Master Playback Volume") &&
+		    chip->model->dac_tlv) {
+			template.tlv.p = chip->model->dac_tlv;
+			template.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
+		}
 		ctl = snd_ctl_new1(&template, chip);
 		if (!ctl)
 			return -ENOMEM;
@@ -773,11 +963,26 @@
 
 int oxygen_mixer_init(struct oxygen *chip)
 {
+	unsigned int i;
 	int err;
 
 	err = add_controls(chip, controls, ARRAY_SIZE(controls));
 	if (err < 0)
 		return err;
+	if (chip->model->pcm_dev_cfg & CAPTURE_1_FROM_SPDIF) {
+		err = add_controls(chip, spdif_input_controls,
+				   ARRAY_SIZE(spdif_input_controls));
+		if (err < 0)
+			return err;
+	}
+	for (i = 0; i < ARRAY_SIZE(monitor_controls); ++i) {
+		if (!(chip->model->pcm_dev_cfg & monitor_controls[i].pcm_dev))
+			continue;
+		err = add_controls(chip, monitor_controls[i].controls,
+				   ARRAY_SIZE(monitor_controls[i].controls));
+		if (err < 0)
+			return err;
+	}
 	if (chip->has_ac97_0) {
 		err = add_controls(chip, ac97_controls,
 				   ARRAY_SIZE(ac97_controls));
diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c
index b70046a..b17c405 100644
--- a/sound/pci/oxygen/oxygen_pcm.c
+++ b/sound/pci/oxygen/oxygen_pcm.c
@@ -119,7 +119,7 @@
 
 	runtime->private_data = (void *)(uintptr_t)channel;
 	if (channel == PCM_B && chip->has_ac97_1 &&
-	    (chip->model->used_channels & OXYGEN_CHANNEL_AC97))
+	    (chip->model->pcm_dev_cfg & CAPTURE_2_FROM_AC97_1))
 		runtime->hw = oxygen_ac97_hardware;
 	else
 		runtime->hw = *oxygen_hardware[channel];
@@ -365,7 +365,7 @@
 		return err;
 
 	is_ac97 = chip->has_ac97_1 &&
-		(chip->model->used_channels & OXYGEN_CHANNEL_AC97);
+		(chip->model->pcm_dev_cfg & CAPTURE_2_FROM_AC97_1);
 
 	spin_lock_irq(&chip->reg_lock);
 	oxygen_write8_masked(chip, OXYGEN_REC_FORMAT,
@@ -640,34 +640,39 @@
 	int outs, ins;
 	int err;
 
-	outs = 1; /* OXYGEN_CHANNEL_MULTICH is always used */
-	ins = !!(chip->model->used_channels & (OXYGEN_CHANNEL_A |
-					       OXYGEN_CHANNEL_B));
-	err = snd_pcm_new(chip->card, "Analog", 0, outs, ins, &pcm);
-	if (err < 0)
-		return err;
-	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &oxygen_multich_ops);
-	if (chip->model->used_channels & OXYGEN_CHANNEL_A)
-		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
-				&oxygen_rec_a_ops);
-	else if (chip->model->used_channels & OXYGEN_CHANNEL_B)
-		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
-				&oxygen_rec_b_ops);
-	pcm->private_data = chip;
-	pcm->private_free = oxygen_pcm_free;
-	strcpy(pcm->name, "Analog");
-	snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
-				      SNDRV_DMA_TYPE_DEV,
-				      snd_dma_pci_data(chip->pci),
-				      512 * 1024, 2048 * 1024);
-	if (ins)
-		snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
-					      SNDRV_DMA_TYPE_DEV,
-					      snd_dma_pci_data(chip->pci),
-					      128 * 1024, 256 * 1024);
+	outs = !!(chip->model->pcm_dev_cfg & PLAYBACK_0_TO_I2S);
+	ins = !!(chip->model->pcm_dev_cfg & (CAPTURE_0_FROM_I2S_1 |
+					     CAPTURE_0_FROM_I2S_2));
+	if (outs | ins) {
+		err = snd_pcm_new(chip->card, "Analog", 0, outs, ins, &pcm);
+		if (err < 0)
+			return err;
+		if (outs)
+			snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+					&oxygen_multich_ops);
+		if (chip->model->pcm_dev_cfg & CAPTURE_0_FROM_I2S_1)
+			snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+					&oxygen_rec_a_ops);
+		else if (chip->model->pcm_dev_cfg & CAPTURE_0_FROM_I2S_2)
+			snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+					&oxygen_rec_b_ops);
+		pcm->private_data = chip;
+		pcm->private_free = oxygen_pcm_free;
+		strcpy(pcm->name, "Analog");
+		if (outs)
+			snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
+						      SNDRV_DMA_TYPE_DEV,
+						      snd_dma_pci_data(chip->pci),
+						      512 * 1024, 2048 * 1024);
+		if (ins)
+			snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
+						      SNDRV_DMA_TYPE_DEV,
+						      snd_dma_pci_data(chip->pci),
+						      128 * 1024, 256 * 1024);
+	}
 
-	outs = !!(chip->model->used_channels & OXYGEN_CHANNEL_SPDIF);
-	ins = !!(chip->model->used_channels & OXYGEN_CHANNEL_C);
+	outs = !!(chip->model->pcm_dev_cfg & PLAYBACK_1_TO_SPDIF);
+	ins = !!(chip->model->pcm_dev_cfg & CAPTURE_1_FROM_SPDIF);
 	if (outs | ins) {
 		err = snd_pcm_new(chip->card, "Digital", 1, outs, ins, &pcm);
 		if (err < 0)
@@ -686,12 +691,13 @@
 						      128 * 1024, 256 * 1024);
 	}
 
-	outs = chip->has_ac97_1 &&
-		(chip->model->used_channels & OXYGEN_CHANNEL_AC97);
-	ins = outs ||
-		(chip->model->used_channels & (OXYGEN_CHANNEL_A |
-					       OXYGEN_CHANNEL_B))
-		== (OXYGEN_CHANNEL_A | OXYGEN_CHANNEL_B);
+	if (chip->has_ac97_1) {
+		outs = !!(chip->model->pcm_dev_cfg & PLAYBACK_2_TO_AC97_1);
+		ins = !!(chip->model->pcm_dev_cfg & CAPTURE_2_FROM_AC97_1);
+	} else {
+		outs = 0;
+		ins = !!(chip->model->pcm_dev_cfg & CAPTURE_2_FROM_I2S_2);
+	}
 	if (outs | ins) {
 		err = snd_pcm_new(chip->card, outs ? "AC97" : "Analog2",
 				  2, outs, ins, &pcm);
diff --git a/sound/pci/oxygen/pcm1796.h b/sound/pci/oxygen/pcm1796.h
new file mode 100644
index 0000000..698bf46
--- /dev/null
+++ b/sound/pci/oxygen/pcm1796.h
@@ -0,0 +1,58 @@
+#ifndef PCM1796_H_INCLUDED
+#define PCM1796_H_INCLUDED
+
+/* register 16 */
+#define PCM1796_ATL_MASK	0xff
+/* register 17 */
+#define PCM1796_ATR_MASK	0xff
+/* register 18 */
+#define PCM1796_MUTE		0x01
+#define PCM1796_DME		0x02
+#define PCM1796_DMF_MASK	0x0c
+#define PCM1796_DMF_DISABLED	0x00
+#define PCM1796_DMF_48		0x04
+#define PCM1796_DMF_441		0x08
+#define PCM1796_DMF_32		0x0c
+#define PCM1796_FMT_MASK	0x70
+#define PCM1796_FMT_16_RJUST	0x00
+#define PCM1796_FMT_20_RJUST	0x10
+#define PCM1796_FMT_24_RJUST	0x20
+#define PCM1796_FMT_24_LJUST	0x30
+#define PCM1796_FMT_16_I2S	0x40
+#define PCM1796_FMT_24_I2S	0x50
+#define PCM1796_ATLD		0x80
+/* register 19 */
+#define PCM1796_INZD		0x01
+#define PCM1796_FLT_MASK	0x02
+#define PCM1796_FLT_SHARP	0x00
+#define PCM1796_FLT_SLOW	0x02
+#define PCM1796_DFMS		0x04
+#define PCM1796_OPE		0x10
+#define PCM1796_ATS_MASK	0x60
+#define PCM1796_ATS_1		0x00
+#define PCM1796_ATS_2		0x20
+#define PCM1796_ATS_4		0x40
+#define PCM1796_ATS_8		0x60
+#define PCM1796_REV		0x80
+/* register 20 */
+#define PCM1796_OS_MASK		0x03
+#define PCM1796_OS_64		0x00
+#define PCM1796_OS_32		0x01
+#define PCM1796_OS_128		0x02
+#define PCM1796_CHSL_MASK	0x04
+#define PCM1796_CHSL_LEFT	0x00
+#define PCM1796_CHSL_RIGHT	0x04
+#define PCM1796_MONO		0x08
+#define PCM1796_DFTH		0x10
+#define PCM1796_DSD		0x20
+#define PCM1796_SRST		0x40
+/* register 21 */
+#define PCM1796_PCMZ		0x01
+#define PCM1796_DZ_MASK		0x06
+/* register 22 */
+#define PCM1796_ZFGL		0x01
+#define PCM1796_ZFGR		0x02
+/* register 23 */
+#define PCM1796_ID_MASK		0x1f
+
+#endif
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c
index d163397..7f84fa5 100644
--- a/sound/pci/oxygen/virtuoso.c
+++ b/sound/pci/oxygen/virtuoso.c
@@ -18,6 +18,9 @@
  */
 
 /*
+ * Xonar D2/D2X
+ * ------------
+ *
  * CMI8788:
  *
  * SPI 0 -> 1st PCM1796 (front)
@@ -30,10 +33,33 @@
  * GPIO 5 <- external power present (D2X only)
  * GPIO 7 -> ALT
  * GPIO 8 -> enable output to speakers
+ */
+
+/*
+ * Xonar DX
+ * --------
  *
- * CM9780:
+ * CMI8788:
  *
- * GPIO 0 -> enable AC'97 bypass (line in -> ADC)
+ * I²C <-> CS4398 (front)
+ *     <-> CS4362A (surround, center/LFE, back)
+ *
+ * GPI 0 <- external power present
+ *
+ * GPIO 0 -> enable output to speakers
+ * GPIO 1 -> enable front panel I/O
+ * GPIO 2 -> M0 of CS5361
+ * GPIO 3 -> M1 of CS5361
+ * GPIO 8 -> route input jack to line-in (0) or mic-in (1)
+ *
+ * CS4398:
+ *
+ * AD0 <- 1
+ * AD1 <- 1
+ *
+ * CS4362A:
+ *
+ * AD0 <- 0
  */
 
 #include <linux/pci.h>
@@ -47,11 +73,14 @@
 #include <sound/tlv.h>
 #include "oxygen.h"
 #include "cm9780.h"
+#include "pcm1796.h"
+#include "cs4398.h"
+#include "cs4362a.h"
 
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
-MODULE_DESCRIPTION("Asus AV200 driver");
+MODULE_DESCRIPTION("Asus AVx00 driver");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Asus,AV200}}");
+MODULE_SUPPORTED_DEVICE("{{Asus,AV100},{Asus,AV200}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
@@ -64,80 +93,44 @@
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "enable card");
 
+enum {
+	MODEL_D2,
+	MODEL_D2X,
+	MODEL_DX,
+};
+
 static struct pci_device_id xonar_ids[] __devinitdata = {
-	{ OXYGEN_PCI_SUBID(0x1043, 0x8269) }, /* Asus Xonar D2 */
-	{ OXYGEN_PCI_SUBID(0x1043, 0x82b7) }, /* Asus Xonar D2X */
+	{ OXYGEN_PCI_SUBID(0x1043, 0x8269), .driver_data = MODEL_D2 },
+	{ OXYGEN_PCI_SUBID(0x1043, 0x8275), .driver_data = MODEL_DX },
+	{ OXYGEN_PCI_SUBID(0x1043, 0x82b7), .driver_data = MODEL_D2X },
 	{ }
 };
 MODULE_DEVICE_TABLE(pci, xonar_ids);
 
 
-#define GPIO_CS5381_M_MASK	0x000c
-#define GPIO_CS5381_M_SINGLE	0x0000
-#define GPIO_CS5381_M_DOUBLE	0x0004
-#define GPIO_CS5381_M_QUAD	0x0008
-#define GPIO_EXT_POWER		0x0020
-#define GPIO_ALT		0x0080
-#define GPIO_OUTPUT_ENABLE	0x0100
+#define GPIO_CS53x1_M_MASK	0x000c
+#define GPIO_CS53x1_M_SINGLE	0x0000
+#define GPIO_CS53x1_M_DOUBLE	0x0004
+#define GPIO_CS53x1_M_QUAD	0x0008
 
-#define GPIO_LINE_MUTE		CM9780_GPO0
+#define GPIO_D2X_EXT_POWER	0x0020
+#define GPIO_D2_ALT		0x0080
+#define GPIO_D2_OUTPUT_ENABLE	0x0100
 
-/* register 16 */
-#define PCM1796_ATL_MASK	0xff
-/* register 17 */
-#define PCM1796_ATR_MASK	0xff
-/* register 18 */
-#define PCM1796_MUTE		0x01
-#define PCM1796_DME		0x02
-#define PCM1796_DMF_MASK	0x0c
-#define PCM1796_DMF_DISABLED	0x00
-#define PCM1796_DMF_48		0x04
-#define PCM1796_DMF_441		0x08
-#define PCM1796_DMF_32		0x0c
-#define PCM1796_FMT_MASK	0x70
-#define PCM1796_FMT_16_RJUST	0x00
-#define PCM1796_FMT_20_RJUST	0x10
-#define PCM1796_FMT_24_RJUST	0x20
-#define PCM1796_FMT_24_LJUST	0x30
-#define PCM1796_FMT_16_I2S	0x40
-#define PCM1796_FMT_24_I2S	0x50
-#define PCM1796_ATLD		0x80
-/* register 19 */
-#define PCM1796_INZD		0x01
-#define PCM1796_FLT_MASK	0x02
-#define PCM1796_FLT_SHARP	0x00
-#define PCM1796_FLT_SLOW	0x02
-#define PCM1796_DFMS		0x04
-#define PCM1796_OPE		0x10
-#define PCM1796_ATS_MASK	0x60
-#define PCM1796_ATS_1		0x00
-#define PCM1796_ATS_2		0x20
-#define PCM1796_ATS_4		0x40
-#define PCM1796_ATS_8		0x60
-#define PCM1796_REV		0x80
-/* register 20 */
-#define PCM1796_OS_MASK		0x03
-#define PCM1796_OS_64		0x00
-#define PCM1796_OS_32		0x01
-#define PCM1796_OS_128		0x02
-#define PCM1796_CHSL_MASK	0x04
-#define PCM1796_CHSL_LEFT	0x00
-#define PCM1796_CHSL_RIGHT	0x04
-#define PCM1796_MONO		0x08
-#define PCM1796_DFTH		0x10
-#define PCM1796_DSD		0x20
-#define PCM1796_SRST		0x40
-/* register 21 */
-#define PCM1796_PCMZ		0x01
-#define PCM1796_DZ_MASK		0x06
-/* register 22 */
-#define PCM1796_ZFGL		0x01
-#define PCM1796_ZFGR		0x02
-/* register 23 */
-#define PCM1796_ID_MASK		0x1f
+#define GPI_DX_EXT_POWER	0x01
+#define GPIO_DX_OUTPUT_ENABLE	0x0001
+#define GPIO_DX_FRONT_PANEL	0x0002
+#define GPIO_DX_INPUT_ROUTE	0x0100
+
+#define I2C_DEVICE_CS4398	0x9e	/* 10011, AD1=1, AD0=1, /W=0 */
+#define I2C_DEVICE_CS4362A	0x30	/* 001100, AD0=0, /W=0 */
 
 struct xonar_data {
-	u8 is_d2x;
+	unsigned int anti_pop_delay;
+	u16 output_enable_bit;
+	u8 ext_power_reg;
+	u8 ext_power_int_reg;
+	u8 ext_power_bit;
 	u8 has_power;
 };
 
@@ -156,62 +149,157 @@
 			 (reg << 8) | value);
 }
 
-static void xonar_init(struct oxygen *chip)
+static void cs4398_write(struct oxygen *chip, u8 reg, u8 value)
+{
+	oxygen_write_i2c(chip, I2C_DEVICE_CS4398, reg, value);
+}
+
+static void cs4362a_write(struct oxygen *chip, u8 reg, u8 value)
+{
+	oxygen_write_i2c(chip, I2C_DEVICE_CS4362A, reg, value);
+}
+
+static void xonar_common_init(struct oxygen *chip)
+{
+	struct xonar_data *data = chip->model_data;
+
+	if (data->ext_power_reg) {
+		oxygen_set_bits8(chip, data->ext_power_int_reg,
+				 data->ext_power_bit);
+		chip->interrupt_mask |= OXYGEN_INT_GPIO;
+		data->has_power = !!(oxygen_read8(chip, data->ext_power_reg)
+				     & data->ext_power_bit);
+	}
+	oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CS53x1_M_MASK);
+	oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
+			      GPIO_CS53x1_M_SINGLE, GPIO_CS53x1_M_MASK);
+	oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC);
+	msleep(data->anti_pop_delay);
+	oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, data->output_enable_bit);
+	oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit);
+}
+
+static void xonar_d2_init(struct oxygen *chip)
 {
 	struct xonar_data *data = chip->model_data;
 	unsigned int i;
 
-	data->is_d2x = chip->pci->subsystem_device == 0x82b7;
+	data->anti_pop_delay = 300;
+	data->output_enable_bit = GPIO_D2_OUTPUT_ENABLE;
 
 	for (i = 0; i < 4; ++i) {
-		pcm1796_write(chip, i, 18, PCM1796_FMT_24_LJUST | PCM1796_ATLD);
+		pcm1796_write(chip, i, 18, PCM1796_MUTE | PCM1796_DMF_DISABLED |
+			      PCM1796_FMT_24_LJUST | PCM1796_ATLD);
 		pcm1796_write(chip, i, 19, PCM1796_FLT_SHARP | PCM1796_ATS_1);
 		pcm1796_write(chip, i, 20, PCM1796_OS_64);
 		pcm1796_write(chip, i, 21, 0);
-		pcm1796_write(chip, i, 16, 0xff); /* set ATL/ATR after ATLD */
-		pcm1796_write(chip, i, 17, 0xff);
+		pcm1796_write(chip, i, 16, 0x0f); /* set ATL/ATR after ATLD */
+		pcm1796_write(chip, i, 17, 0x0f);
 	}
 
-	oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
-			  GPIO_CS5381_M_MASK | GPIO_ALT);
-	oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
-			      GPIO_CS5381_M_SINGLE,
-			      GPIO_CS5381_M_MASK | GPIO_ALT);
-	if (data->is_d2x) {
-		oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
-				    GPIO_EXT_POWER);
-		oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK,
-				  GPIO_EXT_POWER);
-		chip->interrupt_mask |= OXYGEN_INT_GPIO;
-		data->has_power = !!(oxygen_read16(chip, OXYGEN_GPIO_DATA)
-				     & GPIO_EXT_POWER);
-	}
-	oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC);
-	oxygen_ac97_clear_bits(chip, 0, CM9780_GPIO_STATUS, GPIO_LINE_MUTE);
-	msleep(300);
-	oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_OUTPUT_ENABLE);
-	oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
+	oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2_ALT);
+	oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_D2_ALT);
+
+	xonar_common_init(chip);
 
 	snd_component_add(chip->card, "PCM1796");
 	snd_component_add(chip->card, "CS5381");
 }
 
+static void xonar_d2x_init(struct oxygen *chip)
+{
+	struct xonar_data *data = chip->model_data;
+
+	data->ext_power_reg = OXYGEN_GPIO_DATA;
+	data->ext_power_int_reg = OXYGEN_GPIO_INTERRUPT_MASK;
+	data->ext_power_bit = GPIO_D2X_EXT_POWER;
+	oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2X_EXT_POWER);
+	xonar_d2_init(chip);
+}
+
+static void xonar_dx_init(struct oxygen *chip)
+{
+	struct xonar_data *data = chip->model_data;
+
+	data->anti_pop_delay = 800;
+	data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE;
+	data->ext_power_reg = OXYGEN_GPI_DATA;
+	data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
+	data->ext_power_bit = GPI_DX_EXT_POWER;
+
+	oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
+		       OXYGEN_2WIRE_LENGTH_8 |
+		       OXYGEN_2WIRE_INTERRUPT_MASK |
+		       OXYGEN_2WIRE_SPEED_FAST);
+
+	/* set CPEN (control port mode) and power down */
+	cs4398_write(chip, 8, CS4398_CPEN | CS4398_PDN);
+	cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN);
+	/* configure */
+	cs4398_write(chip, 2, CS4398_FM_SINGLE |
+		     CS4398_DEM_NONE | CS4398_DIF_LJUST);
+	cs4398_write(chip, 3, CS4398_ATAPI_B_R | CS4398_ATAPI_A_L);
+	cs4398_write(chip, 4, CS4398_MUTEP_LOW | CS4398_PAMUTE);
+	cs4398_write(chip, 5, 0xfe);
+	cs4398_write(chip, 6, 0xfe);
+	cs4398_write(chip, 7, CS4398_RMP_DN | CS4398_RMP_UP |
+		     CS4398_ZERO_CROSS | CS4398_SOFT_RAMP);
+	cs4362a_write(chip, 0x02, CS4362A_DIF_LJUST);
+	cs4362a_write(chip, 0x03, CS4362A_MUTEC_6 | CS4362A_AMUTE |
+		      CS4362A_RMP_UP | CS4362A_ZERO_CROSS | CS4362A_SOFT_RAMP);
+	cs4362a_write(chip, 0x04, CS4362A_RMP_DN | CS4362A_DEM_NONE);
+	cs4362a_write(chip, 0x05, 0);
+	cs4362a_write(chip, 0x06, CS4362A_FM_SINGLE |
+		      CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L);
+	cs4362a_write(chip, 0x07, 0x7f | CS4362A_MUTE);
+	cs4362a_write(chip, 0x08, 0x7f | CS4362A_MUTE);
+	cs4362a_write(chip, 0x09, CS4362A_FM_SINGLE |
+		      CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L);
+	cs4362a_write(chip, 0x0a, 0x7f | CS4362A_MUTE);
+	cs4362a_write(chip, 0x0b, 0x7f | CS4362A_MUTE);
+	cs4362a_write(chip, 0x0c, CS4362A_FM_SINGLE |
+		      CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L);
+	cs4362a_write(chip, 0x0d, 0x7f | CS4362A_MUTE);
+	cs4362a_write(chip, 0x0e, 0x7f | CS4362A_MUTE);
+	/* clear power down */
+	cs4398_write(chip, 8, CS4398_CPEN);
+	cs4362a_write(chip, 0x01, CS4362A_CPEN);
+
+	oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
+			  GPIO_DX_FRONT_PANEL | GPIO_DX_INPUT_ROUTE);
+	oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
+			    GPIO_DX_FRONT_PANEL | GPIO_DX_INPUT_ROUTE);
+
+	xonar_common_init(chip);
+
+	snd_component_add(chip->card, "CS4398");
+	snd_component_add(chip->card, "CS4362A");
+	snd_component_add(chip->card, "CS5361");
+}
+
 static void xonar_cleanup(struct oxygen *chip)
 {
-	oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
+	struct xonar_data *data = chip->model_data;
+
+	oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit);
+}
+
+static void xonar_dx_cleanup(struct oxygen *chip)
+{
+	xonar_cleanup(chip);
+	cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN);
+	oxygen_clear_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC);
 }
 
 static void set_pcm1796_params(struct oxygen *chip,
 			       struct snd_pcm_hw_params *params)
 {
-#if 0
 	unsigned int i;
 	u8 value;
 
 	value = params_rate(params) >= 96000 ? PCM1796_OS_32 : PCM1796_OS_64;
 	for (i = 0; i < 4; ++i)
 		pcm1796_write(chip, i, 20, value);
-#endif
 }
 
 static void update_pcm1796_volume(struct oxygen *chip)
@@ -236,19 +324,73 @@
 		pcm1796_write(chip, i, 18, value);
 }
 
-static void set_cs5381_params(struct oxygen *chip,
+static void set_cs53x1_params(struct oxygen *chip,
 			      struct snd_pcm_hw_params *params)
 {
 	unsigned int value;
 
 	if (params_rate(params) <= 54000)
-		value = GPIO_CS5381_M_SINGLE;
+		value = GPIO_CS53x1_M_SINGLE;
 	else if (params_rate(params) <= 108000)
-		value = GPIO_CS5381_M_DOUBLE;
+		value = GPIO_CS53x1_M_DOUBLE;
 	else
-		value = GPIO_CS5381_M_QUAD;
+		value = GPIO_CS53x1_M_QUAD;
 	oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
-			      value, GPIO_CS5381_M_MASK);
+			      value, GPIO_CS53x1_M_MASK);
+}
+
+static void set_cs43xx_params(struct oxygen *chip,
+			      struct snd_pcm_hw_params *params)
+{
+	u8 fm_cs4398, fm_cs4362a;
+
+	fm_cs4398 = CS4398_DEM_NONE | CS4398_DIF_LJUST;
+	fm_cs4362a = CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L;
+	if (params_rate(params) <= 50000) {
+		fm_cs4398 |= CS4398_FM_SINGLE;
+		fm_cs4362a |= CS4362A_FM_SINGLE;
+	} else if (params_rate(params) <= 100000) {
+		fm_cs4398 |= CS4398_FM_DOUBLE;
+		fm_cs4362a |= CS4362A_FM_DOUBLE;
+	} else {
+		fm_cs4398 |= CS4398_FM_QUAD;
+		fm_cs4362a |= CS4362A_FM_QUAD;
+	}
+	cs4398_write(chip, 2, fm_cs4398);
+	cs4362a_write(chip, 0x06, fm_cs4362a);
+	cs4362a_write(chip, 0x09, fm_cs4362a);
+	cs4362a_write(chip, 0x0c, fm_cs4362a);
+}
+
+static void update_cs4362a_volumes(struct oxygen *chip)
+{
+	u8 mute;
+
+	mute = chip->dac_mute ? CS4362A_MUTE : 0;
+	cs4362a_write(chip, 7, (127 - chip->dac_volume[2]) | mute);
+	cs4362a_write(chip, 8, (127 - chip->dac_volume[3]) | mute);
+	cs4362a_write(chip, 10, (127 - chip->dac_volume[4]) | mute);
+	cs4362a_write(chip, 11, (127 - chip->dac_volume[5]) | mute);
+	cs4362a_write(chip, 13, (127 - chip->dac_volume[6]) | mute);
+	cs4362a_write(chip, 14, (127 - chip->dac_volume[7]) | mute);
+}
+
+static void update_cs43xx_volume(struct oxygen *chip)
+{
+	cs4398_write(chip, 5, (127 - chip->dac_volume[0]) * 2);
+	cs4398_write(chip, 6, (127 - chip->dac_volume[1]) * 2);
+	update_cs4362a_volumes(chip);
+}
+
+static void update_cs43xx_mute(struct oxygen *chip)
+{
+	u8 reg;
+
+	reg = CS4398_MUTEP_LOW | CS4398_PAMUTE;
+	if (chip->dac_mute)
+		reg |= CS4398_MUTE_B | CS4398_MUTE_A;
+	cs4398_write(chip, 4, reg);
+	update_cs4362a_volumes(chip);
 }
 
 static void xonar_gpio_changed(struct oxygen *chip)
@@ -256,10 +398,8 @@
 	struct xonar_data *data = chip->model_data;
 	u8 has_power;
 
-	if (!data->is_d2x)
-		return;
-	has_power = !!(oxygen_read16(chip, OXYGEN_GPIO_DATA)
-		       & GPIO_EXT_POWER);
+	has_power = !!(oxygen_read8(chip, data->ext_power_reg)
+		       & data->ext_power_bit);
 	if (has_power != data->has_power) {
 		data->has_power = has_power;
 		if (has_power) {
@@ -272,66 +412,13 @@
 	}
 }
 
-static void mute_ac97_ctl(struct oxygen *chip, unsigned int control)
-{
-	unsigned int index = chip->controls[control]->private_value & 0xff;
-	u16 value;
-
-	value = oxygen_read_ac97(chip, 0, index);
-	if (!(value & 0x8000)) {
-		oxygen_write_ac97(chip, 0, index, value | 0x8000);
-		snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
-			       &chip->controls[control]->id);
-	}
-}
-
-static void xonar_ac97_switch_hook(struct oxygen *chip, unsigned int codec,
-				   unsigned int reg, int mute)
-{
-	if (codec != 0)
-		return;
-	/* line-in is exclusive */
-	switch (reg) {
-	case AC97_LINE:
-		oxygen_write_ac97_masked(chip, 0, CM9780_GPIO_STATUS,
-					 mute ? GPIO_LINE_MUTE : 0,
-					 GPIO_LINE_MUTE);
-		if (!mute) {
-			mute_ac97_ctl(chip, CONTROL_MIC_CAPTURE_SWITCH);
-			mute_ac97_ctl(chip, CONTROL_CD_CAPTURE_SWITCH);
-			mute_ac97_ctl(chip, CONTROL_AUX_CAPTURE_SWITCH);
-		}
-		break;
-	case AC97_MIC:
-	case AC97_CD:
-	case AC97_VIDEO:
-	case AC97_AUX:
-		if (!mute) {
-			oxygen_ac97_set_bits(chip, 0, CM9780_GPIO_STATUS,
-					     GPIO_LINE_MUTE);
-			mute_ac97_ctl(chip, CONTROL_LINE_CAPTURE_SWITCH);
-		}
-		break;
-	}
-}
-
-static int pcm1796_volume_info(struct snd_kcontrol *ctl,
-			       struct snd_ctl_elem_info *info)
-{
-	info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-	info->count = 8;
-	info->value.integer.min = 0x0f;
-	info->value.integer.max = 0xff;
-	return 0;
-}
-
 static int alt_switch_get(struct snd_kcontrol *ctl,
 			  struct snd_ctl_elem_value *value)
 {
 	struct oxygen *chip = ctl->private_data;
 
 	value->value.integer.value[0] =
-		!!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_ALT);
+		!!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_D2_ALT);
 	return 0;
 }
 
@@ -345,9 +432,9 @@
 	spin_lock_irq(&chip->reg_lock);
 	old_bits = oxygen_read16(chip, OXYGEN_GPIO_DATA);
 	if (value->value.integer.value[0])
-		new_bits = old_bits | GPIO_ALT;
+		new_bits = old_bits | GPIO_D2_ALT;
 	else
-		new_bits = old_bits & ~GPIO_ALT;
+		new_bits = old_bits & ~GPIO_D2_ALT;
 	changed = new_bits != old_bits;
 	if (changed)
 		oxygen_write16(chip, OXYGEN_GPIO_DATA, new_bits);
@@ -363,20 +450,68 @@
 	.put = alt_switch_put,
 };
 
-static const DECLARE_TLV_DB_SCALE(pcm1796_db_scale, -12000, 50, 0);
-
-static int xonar_control_filter(struct snd_kcontrol_new *template)
+static int front_panel_get(struct snd_kcontrol *ctl,
+			   struct snd_ctl_elem_value *value)
 {
-	if (!strcmp(template->name, "Master Playback Volume")) {
-		template->access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
-		template->info = pcm1796_volume_info,
-		template->tlv.p = pcm1796_db_scale;
-	} else if (!strncmp(template->name, "CD Capture ", 11)) {
+	struct oxygen *chip = ctl->private_data;
+
+	value->value.integer.value[0] =
+		!!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DX_FRONT_PANEL);
+	return 0;
+}
+
+static int front_panel_put(struct snd_kcontrol *ctl,
+			   struct snd_ctl_elem_value *value)
+{
+	struct oxygen *chip = ctl->private_data;
+	u16 old_reg, new_reg;
+
+	spin_lock_irq(&chip->reg_lock);
+	old_reg = oxygen_read16(chip, OXYGEN_GPIO_DATA);
+	if (value->value.integer.value[0])
+		new_reg = old_reg | GPIO_DX_FRONT_PANEL;
+	else
+		new_reg = old_reg & ~GPIO_DX_FRONT_PANEL;
+	oxygen_write16(chip, OXYGEN_GPIO_DATA, new_reg);
+	spin_unlock_irq(&chip->reg_lock);
+	return old_reg != new_reg;
+}
+
+static const struct snd_kcontrol_new front_panel_switch = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Front Panel Switch",
+	.info = snd_ctl_boolean_mono_info,
+	.get = front_panel_get,
+	.put = front_panel_put,
+};
+
+static void xonar_dx_ac97_switch(struct oxygen *chip,
+				 unsigned int reg, unsigned int mute)
+{
+	if (reg == AC97_LINE) {
+		spin_lock_irq(&chip->reg_lock);
+		oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
+				      mute ? GPIO_DX_INPUT_ROUTE : 0,
+				      GPIO_DX_INPUT_ROUTE);
+		spin_unlock_irq(&chip->reg_lock);
+	}
+}
+
+static const DECLARE_TLV_DB_SCALE(pcm1796_db_scale, -12000, 50, 0);
+static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -12700, 100, 0);
+
+static int xonar_d2_control_filter(struct snd_kcontrol_new *template)
+{
+	if (!strncmp(template->name, "CD Capture ", 11))
 		/* CD in is actually connected to the video in pin */
 		template->private_value ^= AC97_CD ^ AC97_VIDEO;
-	} else if (!strcmp(template->name, "Line Capture Volume")) {
-		return 1; /* line-in bypasses the AC'97 mixer */
-	}
+	return 0;
+}
+
+static int xonar_dx_control_filter(struct snd_kcontrol_new *template)
+{
+	if (!strncmp(template->name, "CD Capture ", 11))
+		return 1; /* no CD input */
 	return 0;
 }
 
@@ -385,30 +520,96 @@
 	return snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip));
 }
 
-static const struct oxygen_model model_xonar = {
-	.shortname = "Asus AV200",
-	.longname = "Asus Virtuoso 200",
-	.chip = "AV200",
-	.owner = THIS_MODULE,
-	.init = xonar_init,
-	.control_filter = xonar_control_filter,
-	.mixer_init = xonar_mixer_init,
-	.cleanup = xonar_cleanup,
-	.set_dac_params = set_pcm1796_params,
-	.set_adc_params = set_cs5381_params,
-	.update_dac_volume = update_pcm1796_volume,
-	.update_dac_mute = update_pcm1796_mute,
-	.ac97_switch_hook = xonar_ac97_switch_hook,
-	.gpio_changed = xonar_gpio_changed,
-	.model_data_size = sizeof(struct xonar_data),
-	.dac_channels = 8,
-	.used_channels = OXYGEN_CHANNEL_B |
-			 OXYGEN_CHANNEL_C |
-			 OXYGEN_CHANNEL_SPDIF |
-			 OXYGEN_CHANNEL_MULTICH,
-	.function_flags = OXYGEN_FUNCTION_ENABLE_SPI_4_5,
-	.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-	.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+static int xonar_dx_mixer_init(struct oxygen *chip)
+{
+	return snd_ctl_add(chip->card, snd_ctl_new1(&front_panel_switch, chip));
+}
+
+static const struct oxygen_model xonar_models[] = {
+	[MODEL_D2] = {
+		.shortname = "Xonar D2",
+		.longname = "Asus Virtuoso 200",
+		.chip = "AV200",
+		.owner = THIS_MODULE,
+		.init = xonar_d2_init,
+		.control_filter = xonar_d2_control_filter,
+		.mixer_init = xonar_mixer_init,
+		.cleanup = xonar_cleanup,
+		.set_dac_params = set_pcm1796_params,
+		.set_adc_params = set_cs53x1_params,
+		.update_dac_volume = update_pcm1796_volume,
+		.update_dac_mute = update_pcm1796_mute,
+		.dac_tlv = pcm1796_db_scale,
+		.model_data_size = sizeof(struct xonar_data),
+		.pcm_dev_cfg = PLAYBACK_0_TO_I2S |
+			       PLAYBACK_1_TO_SPDIF |
+			       CAPTURE_0_FROM_I2S_2 |
+			       CAPTURE_1_FROM_SPDIF,
+		.dac_channels = 8,
+		.dac_volume_min = 0x0f,
+		.dac_volume_max = 0xff,
+		.misc_flags = OXYGEN_MISC_MIDI,
+		.function_flags = OXYGEN_FUNCTION_SPI |
+				  OXYGEN_FUNCTION_ENABLE_SPI_4_5,
+		.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+		.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+	},
+	[MODEL_D2X] = {
+		.shortname = "Xonar D2X",
+		.longname = "Asus Virtuoso 200",
+		.chip = "AV200",
+		.owner = THIS_MODULE,
+		.init = xonar_d2x_init,
+		.control_filter = xonar_d2_control_filter,
+		.mixer_init = xonar_mixer_init,
+		.cleanup = xonar_cleanup,
+		.set_dac_params = set_pcm1796_params,
+		.set_adc_params = set_cs53x1_params,
+		.update_dac_volume = update_pcm1796_volume,
+		.update_dac_mute = update_pcm1796_mute,
+		.gpio_changed = xonar_gpio_changed,
+		.dac_tlv = pcm1796_db_scale,
+		.model_data_size = sizeof(struct xonar_data),
+		.pcm_dev_cfg = PLAYBACK_0_TO_I2S |
+			       PLAYBACK_1_TO_SPDIF |
+			       CAPTURE_0_FROM_I2S_2 |
+			       CAPTURE_1_FROM_SPDIF,
+		.dac_channels = 8,
+		.dac_volume_min = 0x0f,
+		.dac_volume_max = 0xff,
+		.misc_flags = OXYGEN_MISC_MIDI,
+		.function_flags = OXYGEN_FUNCTION_SPI |
+				  OXYGEN_FUNCTION_ENABLE_SPI_4_5,
+		.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+		.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+	},
+	[MODEL_DX] = {
+		.shortname = "Xonar DX",
+		.longname = "Asus Virtuoso 100",
+		.chip = "AV200",
+		.owner = THIS_MODULE,
+		.init = xonar_dx_init,
+		.control_filter = xonar_dx_control_filter,
+		.mixer_init = xonar_dx_mixer_init,
+		.cleanup = xonar_dx_cleanup,
+		.set_dac_params = set_cs43xx_params,
+		.set_adc_params = set_cs53x1_params,
+		.update_dac_volume = update_cs43xx_volume,
+		.update_dac_mute = update_cs43xx_mute,
+		.gpio_changed = xonar_gpio_changed,
+		.ac97_switch = xonar_dx_ac97_switch,
+		.dac_tlv = cs4362a_db_scale,
+		.model_data_size = sizeof(struct xonar_data),
+		.pcm_dev_cfg = PLAYBACK_0_TO_I2S |
+			       PLAYBACK_1_TO_SPDIF |
+			       CAPTURE_0_FROM_I2S_2,
+		.dac_channels = 8,
+		.dac_volume_min = 0,
+		.dac_volume_max = 127,
+		.function_flags = OXYGEN_FUNCTION_2WIRE,
+		.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+		.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+	},
 };
 
 static int __devinit xonar_probe(struct pci_dev *pci,
@@ -423,7 +624,8 @@
 		++dev;
 		return -ENOENT;
 	}
-	err = oxygen_pci_probe(pci, index[dev], id[dev], 1, &model_xonar);
+	err = oxygen_pci_probe(pci, index[dev], id[dev],
+			       &xonar_models[pci_id->driver_data]);
 	if (err >= 0)
 		++dev;
 	return err;
diff --git a/sound/pci/oxygen/wm8785.h b/sound/pci/oxygen/wm8785.h
new file mode 100644
index 0000000..8c23e31
--- /dev/null
+++ b/sound/pci/oxygen/wm8785.h
@@ -0,0 +1,45 @@
+#ifndef WM8785_H_INCLUDED
+#define WM8785_H_INCLUDED
+
+#define WM8785_R0	0
+#define WM8785_R1	1
+#define WM8785_R2	2
+#define WM8785_R7	7
+
+/* R0 */
+#define WM8785_MCR_MASK		0x007
+#define WM8785_MCR_SLAVE	0x000
+#define WM8785_MCR_MASTER_128	0x001
+#define WM8785_MCR_MASTER_192	0x002
+#define WM8785_MCR_MASTER_256	0x003
+#define WM8785_MCR_MASTER_384	0x004
+#define WM8785_MCR_MASTER_512	0x005
+#define WM8785_MCR_MASTER_768	0x006
+#define WM8785_OSR_MASK		0x018
+#define WM8785_OSR_SINGLE	0x000
+#define WM8785_OSR_DOUBLE	0x008
+#define WM8785_OSR_QUAD		0x010
+#define WM8785_FORMAT_MASK	0x060
+#define WM8785_FORMAT_RJUST	0x000
+#define WM8785_FORMAT_LJUST	0x020
+#define WM8785_FORMAT_I2S	0x040
+#define WM8785_FORMAT_DSP	0x060
+/* R1 */
+#define WM8785_WL_MASK		0x003
+#define WM8785_WL_16		0x000
+#define WM8785_WL_20		0x001
+#define WM8785_WL_24		0x002
+#define WM8785_WL_32		0x003
+#define WM8785_LRP		0x004
+#define WM8785_BCLKINV		0x008
+#define WM8785_LRSWAP		0x010
+#define WM8785_DEVNO_MASK	0x0e0
+/* R2 */
+#define WM8785_HPFR		0x001
+#define WM8785_HPFL		0x002
+#define WM8785_SDODIS		0x004
+#define WM8785_PWRDNR		0x008
+#define WM8785_PWRDNL		0x010
+#define WM8785_TDM_MASK		0x1c0
+
+#endif
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c
index 9d5bb76..7fdcdc8 100644
--- a/sound/pci/pcxhr/pcxhr.c
+++ b/sound/pci/pcxhr/pcxhr.c
@@ -458,7 +458,7 @@
 
 	snd_printdd("pcxhr_update_r_buffer(pcm%c%d) : addr(%p) bytes(%zx) subs(%d)\n",
 		    is_capture ? 'c' : 'p',
-		    chip->chip_idx, (void*)subs->runtime->dma_addr,
+		    chip->chip_idx, (void *)(long)subs->runtime->dma_addr,
 		    subs->runtime->dma_bytes, subs->number);
 
 	pcxhr_init_rmh(&rmh, CMD_UPDATE_R_BUFFERS);
@@ -626,7 +626,7 @@
 #ifdef CONFIG_SND_DEBUG_DETECT
 	do_gettimeofday(&my_tv2);
 	snd_printdd("***TRIGGER TASKLET*** TIME = %ld (err = %x)\n",
-		    my_tv2.tv_usec - my_tv1.tv_usec, err);
+		    (long)(my_tv2.tv_usec - my_tv1.tv_usec), err);
 #endif
 }
 
@@ -846,7 +846,6 @@
 	struct pcxhr_mgr       *mgr = chip->mgr;
 	struct snd_pcm_runtime *runtime = subs->runtime;
 	struct pcxhr_stream    *stream;
-	int                 is_capture;
 
 	mutex_lock(&mgr->setup_mutex);
 
@@ -856,12 +855,10 @@
 	if( subs->stream == SNDRV_PCM_STREAM_PLAYBACK ) {
 		snd_printdd("pcxhr_open playback chip%d subs%d\n",
 			    chip->chip_idx, subs->number);
-		is_capture = 0;
 		stream = &chip->playback_stream[subs->number];
 	} else {
 		snd_printdd("pcxhr_open capture chip%d subs%d\n",
 			    chip->chip_idx, subs->number);
-		is_capture = 1;
 		if (mgr->mono_capture)
 			runtime->hw.channels_max = 1;
 		else
diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c
index c4e415d..78aa81f 100644
--- a/sound/pci/pcxhr/pcxhr_core.c
+++ b/sound/pci/pcxhr/pcxhr_core.c
@@ -897,7 +897,7 @@
 #ifdef CONFIG_SND_DEBUG_DETECT
 	do_gettimeofday(&my_tv2);
 	snd_printdd("***SET PIPE STATE*** TIME = %ld (err = %x)\n",
-		    my_tv2.tv_usec - my_tv1.tv_usec, err);
+		    (long)(my_tv2.tv_usec - my_tv1.tv_usec), err);
 #endif
 	return 0;
 }
@@ -1005,30 +1005,37 @@
 			int nb_stream = (prmh->stat[i] >> (2*FIELD_SIZE)) & MASK_FIRST_FIELD;
 			int pipe = prmh->stat[i] & MASK_FIRST_FIELD;
 			int is_capture = prmh->stat[i] & 0x400000;
-			u32 err;
+			u32 err2;
 
 			if (prmh->stat[i] & 0x800000) {	/* if BIT_END */
 				snd_printdd("TASKLET : End%sPipe %d\n",
 					    is_capture ? "Record" : "Play", pipe);
 			}
 			i++;
-			err = prmh->stat[i] ? prmh->stat[i] : prmh->stat[i+1];
-			if (err)
-				pcxhr_handle_async_err(mgr, err, PCXHR_ERR_PIPE,
+			err2 = prmh->stat[i] ? prmh->stat[i] : prmh->stat[i+1];
+			if (err2)
+				pcxhr_handle_async_err(mgr, err2,
+						       PCXHR_ERR_PIPE,
 						       pipe, is_capture);
 			i += 2;
 			for (j = 0; j < nb_stream; j++) {
-				err = prmh->stat[i] ? prmh->stat[i] : prmh->stat[i+1];
-				if (err)
-					pcxhr_handle_async_err(mgr, err, PCXHR_ERR_STREAM,
-							       pipe, is_capture);
+				err2 = prmh->stat[i] ?
+					prmh->stat[i] : prmh->stat[i+1];
+				if (err2)
+					pcxhr_handle_async_err(mgr, err2,
+							       PCXHR_ERR_STREAM,
+							       pipe,
+							       is_capture);
 				i += 2;
 			}
 			for (j = 0; j < nb_audio; j++) {
-				err = prmh->stat[i] ? prmh->stat[i] : prmh->stat[i+1];
-				if (err)
-					pcxhr_handle_async_err(mgr, err, PCXHR_ERR_AUDIO,
-							       pipe, is_capture);
+				err2 = prmh->stat[i] ?
+					prmh->stat[i] : prmh->stat[i+1];
+				if (err2)
+					pcxhr_handle_async_err(mgr, err2,
+							       PCXHR_ERR_AUDIO,
+							       pipe,
+							       is_capture);
 				i += 2;
 			}
 		}
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c
index 9408b1e..979f7da 100644
--- a/sound/pci/riptide/riptide.c
+++ b/sound/pci/riptide/riptide.c
@@ -1630,14 +1630,14 @@
 	struct snd_riptide *chip = snd_pcm_substream_chip(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct pcmhw *data;
-	int index = substream->number;
+	int sub_num = substream->number;
 
-	chip->playback_substream[index] = substream;
+	chip->playback_substream[sub_num] = substream;
 	runtime->hw = snd_riptide_playback;
 	data = kzalloc(sizeof(struct pcmhw), GFP_KERNEL);
-	data->paths = lbus_play_paths[index];
-	data->id = play_ids[index];
-	data->source = play_sources[index];
+	data->paths = lbus_play_paths[sub_num];
+	data->id = play_ids[sub_num];
+	data->source = play_sources[sub_num];
 	data->intdec[0] = 0xff;
 	data->intdec[1] = 0xff;
 	data->state = ST_STOP;
@@ -1670,10 +1670,10 @@
 {
 	struct snd_riptide *chip = snd_pcm_substream_chip(substream);
 	struct pcmhw *data = get_pcmhwdev(substream);
-	int index = substream->number;
+	int sub_num = substream->number;
 
 	substream->runtime->private_data = NULL;
-	chip->playback_substream[index] = NULL;
+	chip->playback_substream[sub_num] = NULL;
 	kfree(data);
 	return 0;
 }
diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c
index df184aa..e7ef3a1 100644
--- a/sound/pci/rme32.c
+++ b/sound/pci/rme32.c
@@ -1350,7 +1350,8 @@
 		return err;
 	rme32->port = pci_resource_start(rme32->pci, 0);
 
-	if ((rme32->iobase = ioremap_nocache(rme32->port, RME32_IO_SIZE)) == 0) {
+	rme32->iobase = ioremap_nocache(rme32->port, RME32_IO_SIZE);
+	if (!rme32->iobase) {
 		snd_printk(KERN_ERR "unable to remap memory region 0x%lx-0x%lx\n",
 			   rme32->port, rme32->port + RME32_IO_SIZE - 1);
 		return -ENOMEM;
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
index fb0a4ee8..3fdd488 100644
--- a/sound/pci/rme96.c
+++ b/sound/pci/rme96.c
@@ -1559,7 +1559,8 @@
 		return err;
 	rme96->port = pci_resource_start(rme96->pci, 0);
 
-	if ((rme96->iobase = ioremap_nocache(rme96->port, RME96_IO_SIZE)) == 0) {
+	rme96->iobase = ioremap_nocache(rme96->port, RME96_IO_SIZE);
+	if (!rme96->iobase) {
 		snd_printk(KERN_ERR "unable to remap memory region 0x%lx-0x%lx\n", rme96->port, rme96->port + RME96_IO_SIZE - 1);
 		return -ENOMEM;
 	}
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index 1be84f2..4d6fbb3 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -318,6 +318,10 @@
 #define HDSP_midi1IRQPending    (1<<31)
 
 #define HDSP_spdifFrequencyMask    (HDSP_spdifFrequency0|HDSP_spdifFrequency1|HDSP_spdifFrequency2)
+#define HDSP_spdifFrequencyMask_9632 (HDSP_spdifFrequency0|\
+				      HDSP_spdifFrequency1|\
+				      HDSP_spdifFrequency2|\
+				      HDSP_spdifFrequency3)
 
 #define HDSP_spdifFrequency32KHz   (HDSP_spdifFrequency0)
 #define HDSP_spdifFrequency44_1KHz (HDSP_spdifFrequency1)
@@ -328,7 +332,9 @@
 #define HDSP_spdifFrequency96KHz   (HDSP_spdifFrequency2|HDSP_spdifFrequency1)
 
 /* This is for H9632 cards */
-#define HDSP_spdifFrequency128KHz   HDSP_spdifFrequencyMask
+#define HDSP_spdifFrequency128KHz   (HDSP_spdifFrequency0|\
+				     HDSP_spdifFrequency1|\
+				     HDSP_spdifFrequency2)
 #define HDSP_spdifFrequency176_4KHz HDSP_spdifFrequency3
 #define HDSP_spdifFrequency192KHz   (HDSP_spdifFrequency3|HDSP_spdifFrequency0)
 
@@ -885,28 +891,15 @@
 	return ret;
 }
 
-static int hdsp_external_sample_rate (struct hdsp *hdsp)
-{
-	unsigned int status2 = hdsp_read(hdsp, HDSP_status2Register);
-	unsigned int rate_bits = status2 & HDSP_systemFrequencyMask;
-
-	switch (rate_bits) {
-	case HDSP_systemFrequency32:   return 32000;
-	case HDSP_systemFrequency44_1: return 44100;
-	case HDSP_systemFrequency48:   return 48000;
-	case HDSP_systemFrequency64:   return 64000;
-	case HDSP_systemFrequency88_2: return 88200;
-	case HDSP_systemFrequency96:   return 96000;
-	default:
-		return 0;
-	}
-}
-
 static int hdsp_spdif_sample_rate(struct hdsp *hdsp)
 {
 	unsigned int status = hdsp_read(hdsp, HDSP_statusRegister);
 	unsigned int rate_bits = (status & HDSP_spdifFrequencyMask);
 
+	/* For the 9632, the mask is different */
+	if (hdsp->io_type == H9632)
+		 rate_bits = (status & HDSP_spdifFrequencyMask_9632);
+
 	if (status & HDSP_SPDIFErrorFlag)
 		return 0;
 	
@@ -933,6 +926,31 @@
 	return 0;
 }
 
+static int hdsp_external_sample_rate(struct hdsp *hdsp)
+{
+	unsigned int status2 = hdsp_read(hdsp, HDSP_status2Register);
+	unsigned int rate_bits = status2 & HDSP_systemFrequencyMask;
+
+	/* For the 9632 card, there seems to be no bit for indicating external
+	 * sample rate greater than 96kHz. The card reports the corresponding
+	 * single speed. So the best means seems to get spdif rate when
+	 * autosync reference is spdif */
+	if (hdsp->io_type == H9632 &&
+	    hdsp_autosync_ref(hdsp) == HDSP_AUTOSYNC_FROM_SPDIF)
+		 return hdsp_spdif_sample_rate(hdsp);
+
+	switch (rate_bits) {
+	case HDSP_systemFrequency32:   return 32000;
+	case HDSP_systemFrequency44_1: return 44100;
+	case HDSP_systemFrequency48:   return 48000;
+	case HDSP_systemFrequency64:   return 64000;
+	case HDSP_systemFrequency88_2: return 88200;
+	case HDSP_systemFrequency96:   return 96000;
+	default:
+		return 0;
+	}
+}
+
 static void hdsp_compute_period_size(struct hdsp *hdsp)
 {
 	hdsp->period_bytes = 1 << ((hdsp_decode_latency(hdsp->control_register) + 8));
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index 9a19ae6..ab423bc 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -540,7 +540,8 @@
 
 static inline int HDSPM_bit2freq(int n)
 {
-	static int bit2freq_tab[] = { 0, 32000, 44100, 48000, 64000, 88200,
+	static const int bit2freq_tab[] = {
+		0, 32000, 44100, 48000, 64000, 88200,
 		96000, 128000, 176400, 192000 };
 	if (n < 1 || n > 9)
 		return 0;
@@ -582,7 +583,7 @@
 	return hdspm->mixer->ch[chan].pb[pb];
 }
 
-static inline int hdspm_write_in_gain(struct hdspm * hdspm, unsigned int chan,
+static int hdspm_write_in_gain(struct hdspm *hdspm, unsigned int chan,
 				      unsigned int in, unsigned short data)
 {
 	if (chan >= HDSPM_MIXER_CHANNELS || in >= HDSPM_MIXER_CHANNELS)
@@ -595,7 +596,7 @@
 	return 0;
 }
 
-static inline int hdspm_write_pb_gain(struct hdspm * hdspm, unsigned int chan,
+static int hdspm_write_pb_gain(struct hdspm *hdspm, unsigned int chan,
 				      unsigned int pb, unsigned short data)
 {
 	if (chan >= HDSPM_MIXER_CHANNELS || pb >= HDSPM_MIXER_CHANNELS)
@@ -621,7 +622,7 @@
 }
 
 /* check if same process is writing and reading */
-static inline int snd_hdspm_use_is_exclusive(struct hdspm * hdspm)
+static int snd_hdspm_use_is_exclusive(struct hdspm *hdspm)
 {
 	unsigned long flags;
 	int ret = 1;
@@ -636,7 +637,7 @@
 }
 
 /* check for external sample rate */
-static inline int hdspm_external_sample_rate(struct hdspm * hdspm)
+static int hdspm_external_sample_rate(struct hdspm *hdspm)
 {
 	if (hdspm->is_aes32) {
 		unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
@@ -787,7 +788,7 @@
 }
 
 /* should I silence all or only opened ones ? doit all for first even is 4MB*/
-static inline void hdspm_silence_playback(struct hdspm * hdspm)
+static void hdspm_silence_playback(struct hdspm *hdspm)
 {
 	int i;
 	int n = hdspm->period_bytes;
@@ -1028,9 +1029,9 @@
 {
 	/* the hardware already does the relevant bit-mask with 0xff */
 	if (id)
-		return hdspm_write(hdspm, HDSPM_midiDataOut1, val);
+		hdspm_write(hdspm, HDSPM_midiDataOut1, val);
 	else
-		return hdspm_write(hdspm, HDSPM_midiDataOut0, val);
+		hdspm_write(hdspm, HDSPM_midiDataOut0, val);
 }
 
 static inline int snd_hdspm_midi_input_available (struct hdspm *hdspm, int id)
@@ -1057,7 +1058,7 @@
 		return 0;
 }
 
-static inline void snd_hdspm_flush_midi_input (struct hdspm *hdspm, int id)
+static void snd_hdspm_flush_midi_input(struct hdspm *hdspm, int id)
 {
 	while (snd_hdspm_midi_input_available (hdspm, id))
 		snd_hdspm_midi_read_byte (hdspm, id);
diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c
index 742f118..df2007e 100644
--- a/sound/pci/sis7019.c
+++ b/sound/pci/sis7019.c
@@ -1194,7 +1194,6 @@
 	/* snd_pcm_suspend_all() stopped all channels, so we're quiescent.
 	 */
 	if (sis->irq >= 0) {
-		synchronize_irq(sis->irq);
 		free_irq(sis->irq, sis);
 		sis->irq = -1;
 	}
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
index 71138ff..bbcee2c 100644
--- a/sound/pci/trident/trident_main.c
+++ b/sound/pci/trident/trident_main.c
@@ -3676,6 +3676,8 @@
 	else if (trident->device == TRIDENT_DEVICE_ID_SI7018) {
 		outl(0, TRID_REG(trident, SI_SERIAL_INTF_CTRL));
 	}
+	if (trident->irq >= 0)
+		free_irq(trident->irq, trident);
 	if (trident->tlb.buffer.area) {
 		outl(0, TRID_REG(trident, NX_TLBC));
 		if (trident->tlb.memhdr)
@@ -3685,8 +3687,6 @@
 		vfree(trident->tlb.shadow_entries);
 		snd_dma_free_pages(&trident->tlb.buffer);
 	}
-	if (trident->irq >= 0)
-		free_irq(trident->irq, trident);
 	pci_release_regions(trident->pci);
 	pci_disable_device(trident->pci);
 	kfree(trident);
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index a756be6..b585cc3 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -2236,7 +2236,7 @@
 	/* disable interrupts */
 	for (i = 0; i < chip->num_devs; i++)
 		snd_via82xx_channel_reset(chip, &chip->devs[i]);
-	synchronize_irq(chip->irq);
+
 	if (chip->irq >= 0)
 		free_irq(chip->irq, chip);
  __end_hw:
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c
index f5df1c7..31f64ee 100644
--- a/sound/pci/via82xx_modem.c
+++ b/sound/pci/via82xx_modem.c
@@ -1075,7 +1075,7 @@
 	/* disable interrupts */
 	for (i = 0; i < chip->num_devs; i++)
 		snd_via82xx_channel_reset(chip, &chip->devs[i]);
-	synchronize_irq(chip->irq);
+
       __end_hw:
 	if (chip->irq >= 0)
 		free_irq(chip->irq, chip);
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
index 42c1eb7d..29b3056 100644
--- a/sound/pci/ymfpci/ymfpci_main.c
+++ b/sound/pci/ymfpci/ymfpci_main.c
@@ -2249,6 +2249,8 @@
 #ifdef CONFIG_PM
 	vfree(chip->saved_regs);
 #endif
+	if (chip->irq >= 0)
+		free_irq(chip->irq, chip);
 	release_and_free_resource(chip->mpu_res);
 	release_and_free_resource(chip->fm_res);
 	snd_ymfpci_free_gameport(chip);
@@ -2257,8 +2259,6 @@
 	if (chip->work_ptr.area)
 		snd_dma_free_pages(&chip->work_ptr);
 	
-	if (chip->irq >= 0)
-		free_irq(chip->irq, chip);
 	release_and_free_resource(chip->res_reg_area);
 
 	pci_write_config_word(chip->pci, 0x40, chip->old_legacy_ctrl);
diff --git a/sound/ppc/awacs.c b/sound/ppc/awacs.c
index 8441e78..566a6d0 100644
--- a/sound/ppc/awacs.c
+++ b/sound/ppc/awacs.c
@@ -141,7 +141,7 @@
 	uinfo->value.integer.max = 15;
 	return 0;
 }
- 
+
 static int snd_pmac_awacs_get_volume(struct snd_kcontrol *kcontrol,
 				     struct snd_ctl_elem_value *ucontrol)
 {
@@ -267,7 +267,8 @@
 static void awacs_set_cuda(int reg, int val)
 {
 	struct adb_request req;
-	cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, 0x8a, reg, val);
+	cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, 0x8a,
+			reg, val);
 	while (! req.complete)
 		cuda_poll();
 }
@@ -289,11 +290,11 @@
 /*
  * vol = 0 - 31 (attenuation), 32 = mute bit, stereo
  */
-static int awacs_amp_set_vol(struct awacs_amp *amp, int index, int lvol, int rvol,
-			     int do_check)
+static int awacs_amp_set_vol(struct awacs_amp *amp, int index,
+			     int lvol, int rvol, int do_check)
 {
 	if (do_check && amp->amp_vol[index][0] == lvol &&
-	    amp->amp_vol[index][1] == rvol)
+			amp->amp_vol[index][1] == rvol)
 		return 0;
 	awacs_set_cuda(3 + index, lvol);
 	awacs_set_cuda(5 + index, rvol);
@@ -337,7 +338,7 @@
 	uinfo->value.integer.max = 31;
 	return 0;
 }
- 
+
 static int snd_pmac_awacs_get_volume_amp(struct snd_kcontrol *kcontrol,
 					 struct snd_ctl_elem_value *ucontrol)
 {
@@ -361,8 +362,10 @@
 	snd_assert(amp, return -EINVAL);
 	snd_assert(index >= 0 && index <= 1, return -EINVAL);
 
-	vol[0] = (31 - (ucontrol->value.integer.value[0] & 31)) | (amp->amp_vol[index][0] & 32);
-	vol[1] = (31 - (ucontrol->value.integer.value[1] & 31)) | (amp->amp_vol[index][1] & 32);
+	vol[0] = (31 - (ucontrol->value.integer.value[0] & 31))
+		| (amp->amp_vol[index][0] & 32);
+	vol[1] = (31 - (ucontrol->value.integer.value[1] & 31))
+		| (amp->amp_vol[index][1] & 32);
 	return awacs_amp_set_vol(amp, index, vol[0], vol[1], 1);
 }
 
@@ -374,8 +377,10 @@
 	struct awacs_amp *amp = chip->mixer_data;
 	snd_assert(amp, return -EINVAL);
 	snd_assert(index >= 0 && index <= 1, return -EINVAL);
-	ucontrol->value.integer.value[0] = (amp->amp_vol[index][0] & 32) ? 0 : 1;
-	ucontrol->value.integer.value[1] = (amp->amp_vol[index][1] & 32) ? 0 : 1;
+	ucontrol->value.integer.value[0] = (amp->amp_vol[index][0] & 32)
+					? 0 : 1;
+	ucontrol->value.integer.value[1] = (amp->amp_vol[index][1] & 32)
+					? 0 : 1;
 	return 0;
 }
 
@@ -389,8 +394,10 @@
 	snd_assert(amp, return -EINVAL);
 	snd_assert(index >= 0 && index <= 1, return -EINVAL);
 
-	vol[0] = (ucontrol->value.integer.value[0] ? 0 : 32) | (amp->amp_vol[index][0] & 31);
-	vol[1] = (ucontrol->value.integer.value[1] ? 0 : 32) | (amp->amp_vol[index][1] & 31);
+	vol[0] = (ucontrol->value.integer.value[0] ? 0 : 32)
+		| (amp->amp_vol[index][0] & 31);
+	vol[1] = (ucontrol->value.integer.value[1] ? 0 : 32)
+		| (amp->amp_vol[index][1] & 31);
 	return awacs_amp_set_vol(amp, index, vol[0], vol[1], 1);
 }
 
@@ -403,7 +410,7 @@
 	uinfo->value.integer.max = 14;
 	return 0;
 }
- 
+
 static int snd_pmac_awacs_get_tone_amp(struct snd_kcontrol *kcontrol,
 				       struct snd_ctl_elem_value *ucontrol)
 {
@@ -445,7 +452,7 @@
 	uinfo->value.integer.max = 99;
 	return 0;
 }
- 
+
 static int snd_pmac_awacs_get_master_amp(struct snd_kcontrol *kcontrol,
 					 struct snd_ctl_elem_value *ucontrol)
 {
@@ -544,7 +551,7 @@
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 	uinfo->count = 1;
 	uinfo->value.integer.min = 0;
-	uinfo->value.integer.max = 2;
+	uinfo->value.integer.max = 3;
 	return 0;
 }
 
@@ -552,16 +559,14 @@
 					   struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
-	int val;
+	int val = 0;
 	unsigned long flags;
 
 	spin_lock_irqsave(&chip->reg_lock, flags);
 	if (chip->awacs_reg[6] & MASK_MIC_BOOST)
-		val = 2;
-	else if (chip->awacs_reg[0] & MASK_GAINLINE)
-		val = 1;
-	else
-		val = 0;
+		val |= 2;
+	if (chip->awacs_reg[0] & MASK_GAINLINE)
+		val |= 1;
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 	ucontrol->value.integer.value[0] = val;
 	return 0;
@@ -578,11 +583,10 @@
 	spin_lock_irqsave(&chip->reg_lock, flags);
 	val0 = chip->awacs_reg[0] & ~MASK_GAINLINE;
 	val6 = chip->awacs_reg[6] & ~MASK_MIC_BOOST;
-	if (ucontrol->value.integer.value[0] > 0) {
+	if (ucontrol->value.integer.value[0] & 1)
 		val0 |= MASK_GAINLINE;
-		if (ucontrol->value.integer.value[0] > 1)
-			val6 |= MASK_MIC_BOOST;
-	}
+	if (ucontrol->value.integer.value[0] & 2)
+		val6 |= MASK_MIC_BOOST;
 	if (val0 != chip->awacs_reg[0]) {
 		snd_pmac_awacs_write_reg(chip, 0, val0);
 		changed = 1;
@@ -599,9 +603,32 @@
  * lists of mixer elements
  */
 static struct snd_kcontrol_new snd_pmac_awacs_mixers[] __initdata = {
-	AWACS_VOLUME("Master Playback Volume", 2, 6, 1),
 	AWACS_SWITCH("Master Capture Switch", 1, SHIFT_LOOPTHRU, 0),
-	AWACS_VOLUME("Capture Volume", 0, 4, 0),
+	AWACS_VOLUME("Master Capture Volume", 0, 4, 0),
+/*	AWACS_SWITCH("Unknown Playback Switch", 6, SHIFT_PAROUT0, 0), */
+};
+
+static struct snd_kcontrol_new snd_pmac_screamer_mixers_beige[] __initdata = {
+	AWACS_VOLUME("Master Playback Volume", 2, 6, 1),
+	AWACS_VOLUME("Play-through Playback Volume", 5, 6, 1),
+	AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0),
+	AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_LINE, 0),
+};
+
+static struct snd_kcontrol_new snd_pmac_screamer_mixers_imac[] __initdata = {
+	AWACS_VOLUME("Line out Playback Volume", 2, 6, 1),
+	AWACS_VOLUME("Master Playback Volume", 5, 6, 1),
+	AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
+};
+
+static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac7500[] __initdata = {
+	AWACS_VOLUME("Line out Playback Volume", 2, 6, 1),
+	AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
+	AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0),
+};
+
+static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac[] __initdata = {
+	AWACS_VOLUME("Master Playback Volume", 2, 6, 1),
 	AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
 };
 
@@ -621,35 +648,61 @@
 static struct snd_kcontrol_new snd_pmac_awacs_master_sw __initdata =
 AWACS_SWITCH("Master Playback Switch", 1, SHIFT_HDMUTE, 1);
 
+static struct snd_kcontrol_new snd_pmac_awacs_master_sw_imac __initdata =
+AWACS_SWITCH("Line out Playback Switch", 1, SHIFT_HDMUTE, 1);
+
 static struct snd_kcontrol_new snd_pmac_awacs_mic_boost[] __initdata = {
-	AWACS_SWITCH("Mic Boost", 0, SHIFT_GAINLINE, 0),
+	AWACS_SWITCH("Mic Boost Capture Switch", 0, SHIFT_GAINLINE, 0),
 };
 
 static struct snd_kcontrol_new snd_pmac_screamer_mic_boost[] __initdata = {
 	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-	  .name = "Mic Boost",
+	  .name = "Mic Boost Capture Volume",
 	  .info = snd_pmac_screamer_mic_boost_info,
 	  .get = snd_pmac_screamer_mic_boost_get,
 	  .put = snd_pmac_screamer_mic_boost_put,
 	},
 };
 
+static struct snd_kcontrol_new snd_pmac_awacs_mic_boost_pmac7500[] __initdata =
+{
+	AWACS_SWITCH("Line Boost Capture Switch", 0, SHIFT_GAINLINE, 0),
+};
+
+static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_beige[] __initdata =
+{
+	AWACS_SWITCH("Line Boost Capture Switch", 0, SHIFT_GAINLINE, 0),
+	AWACS_SWITCH("CD Boost Capture Switch", 6, SHIFT_MIC_BOOST, 0),
+};
+
+static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_imac[] __initdata =
+{
+	AWACS_SWITCH("Line Boost Capture Switch", 0, SHIFT_GAINLINE, 0),
+	AWACS_SWITCH("Mic Boost Capture Switch", 6, SHIFT_MIC_BOOST, 0),
+};
+
 static struct snd_kcontrol_new snd_pmac_awacs_speaker_vol[] __initdata = {
 	AWACS_VOLUME("PC Speaker Playback Volume", 4, 6, 1),
 };
+
 static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw __initdata =
 AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_SPKMUTE, 1);
 
+static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac __initdata =
+AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_PAROUT1, 0);
+
 
 /*
  * add new mixer elements to the card
  */
-static int build_mixers(struct snd_pmac *chip, int nums, struct snd_kcontrol_new *mixers)
+static int build_mixers(struct snd_pmac *chip, int nums,
+			struct snd_kcontrol_new *mixers)
 {
 	int i, err;
 
 	for (i = 0; i < nums; i++) {
-		if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&mixers[i], chip))) < 0)
+		err = snd_ctl_add(chip->card, snd_ctl_new1(&mixers[i], chip));
+		if (err < 0)
 			return err;
 	}
 	return 0;
@@ -699,8 +752,10 @@
 #ifdef PMAC_AMP_AVAIL
 	if (chip->mixer_data) {
 		struct awacs_amp *amp = chip->mixer_data;
-		awacs_amp_set_vol(amp, 0, amp->amp_vol[0][0], amp->amp_vol[0][1], 0);
-		awacs_amp_set_vol(amp, 1, amp->amp_vol[1][0], amp->amp_vol[1][1], 0);
+		awacs_amp_set_vol(amp, 0,
+				  amp->amp_vol[0][0], amp->amp_vol[0][1], 0);
+		awacs_amp_set_vol(amp, 1,
+				  amp->amp_vol[1][0], amp->amp_vol[1][1], 0);
 		awacs_amp_set_tone(amp, amp->amp_tone[0], amp->amp_tone[1]);
 		awacs_amp_set_master(amp, amp->amp_master);
 	}
@@ -708,6 +763,14 @@
 }
 #endif /* CONFIG_PM */
 
+#define IS_PM7500 (machine_is_compatible("AAPL,7500"))
+#define IS_BEIGE (machine_is_compatible("AAPL,Gossamer"))
+#define IS_IMAC (machine_is_compatible("PowerMac2,1") \
+		|| machine_is_compatible("PowerMac2,2") \
+		|| machine_is_compatible("PowerMac4,1"))
+
+static int imac;
+
 #ifdef PMAC_SUPPORT_AUTOMUTE
 /*
  * auto-mute stuffs
@@ -750,9 +813,16 @@
 		} else
 #endif
 		{
-			int reg = chip->awacs_reg[1] | (MASK_HDMUTE|MASK_SPKMUTE);
+			int reg = chip->awacs_reg[1]
+				| (MASK_HDMUTE | MASK_SPKMUTE);
+			if (imac) {
+				reg &= ~MASK_SPKMUTE;
+				reg &= ~MASK_PAROUT1;
+			}
 			if (snd_pmac_awacs_detect_headphone(chip))
 				reg &= ~MASK_HDMUTE;
+			else if (imac)
+				reg |= MASK_PAROUT1;
 			else
 				reg &= ~MASK_SPKMUTE;
 			if (do_notify && reg == chip->awacs_reg[1])
@@ -778,8 +848,11 @@
 int __init
 snd_pmac_awacs_init(struct snd_pmac *chip)
 {
+	int pm7500 = IS_PM7500;
+	int beige = IS_BEIGE;
 	int err, vol;
 
+	imac = IS_IMAC;
 	/* looks like MASK_GAINLINE triggers something, so we set here
 	 * as start-up
 	 */
@@ -787,7 +860,7 @@
 	chip->awacs_reg[1] = MASK_CMUTE | MASK_AMUTE;
 	/* FIXME: Only machines with external SRS module need MASK_PAROUT */
 	if (chip->has_iic || chip->device_id == 0x5 ||
-	    /*chip->_device_id == 0x8 || */
+	    /* chip->_device_id == 0x8 || */
 	    chip->device_id == 0xb)
 		chip->awacs_reg[1] |= MASK_PAROUT;
 	/* get default volume from nvram */
@@ -798,8 +871,10 @@
 	chip->awacs_reg[2] = vol;
 	chip->awacs_reg[4] = vol;
 	if (chip->model == PMAC_SCREAMER) {
-		chip->awacs_reg[5] = vol; /* FIXME: screamer has loopthru vol control */
-		chip->awacs_reg[6] = MASK_MIC_BOOST; /* FIXME: maybe should be vol << 3 for PCMCIA speaker */
+		/* FIXME: screamer has loopthru vol control */
+		chip->awacs_reg[5] = vol;
+		/* FIXME: maybe should be vol << 3 for PCMCIA speaker */
+		chip->awacs_reg[6] = MASK_MIC_BOOST;
 		chip->awacs_reg[7] = 0;
 	}
 
@@ -815,7 +890,8 @@
 			return -ENOMEM;
 		chip->mixer_data = amp;
 		chip->mixer_free = awacs_amp_free;
-		awacs_amp_set_vol(amp, 0, 63, 63, 0); /* mute and zero vol */
+		/* mute and zero vol */
+		awacs_amp_set_vol(amp, 0, 63, 63, 0);
 		awacs_amp_set_vol(amp, 1, 63, 63, 0);
 		awacs_amp_set_tone(amp, 7, 7); /* 0 dB */
 		awacs_amp_set_master(amp, 79); /* 0 dB */
@@ -826,20 +902,25 @@
 		/* set headphone-jack detection bit */
 		switch (chip->model) {
 		case PMAC_AWACS:
-			chip->hp_stat_mask = 0x04;
+			chip->hp_stat_mask = pm7500 ? MASK_HDPCONN
+				: MASK_LOCONN;
 			break;
 		case PMAC_SCREAMER:
 			switch (chip->device_id) {
 			case 0x08:
-				/* 1 = side jack, 2 = front jack */
-				chip->hp_stat_mask = 0x03;
+			case 0x0B:
+				chip->hp_stat_mask = imac
+					? MASK_LOCONN_IMAC |
+					MASK_HDPLCONN_IMAC |
+					MASK_HDPRCONN_IMAC
+					: MASK_HDPCONN;
 				break;
 			case 0x00:
 			case 0x05:
-				chip->hp_stat_mask = 0x04;
+				chip->hp_stat_mask = MASK_LOCONN;
 				break;
 			default:
-				chip->hp_stat_mask = 0x08;
+				chip->hp_stat_mask = MASK_HDPCONN;
 				break;
 			}
 			break;
@@ -854,19 +935,43 @@
 	 */
 	strcpy(chip->card->mixername, "PowerMac AWACS");
 
-	if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mixers),
-				snd_pmac_awacs_mixers)) < 0)
+	err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mixers),
+				snd_pmac_awacs_mixers);
+	if (err < 0)
 		return err;
-	if (chip->model == PMAC_SCREAMER)
+	if (beige)
+		;
+	else if (chip->model == PMAC_SCREAMER)
 		err = build_mixers(chip, ARRAY_SIZE(snd_pmac_screamer_mixers2),
 				   snd_pmac_screamer_mixers2);
-	else
+	else if (!pm7500)
 		err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mixers2),
 				   snd_pmac_awacs_mixers2);
 	if (err < 0)
 		return err;
-	chip->master_sw_ctl = snd_ctl_new1(&snd_pmac_awacs_master_sw, chip);
-	if ((err = snd_ctl_add(chip->card, chip->master_sw_ctl)) < 0)
+	if (pm7500)
+		err = build_mixers(chip,
+				   ARRAY_SIZE(snd_pmac_awacs_mixers_pmac7500),
+				   snd_pmac_awacs_mixers_pmac7500);
+	else if (beige)
+		err = build_mixers(chip,
+				   ARRAY_SIZE(snd_pmac_screamer_mixers_beige),
+				   snd_pmac_screamer_mixers_beige);
+	else if (imac)
+		err = build_mixers(chip,
+				   ARRAY_SIZE(snd_pmac_screamer_mixers_imac),
+				   snd_pmac_screamer_mixers_imac);
+	else
+		err = build_mixers(chip,
+				   ARRAY_SIZE(snd_pmac_awacs_mixers_pmac),
+				   snd_pmac_awacs_mixers_pmac);
+	if (err < 0)
+		return err;
+	chip->master_sw_ctl = snd_ctl_new1((pm7500 || imac)
+			? &snd_pmac_awacs_master_sw_imac
+			: &snd_pmac_awacs_master_sw, chip);
+	err = snd_ctl_add(chip->card, chip->master_sw_ctl);
+	if (err < 0)
 		return err;
 #ifdef PMAC_AMP_AVAIL
 	if (chip->mixer_data) {
@@ -876,37 +981,58 @@
 		 * screamer registers.
 		 * in this case, it seems the route C is not used.
 		 */
-		if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_amp_vol),
-					snd_pmac_awacs_amp_vol)) < 0)
+		err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_amp_vol),
+					snd_pmac_awacs_amp_vol);
+		if (err < 0)
 			return err;
 		/* overwrite */
-		chip->master_sw_ctl = snd_ctl_new1(&snd_pmac_awacs_amp_hp_sw, chip);
-		if ((err = snd_ctl_add(chip->card, chip->master_sw_ctl)) < 0)
+		chip->master_sw_ctl = snd_ctl_new1(&snd_pmac_awacs_amp_hp_sw,
+							chip);
+		err = snd_ctl_add(chip->card, chip->master_sw_ctl);
+		if (err < 0)
 			return err;
-		chip->speaker_sw_ctl = snd_ctl_new1(&snd_pmac_awacs_amp_spk_sw, chip);
-		if ((err = snd_ctl_add(chip->card, chip->speaker_sw_ctl)) < 0)
+		chip->speaker_sw_ctl = snd_ctl_new1(&snd_pmac_awacs_amp_spk_sw,
+							chip);
+		err = snd_ctl_add(chip->card, chip->speaker_sw_ctl);
+		if (err < 0)
 			return err;
 	} else
 #endif /* PMAC_AMP_AVAIL */
 	{
 		/* route A = headphone, route C = speaker */
-		if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_speaker_vol),
-					snd_pmac_awacs_speaker_vol)) < 0)
+		err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_speaker_vol),
+					snd_pmac_awacs_speaker_vol);
+		if (err < 0)
 			return err;
-		chip->speaker_sw_ctl = snd_ctl_new1(&snd_pmac_awacs_speaker_sw, chip);
-		if ((err = snd_ctl_add(chip->card, chip->speaker_sw_ctl)) < 0)
+		chip->speaker_sw_ctl = snd_ctl_new1(imac
+				? &snd_pmac_awacs_speaker_sw_imac
+				: &snd_pmac_awacs_speaker_sw, chip);
+		err = snd_ctl_add(chip->card, chip->speaker_sw_ctl);
+		if (err < 0)
 			return err;
 	}
 
-	if (chip->model == PMAC_SCREAMER) {
-		if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_screamer_mic_boost),
-					snd_pmac_screamer_mic_boost)) < 0)
-			return err;
-	} else {
-		if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mic_boost),
-					snd_pmac_awacs_mic_boost)) < 0)
-			return err;
-	}
+	if (beige)
+		err = build_mixers(chip,
+				ARRAY_SIZE(snd_pmac_screamer_mic_boost_beige),
+				snd_pmac_screamer_mic_boost_beige);
+	else if (imac)
+		err = build_mixers(chip,
+				ARRAY_SIZE(snd_pmac_screamer_mic_boost_imac),
+				snd_pmac_screamer_mic_boost_imac);
+	else if (chip->model == PMAC_SCREAMER)
+		err = build_mixers(chip,
+				ARRAY_SIZE(snd_pmac_screamer_mic_boost),
+				snd_pmac_screamer_mic_boost);
+	else if (pm7500)
+		err = build_mixers(chip,
+				ARRAY_SIZE(snd_pmac_awacs_mic_boost_pmac7500),
+				snd_pmac_awacs_mic_boost_pmac7500);
+	else
+		err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mic_boost),
+				snd_pmac_awacs_mic_boost);
+	if (err < 0)
+		return err;
 
 	/*
 	 * set lowlevel callbacks
@@ -917,7 +1043,8 @@
 	chip->resume = snd_pmac_awacs_resume;
 #endif
 #ifdef PMAC_SUPPORT_AUTOMUTE
-	if ((err = snd_pmac_add_automute(chip)) < 0)
+	err = snd_pmac_add_automute(chip);
+	if (err < 0)
 		return err;
 	chip->detect_headphone = snd_pmac_awacs_detect_headphone;
 	chip->update_automute = snd_pmac_awacs_update_automute;
diff --git a/sound/ppc/awacs.h b/sound/ppc/awacs.h
index 1b2cc44..c33e6a5 100644
--- a/sound/ppc/awacs.h
+++ b/sound/ppc/awacs.h
@@ -116,6 +116,11 @@
 #define MASK_HDMUTE	MASK_AMUTE
 #define SHIFT_HDMUTE	9
 #define MASK_PAROUT	(0x3 << 10)	/* Parallel Out (???) */
+#define MASK_PAROUT0	(0x1 << 10)	/* Parallel Out (???) */
+#define MASK_PAROUT1	(0x1 << 11)	/* Parallel Out (enable speaker) */
+#define SHIFT_PAROUT	10
+#define SHIFT_PAROUT0	10
+#define SHIFT_PAROUT1	11
 
 #define SAMPLERATE_48000	(0x0 << 3)	/* 48 or 44.1 kHz */
 #define SAMPLERATE_32000	(0x1 << 3)	/* 32 or 29.4 kHz */
@@ -139,7 +144,7 @@
 #define VOLLEFT(x)	(((~(x)) << 6) & MASK_OUTVOLLEFT)
 
 /* address 6 */
-#define MASK_MIC_BOOST  (0x4)           /* screamer mic boost */
+#define MASK_MIC_BOOST  (0x4)		/* screamer mic boost */
 #define SHIFT_MIC_BOOST	2
 
 /* Audio Codec Status Reg Bit Masks */
@@ -152,8 +157,15 @@
 #define MASK_REVISION	(0xf << 12)	/* Revision Number */
 #define MASK_MFGID	(0xf << 8)	/* Mfg. ID */
 #define MASK_CODSTATRES	(0xf << 4)	/* bits 4 - 7 reserved */
-#define MASK_INPPORT	(0xf)		/* Input Port */
-#define MASK_HDPCONN	8		/* headphone plugged in */
+#define MASK_INSENSE	(0xf)		/* port sense bits: */
+#define MASK_HDPCONN		8	/* headphone plugged in */
+#define MASK_LOCONN		4	/* line-out plugged in */
+#define MASK_LICONN		2	/* line-in plugged in */
+#define MASK_MICCONN		1	/* microphone plugged in */
+#define MASK_LICONN_IMAC	8	/* line-in plugged in */
+#define MASK_HDPRCONN_IMAC	4	/* headphone right plugged in */
+#define MASK_HDPLCONN_IMAC	2	/* headphone left plugged in */
+#define MASK_LOCONN_IMAC	1	/* line-out plugged in */
 
 /* Clipping Count Reg Bit Masks */
 /* -------- ----- --- --- ----- */
@@ -163,7 +175,8 @@
 /* DBDMA ChannelStatus Bit Masks */
 /* ----- ------------- --- ----- */
 #define MASK_CSERR	(0x1 << 7)	/* Error */
-#define MASK_EOI	(0x1 << 6)	/* End of Input -- only for Input Channel */
+#define MASK_EOI	(0x1 << 6)	/* End of Input --
+					   only for Input Channel */
 #define MASK_CSUNUSED	(0x1f << 1)	/* bits 1-5 not used */
 #define MASK_WAIT	(0x1)		/* Wait */
 
diff --git a/sound/ppc/burgundy.c b/sound/ppc/burgundy.c
index 1a545ac..f860d39 100644
--- a/sound/ppc/burgundy.c
+++ b/sound/ppc/burgundy.c
@@ -102,7 +102,8 @@
 }
 
 static void
-snd_pmac_burgundy_wcb(struct snd_pmac *chip, unsigned int addr, unsigned int val)
+snd_pmac_burgundy_wcb(struct snd_pmac *chip, unsigned int addr,
+		      unsigned int val)
 {
 	out_le32(&chip->awacs->codec_ctrl, addr + 0x300000 + (val & 0xff));
 	snd_pmac_burgundy_busy_wait(chip);
@@ -126,8 +127,11 @@
 	return val;
 }
 
+#define BASE2ADDR(base)	((base) << 12)
+#define ADDR2BASE(addr)	((addr) >> 12)
+
 /*
- * Burgundy volume: 0 - 100, stereo
+ * Burgundy volume: 0 - 100, stereo, word reg
  */
 static void
 snd_pmac_burgundy_write_volume(struct snd_pmac *chip, unsigned int address,
@@ -168,13 +172,6 @@
 		volume[1] = 0;
 }
 
-
-/*
- */
-
-#define BASE2ADDR(base)	((base) << 12)
-#define ADDR2BASE(addr)	((addr) >> 12)
-
 static int snd_pmac_burgundy_info_volume(struct snd_kcontrol *kcontrol,
 					 struct snd_ctl_elem_info *uinfo)
 {
@@ -191,8 +188,8 @@
 	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
 	unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
 	int shift = (kcontrol->private_value >> 8) & 0xff;
-	snd_pmac_burgundy_read_volume(chip, addr, ucontrol->value.integer.value,
-				      shift);
+	snd_pmac_burgundy_read_volume(chip, addr,
+				      ucontrol->value.integer.value, shift);
 	return 0;
 }
 
@@ -204,75 +201,101 @@
 	int shift = (kcontrol->private_value >> 8) & 0xff;
 	long nvoices[2];
 
-	snd_pmac_burgundy_write_volume(chip, addr, ucontrol->value.integer.value,
-				       shift);
+	snd_pmac_burgundy_write_volume(chip, addr,
+				       ucontrol->value.integer.value, shift);
 	snd_pmac_burgundy_read_volume(chip, addr, nvoices, shift);
 	return (nvoices[0] != ucontrol->value.integer.value[0] ||
 		nvoices[1] != ucontrol->value.integer.value[1]);
 }
 
-#define BURGUNDY_VOLUME(xname, xindex, addr, shift) \
+#define BURGUNDY_VOLUME_W(xname, xindex, addr, shift) \
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
   .info = snd_pmac_burgundy_info_volume,\
   .get = snd_pmac_burgundy_get_volume,\
   .put = snd_pmac_burgundy_put_volume,\
   .private_value = ((ADDR2BASE(addr) & 0xff) | ((shift) << 8)) }
 
-/* lineout/speaker */
-
-static int snd_pmac_burgundy_info_switch_out(struct snd_kcontrol *kcontrol,
-					     struct snd_ctl_elem_info *uinfo)
+/*
+ * Burgundy volume: 0 - 100, stereo, 2-byte reg
+ */
+static void
+snd_pmac_burgundy_write_volume_2b(struct snd_pmac *chip, unsigned int address,
+				  long *volume, int off)
 {
-	int stereo = (kcontrol->private_value >> 24) & 1;
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-	uinfo->count = stereo + 1;
+	int lvolume, rvolume;
+
+	off |= off << 2;
+	lvolume = volume[0] ? volume[0] + BURGUNDY_VOLUME_OFFSET : 0;
+	rvolume = volume[1] ? volume[1] + BURGUNDY_VOLUME_OFFSET : 0;
+
+	snd_pmac_burgundy_wcb(chip, address + off, lvolume);
+	snd_pmac_burgundy_wcb(chip, address + off + 0x500, rvolume);
+}
+
+static void
+snd_pmac_burgundy_read_volume_2b(struct snd_pmac *chip, unsigned int address,
+				 long *volume, int off)
+{
+	volume[0] = snd_pmac_burgundy_rcb(chip, address + off);
+	if (volume[0] >= BURGUNDY_VOLUME_OFFSET)
+		volume[0] -= BURGUNDY_VOLUME_OFFSET;
+	else
+		volume[0] = 0;
+	volume[1] = snd_pmac_burgundy_rcb(chip, address + off + 0x100);
+	if (volume[1] >= BURGUNDY_VOLUME_OFFSET)
+		volume[1] -= BURGUNDY_VOLUME_OFFSET;
+	else
+		volume[1] = 0;
+}
+
+static int snd_pmac_burgundy_info_volume_2b(struct snd_kcontrol *kcontrol,
+					    struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
 	uinfo->value.integer.min = 0;
-	uinfo->value.integer.max = 1;
+	uinfo->value.integer.max = 100;
 	return 0;
 }
 
-static int snd_pmac_burgundy_get_switch_out(struct snd_kcontrol *kcontrol,
-					    struct snd_ctl_elem_value *ucontrol)
+static int snd_pmac_burgundy_get_volume_2b(struct snd_kcontrol *kcontrol,
+					   struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
-	int lmask = kcontrol->private_value & 0xff;
-	int rmask = (kcontrol->private_value >> 8) & 0xff;
-	int stereo = (kcontrol->private_value >> 24) & 1;
-	int val = snd_pmac_burgundy_rcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES);
-	ucontrol->value.integer.value[0] = (val & lmask) ? 1 : 0;
-	if (stereo)
-		ucontrol->value.integer.value[1] = (val & rmask) ? 1 : 0;
+	unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
+	int off = kcontrol->private_value & 0x300;
+	snd_pmac_burgundy_read_volume_2b(chip, addr,
+			ucontrol->value.integer.value, off);
 	return 0;
 }
 
-static int snd_pmac_burgundy_put_switch_out(struct snd_kcontrol *kcontrol,
-					    struct snd_ctl_elem_value *ucontrol)
+static int snd_pmac_burgundy_put_volume_2b(struct snd_kcontrol *kcontrol,
+					   struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
-	int lmask = kcontrol->private_value & 0xff;
-	int rmask = (kcontrol->private_value >> 8) & 0xff;
-	int stereo = (kcontrol->private_value >> 24) & 1;
-	int val, oval;
-	oval = snd_pmac_burgundy_rcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES);
-	val = oval & ~(lmask | rmask);
-	if (ucontrol->value.integer.value[0])
-		val |= lmask;
-	if (stereo && ucontrol->value.integer.value[1])
-		val |= rmask;
-	snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, val);
-	return val != oval;
+	unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
+	int off = kcontrol->private_value & 0x300;
+	long nvoices[2];
+
+	snd_pmac_burgundy_write_volume_2b(chip, addr,
+			ucontrol->value.integer.value, off);
+	snd_pmac_burgundy_read_volume_2b(chip, addr, nvoices, off);
+	return (nvoices[0] != ucontrol->value.integer.value[0] ||
+		nvoices[1] != ucontrol->value.integer.value[1]);
 }
 
-#define BURGUNDY_OUTPUT_SWITCH(xname, xindex, lmask, rmask, stereo) \
+#define BURGUNDY_VOLUME_2B(xname, xindex, addr, off) \
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
-  .info = snd_pmac_burgundy_info_switch_out,\
-  .get = snd_pmac_burgundy_get_switch_out,\
-  .put = snd_pmac_burgundy_put_switch_out,\
-  .private_value = ((lmask) | ((rmask) << 8) | ((stereo) << 24)) }
+  .info = snd_pmac_burgundy_info_volume_2b,\
+  .get = snd_pmac_burgundy_get_volume_2b,\
+  .put = snd_pmac_burgundy_put_volume_2b,\
+  .private_value = ((ADDR2BASE(addr) & 0xff) | ((off) << 8)) }
 
-/* line/speaker output volume */
-static int snd_pmac_burgundy_info_volume_out(struct snd_kcontrol *kcontrol,
-					     struct snd_ctl_elem_info *uinfo)
+/*
+ * Burgundy gain/attenuation: 0 - 15, mono/stereo, byte reg
+ */
+static int snd_pmac_burgundy_info_gain(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_info *uinfo)
 {
 	int stereo = (kcontrol->private_value >> 24) & 1;
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
@@ -282,60 +305,269 @@
 	return 0;
 }
 
-static int snd_pmac_burgundy_get_volume_out(struct snd_kcontrol *kcontrol,
-					    struct snd_ctl_elem_value *ucontrol)
+static int snd_pmac_burgundy_get_gain(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
 	unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
 	int stereo = (kcontrol->private_value >> 24) & 1;
+	int atten = (kcontrol->private_value >> 25) & 1;
 	int oval;
 
-	oval = ~snd_pmac_burgundy_rcb(chip, addr) & 0xff;
+	oval = snd_pmac_burgundy_rcb(chip, addr);
+	if (atten)
+		oval = ~oval & 0xff;
 	ucontrol->value.integer.value[0] = oval & 0xf;
 	if (stereo)
 		ucontrol->value.integer.value[1] = (oval >> 4) & 0xf;
 	return 0;
 }
 
-static int snd_pmac_burgundy_put_volume_out(struct snd_kcontrol *kcontrol,
-					    struct snd_ctl_elem_value *ucontrol)
+static int snd_pmac_burgundy_put_gain(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
 	unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
 	int stereo = (kcontrol->private_value >> 24) & 1;
-	unsigned int oval, val;
+	int atten = (kcontrol->private_value >> 25) & 1;
+	int oval, val;
 
-	oval = ~snd_pmac_burgundy_rcb(chip, addr) & 0xff;
-	val = ucontrol->value.integer.value[0] & 15;
+	oval = snd_pmac_burgundy_rcb(chip, addr);
+	if (atten)
+		oval = ~oval & 0xff;
+	val = ucontrol->value.integer.value[0];
 	if (stereo)
-		val |= (ucontrol->value.integer.value[1] & 15) << 4;
+		val |= ucontrol->value.integer.value[1] << 4;
 	else
-		val |= val << 4;
-	val = ~val & 0xff;
+		val |= ucontrol->value.integer.value[0] << 4;
+	if (atten)
+		val = ~val & 0xff;
 	snd_pmac_burgundy_wcb(chip, addr, val);
 	return val != oval;
 }
 
-#define BURGUNDY_OUTPUT_VOLUME(xname, xindex, addr, stereo) \
+#define BURGUNDY_VOLUME_B(xname, xindex, addr, stereo, atten) \
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
-  .info = snd_pmac_burgundy_info_volume_out,\
-  .get = snd_pmac_burgundy_get_volume_out,\
-  .put = snd_pmac_burgundy_put_volume_out,\
-  .private_value = (ADDR2BASE(addr) | ((stereo) << 24)) }
+  .info = snd_pmac_burgundy_info_gain,\
+  .get = snd_pmac_burgundy_get_gain,\
+  .put = snd_pmac_burgundy_put_gain,\
+  .private_value = (ADDR2BASE(addr) | ((stereo) << 24) | ((atten) << 25)) }
 
+/*
+ * Burgundy switch: 0/1, mono/stereo, word reg
+ */
+static int snd_pmac_burgundy_info_switch_w(struct snd_kcontrol *kcontrol,
+					   struct snd_ctl_elem_info *uinfo)
+{
+	int stereo = (kcontrol->private_value >> 24) & 1;
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = stereo + 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int snd_pmac_burgundy_get_switch_w(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
+	unsigned int addr = BASE2ADDR((kcontrol->private_value >> 16) & 0xff);
+	int lmask = 1 << (kcontrol->private_value & 0xff);
+	int rmask = 1 << ((kcontrol->private_value >> 8) & 0xff);
+	int stereo = (kcontrol->private_value >> 24) & 1;
+	int val = snd_pmac_burgundy_rcw(chip, addr);
+	ucontrol->value.integer.value[0] = (val & lmask) ? 1 : 0;
+	if (stereo)
+		ucontrol->value.integer.value[1] = (val & rmask) ? 1 : 0;
+	return 0;
+}
+
+static int snd_pmac_burgundy_put_switch_w(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
+	unsigned int addr = BASE2ADDR((kcontrol->private_value >> 16) & 0xff);
+	int lmask = 1 << (kcontrol->private_value & 0xff);
+	int rmask = 1 << ((kcontrol->private_value >> 8) & 0xff);
+	int stereo = (kcontrol->private_value >> 24) & 1;
+	int val, oval;
+	oval = snd_pmac_burgundy_rcw(chip, addr);
+	val = oval & ~(lmask | (stereo ? rmask : 0));
+	if (ucontrol->value.integer.value[0])
+		val |= lmask;
+	if (stereo && ucontrol->value.integer.value[1])
+		val |= rmask;
+	snd_pmac_burgundy_wcw(chip, addr, val);
+	return val != oval;
+}
+
+#define BURGUNDY_SWITCH_W(xname, xindex, addr, lbit, rbit, stereo) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
+  .info = snd_pmac_burgundy_info_switch_w,\
+  .get = snd_pmac_burgundy_get_switch_w,\
+  .put = snd_pmac_burgundy_put_switch_w,\
+  .private_value = ((lbit) | ((rbit) << 8)\
+		| (ADDR2BASE(addr) << 16) | ((stereo) << 24)) }
+
+/*
+ * Burgundy switch: 0/1, mono/stereo, byte reg, bit mask
+ */
+static int snd_pmac_burgundy_info_switch_b(struct snd_kcontrol *kcontrol,
+					   struct snd_ctl_elem_info *uinfo)
+{
+	int stereo = (kcontrol->private_value >> 24) & 1;
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = stereo + 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int snd_pmac_burgundy_get_switch_b(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
+	unsigned int addr = BASE2ADDR((kcontrol->private_value >> 16) & 0xff);
+	int lmask = kcontrol->private_value & 0xff;
+	int rmask = (kcontrol->private_value >> 8) & 0xff;
+	int stereo = (kcontrol->private_value >> 24) & 1;
+	int val = snd_pmac_burgundy_rcb(chip, addr);
+	ucontrol->value.integer.value[0] = (val & lmask) ? 1 : 0;
+	if (stereo)
+		ucontrol->value.integer.value[1] = (val & rmask) ? 1 : 0;
+	return 0;
+}
+
+static int snd_pmac_burgundy_put_switch_b(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
+	unsigned int addr = BASE2ADDR((kcontrol->private_value >> 16) & 0xff);
+	int lmask = kcontrol->private_value & 0xff;
+	int rmask = (kcontrol->private_value >> 8) & 0xff;
+	int stereo = (kcontrol->private_value >> 24) & 1;
+	int val, oval;
+	oval = snd_pmac_burgundy_rcb(chip, addr);
+	val = oval & ~(lmask | rmask);
+	if (ucontrol->value.integer.value[0])
+		val |= lmask;
+	if (stereo && ucontrol->value.integer.value[1])
+		val |= rmask;
+	snd_pmac_burgundy_wcb(chip, addr, val);
+	return val != oval;
+}
+
+#define BURGUNDY_SWITCH_B(xname, xindex, addr, lmask, rmask, stereo) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
+  .info = snd_pmac_burgundy_info_switch_b,\
+  .get = snd_pmac_burgundy_get_switch_b,\
+  .put = snd_pmac_burgundy_put_switch_b,\
+  .private_value = ((lmask) | ((rmask) << 8)\
+		| (ADDR2BASE(addr) << 16) | ((stereo) << 24)) }
+
+/*
+ * Burgundy mixers
+ */
 static struct snd_kcontrol_new snd_pmac_burgundy_mixers[] __initdata = {
-	BURGUNDY_VOLUME("Master Playback Volume", 0, MASK_ADDR_BURGUNDY_MASTER_VOLUME, 8),
-	BURGUNDY_VOLUME("Line Playback Volume", 0, MASK_ADDR_BURGUNDY_VOLLINE, 16),
-	BURGUNDY_VOLUME("CD Playback Volume", 0, MASK_ADDR_BURGUNDY_VOLCD, 16),
-	BURGUNDY_VOLUME("Mic Playback Volume", 0, MASK_ADDR_BURGUNDY_VOLMIC, 16),
-	BURGUNDY_OUTPUT_VOLUME("PC Speaker Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENHP, 0),
-	/*BURGUNDY_OUTPUT_VOLUME("PCM Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENLINEOUT, 1),*/
-	BURGUNDY_OUTPUT_VOLUME("Headphone Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENSPEAKER, 1),
-};	
-static struct snd_kcontrol_new snd_pmac_burgundy_master_sw __initdata = 
-BURGUNDY_OUTPUT_SWITCH("Headphone Playback Switch", 0, BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1);
-static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw __initdata = 
-BURGUNDY_OUTPUT_SWITCH("PC Speaker Playback Switch", 0, BURGUNDY_OUTPUT_INTERN, 0, 0);
+	BURGUNDY_VOLUME_W("Master Playback Volume", 0,
+			MASK_ADDR_BURGUNDY_MASTER_VOLUME, 8),
+	BURGUNDY_VOLUME_W("CD Capture Volume", 0,
+			MASK_ADDR_BURGUNDY_VOLCD, 16),
+	BURGUNDY_VOLUME_2B("Input Capture Volume", 0,
+			MASK_ADDR_BURGUNDY_VOLMIX01, 2),
+	BURGUNDY_VOLUME_2B("Mixer Playback Volume", 0,
+			MASK_ADDR_BURGUNDY_VOLMIX23, 0),
+	BURGUNDY_VOLUME_B("CD Gain Capture Volume", 0,
+			MASK_ADDR_BURGUNDY_GAINCD, 1, 0),
+	BURGUNDY_SWITCH_W("Master Capture Switch", 0,
+			MASK_ADDR_BURGUNDY_OUTPUTENABLES, 24, 0, 0),
+	BURGUNDY_SWITCH_W("CD Capture Switch", 0,
+			MASK_ADDR_BURGUNDY_CAPTURESELECTS, 0, 16, 1),
+	BURGUNDY_SWITCH_W("CD Playback Switch", 0,
+			MASK_ADDR_BURGUNDY_OUTPUTSELECTS, 0, 16, 1),
+/*	BURGUNDY_SWITCH_W("Loop Capture Switch", 0,
+ *		MASK_ADDR_BURGUNDY_CAPTURESELECTS, 8, 24, 1),
+ *	BURGUNDY_SWITCH_B("Mixer out Capture Switch", 0,
+ *		MASK_ADDR_BURGUNDY_HOSTIFAD, 0x02, 0, 0),
+ *	BURGUNDY_SWITCH_B("Mixer Capture Switch", 0,
+ *		MASK_ADDR_BURGUNDY_HOSTIFAD, 0x01, 0, 0),
+ *	BURGUNDY_SWITCH_B("PCM out Capture Switch", 0,
+ *		MASK_ADDR_BURGUNDY_HOSTIFEH, 0x02, 0, 0),
+ */	BURGUNDY_SWITCH_B("PCM Capture Switch", 0,
+			MASK_ADDR_BURGUNDY_HOSTIFEH, 0x01, 0, 0)
+};
+static struct snd_kcontrol_new snd_pmac_burgundy_mixers_imac[] __initdata = {
+	BURGUNDY_VOLUME_W("Line in Capture Volume", 0,
+			MASK_ADDR_BURGUNDY_VOLLINE, 16),
+	BURGUNDY_VOLUME_W("Mic Capture Volume", 0,
+			MASK_ADDR_BURGUNDY_VOLMIC, 16),
+	BURGUNDY_VOLUME_B("Line in Gain Capture Volume", 0,
+			MASK_ADDR_BURGUNDY_GAINLINE, 1, 0),
+	BURGUNDY_VOLUME_B("Mic Gain Capture Volume", 0,
+			MASK_ADDR_BURGUNDY_GAINMIC, 1, 0),
+	BURGUNDY_VOLUME_B("PC Speaker Playback Volume", 0,
+			MASK_ADDR_BURGUNDY_ATTENSPEAKER, 1, 1),
+	BURGUNDY_VOLUME_B("Line out Playback Volume", 0,
+			MASK_ADDR_BURGUNDY_ATTENLINEOUT, 1, 1),
+	BURGUNDY_VOLUME_B("Headphone Playback Volume", 0,
+			MASK_ADDR_BURGUNDY_ATTENHP, 1, 1),
+	BURGUNDY_SWITCH_W("Line in Capture Switch", 0,
+			MASK_ADDR_BURGUNDY_CAPTURESELECTS, 1, 17, 1),
+	BURGUNDY_SWITCH_W("Mic Capture Switch", 0,
+			MASK_ADDR_BURGUNDY_CAPTURESELECTS, 2, 18, 1),
+	BURGUNDY_SWITCH_W("Line in Playback Switch", 0,
+			MASK_ADDR_BURGUNDY_OUTPUTSELECTS, 1, 17, 1),
+	BURGUNDY_SWITCH_W("Mic Playback Switch", 0,
+			MASK_ADDR_BURGUNDY_OUTPUTSELECTS, 2, 18, 1),
+	BURGUNDY_SWITCH_B("Mic Boost Capture Switch", 0,
+			MASK_ADDR_BURGUNDY_INPBOOST, 0x40, 0x80, 1)
+};
+static struct snd_kcontrol_new snd_pmac_burgundy_mixers_pmac[] __initdata = {
+	BURGUNDY_VOLUME_W("Line in Capture Volume", 0,
+			MASK_ADDR_BURGUNDY_VOLMIC, 16),
+	BURGUNDY_VOLUME_B("Line in Gain Capture Volume", 0,
+			MASK_ADDR_BURGUNDY_GAINMIC, 1, 0),
+	BURGUNDY_VOLUME_B("PC Speaker Playback Volume", 0,
+			MASK_ADDR_BURGUNDY_ATTENMONO, 0, 1),
+	BURGUNDY_VOLUME_B("Line out Playback Volume", 0,
+			MASK_ADDR_BURGUNDY_ATTENSPEAKER, 1, 1),
+	BURGUNDY_SWITCH_W("Line in Capture Switch", 0,
+			MASK_ADDR_BURGUNDY_CAPTURESELECTS, 2, 18, 1),
+	BURGUNDY_SWITCH_W("Line in Playback Switch", 0,
+			MASK_ADDR_BURGUNDY_OUTPUTSELECTS, 2, 18, 1),
+/*	BURGUNDY_SWITCH_B("Line in Boost Capture Switch", 0,
+ *		MASK_ADDR_BURGUNDY_INPBOOST, 0x40, 0x80, 1) */
+};
+static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_imac __initdata =
+BURGUNDY_SWITCH_B("Master Playback Switch", 0,
+	MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
+	BURGUNDY_OUTPUT_LEFT | BURGUNDY_LINEOUT_LEFT | BURGUNDY_HP_LEFT,
+	BURGUNDY_OUTPUT_RIGHT | BURGUNDY_LINEOUT_RIGHT | BURGUNDY_HP_RIGHT, 1);
+static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_pmac __initdata =
+BURGUNDY_SWITCH_B("Master Playback Switch", 0,
+	MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
+	BURGUNDY_OUTPUT_INTERN
+	| BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1);
+static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_imac __initdata =
+BURGUNDY_SWITCH_B("PC Speaker Playback Switch", 0,
+	MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
+	BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1);
+static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_pmac __initdata =
+BURGUNDY_SWITCH_B("PC Speaker Playback Switch", 0,
+	MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
+	BURGUNDY_OUTPUT_INTERN, 0, 0);
+static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_imac __initdata =
+BURGUNDY_SWITCH_B("Line out Playback Switch", 0,
+	MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
+	BURGUNDY_LINEOUT_LEFT, BURGUNDY_LINEOUT_RIGHT, 1);
+static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_pmac __initdata =
+BURGUNDY_SWITCH_B("Line out Playback Switch", 0,
+	MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
+	BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1);
+static struct snd_kcontrol_new snd_pmac_burgundy_hp_sw_imac __initdata =
+BURGUNDY_SWITCH_B("Headphone Playback Switch", 0,
+	MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
+	BURGUNDY_HP_LEFT, BURGUNDY_HP_RIGHT, 1);
 
 
 #ifdef PMAC_SUPPORT_AUTOMUTE
@@ -350,16 +582,26 @@
 static void snd_pmac_burgundy_update_automute(struct snd_pmac *chip, int do_notify)
 {
 	if (chip->auto_mute) {
+		int imac = machine_is_compatible("iMac");
 		int reg, oreg;
-		reg = oreg = snd_pmac_burgundy_rcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES);
-		reg &= ~(BURGUNDY_OUTPUT_LEFT | BURGUNDY_OUTPUT_RIGHT | BURGUNDY_OUTPUT_INTERN);
+		reg = oreg = snd_pmac_burgundy_rcb(chip,
+				MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES);
+		reg &= imac ? ~(BURGUNDY_OUTPUT_LEFT | BURGUNDY_OUTPUT_RIGHT
+				| BURGUNDY_HP_LEFT | BURGUNDY_HP_RIGHT)
+			: ~(BURGUNDY_OUTPUT_LEFT | BURGUNDY_OUTPUT_RIGHT
+				| BURGUNDY_OUTPUT_INTERN);
 		if (snd_pmac_burgundy_detect_headphone(chip))
-			reg |= BURGUNDY_OUTPUT_LEFT | BURGUNDY_OUTPUT_RIGHT;
+			reg |= imac ? (BURGUNDY_HP_LEFT | BURGUNDY_HP_RIGHT)
+				: (BURGUNDY_OUTPUT_LEFT
+					| BURGUNDY_OUTPUT_RIGHT);
 		else
-			reg |= BURGUNDY_OUTPUT_INTERN;
+			reg |= imac ? (BURGUNDY_OUTPUT_LEFT
+					| BURGUNDY_OUTPUT_RIGHT)
+				: (BURGUNDY_OUTPUT_INTERN);
 		if (do_notify && reg == oreg)
 			return;
-		snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, reg);
+		snd_pmac_burgundy_wcb(chip,
+				MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, reg);
 		if (do_notify) {
 			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
 				       &chip->master_sw_ctl->id);
@@ -378,6 +620,7 @@
  */
 int __init snd_pmac_burgundy_init(struct snd_pmac *chip)
 {
+	int imac = machine_is_compatible("iMac");
 	int i, err;
 
 	/* Checks to see the chip is alive and kicking */
@@ -386,7 +629,7 @@
 		return 1;
 	}
 
-	snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_OUTPUTENABLES,
+	snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_OUTPUTENABLES,
 			   DEF_BURGUNDY_OUTPUTENABLES);
 	snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
 			   DEF_BURGUNDY_MORE_OUTPUTENABLES);
@@ -396,7 +639,8 @@
 	snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_INPSEL21,
 			   DEF_BURGUNDY_INPSEL21);
 	snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_INPSEL3,
-			   DEF_BURGUNDY_INPSEL3);
+			   imac ? DEF_BURGUNDY_INPSEL3_IMAC
+			   : DEF_BURGUNDY_INPSEL3_PMAC);
 	snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_GAINCD,
 			   DEF_BURGUNDY_GAINCD);
 	snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_GAINLINE,
@@ -422,27 +666,62 @@
 	snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_VOLMIC,
 			   DEF_BURGUNDY_VOLMIC);
 
-	if (chip->hp_stat_mask == 0)
+	if (chip->hp_stat_mask == 0) {
 		/* set headphone-jack detection bit */
-		chip->hp_stat_mask = 0x04;
-
+		if (imac)
+			chip->hp_stat_mask = BURGUNDY_HPDETECT_IMAC_UPPER
+				| BURGUNDY_HPDETECT_IMAC_LOWER
+				| BURGUNDY_HPDETECT_IMAC_SIDE;
+		else
+			chip->hp_stat_mask = BURGUNDY_HPDETECT_PMAC_BACK;
+	}
 	/*
 	 * build burgundy mixers
 	 */
 	strcpy(chip->card->mixername, "PowerMac Burgundy");
 
 	for (i = 0; i < ARRAY_SIZE(snd_pmac_burgundy_mixers); i++) {
-		if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_pmac_burgundy_mixers[i], chip))) < 0)
+		err = snd_ctl_add(chip->card,
+		    snd_ctl_new1(&snd_pmac_burgundy_mixers[i], chip));
+		if (err < 0)
 			return err;
 	}
-	chip->master_sw_ctl = snd_ctl_new1(&snd_pmac_burgundy_master_sw, chip);
-	if ((err = snd_ctl_add(chip->card, chip->master_sw_ctl)) < 0)
+	for (i = 0; i < (imac ? ARRAY_SIZE(snd_pmac_burgundy_mixers_imac)
+			: ARRAY_SIZE(snd_pmac_burgundy_mixers_pmac)); i++) {
+		err = snd_ctl_add(chip->card,
+		    snd_ctl_new1(imac ? &snd_pmac_burgundy_mixers_imac[i]
+		    : &snd_pmac_burgundy_mixers_pmac[i], chip));
+		if (err < 0)
+			return err;
+	}
+	chip->master_sw_ctl = snd_ctl_new1(imac
+			? &snd_pmac_burgundy_master_sw_imac
+			: &snd_pmac_burgundy_master_sw_pmac, chip);
+	err = snd_ctl_add(chip->card, chip->master_sw_ctl);
+	if (err < 0)
 		return err;
-	chip->speaker_sw_ctl = snd_ctl_new1(&snd_pmac_burgundy_speaker_sw, chip);
-	if ((err = snd_ctl_add(chip->card, chip->speaker_sw_ctl)) < 0)
+	chip->master_sw_ctl = snd_ctl_new1(imac
+			? &snd_pmac_burgundy_line_sw_imac
+			: &snd_pmac_burgundy_line_sw_pmac, chip);
+	err = snd_ctl_add(chip->card, chip->master_sw_ctl);
+	if (err < 0)
+		return err;
+	if (imac) {
+		chip->master_sw_ctl = snd_ctl_new1(
+				&snd_pmac_burgundy_hp_sw_imac, chip);
+		err = snd_ctl_add(chip->card, chip->master_sw_ctl);
+		if (err < 0)
+			return err;
+	}
+	chip->speaker_sw_ctl = snd_ctl_new1(imac
+			? &snd_pmac_burgundy_speaker_sw_imac
+			: &snd_pmac_burgundy_speaker_sw_pmac, chip);
+	err = snd_ctl_add(chip->card, chip->speaker_sw_ctl);
+	if (err < 0)
 		return err;
 #ifdef PMAC_SUPPORT_AUTOMUTE
-	if ((err = snd_pmac_add_automute(chip)) < 0)
+	err = snd_pmac_add_automute(chip);
+	if (err < 0)
 		return err;
 
 	chip->detect_headphone = snd_pmac_burgundy_detect_headphone;
diff --git a/sound/ppc/burgundy.h b/sound/ppc/burgundy.h
index ebb457a..7a7f9cf 100644
--- a/sound/ppc/burgundy.h
+++ b/sound/ppc/burgundy.h
@@ -22,6 +22,7 @@
 #ifndef __BURGUNDY_H
 #define __BURGUNDY_H
 
+#define MASK_ADDR_BURGUNDY_INPBOOST (0x10 << 12)
 #define MASK_ADDR_BURGUNDY_INPSEL21 (0x11 << 12)
 #define MASK_ADDR_BURGUNDY_INPSEL3 (0x12 << 12)
 
@@ -35,7 +36,10 @@
 #define MASK_ADDR_BURGUNDY_VOLCH3 (0x22 << 12)
 #define MASK_ADDR_BURGUNDY_VOLCH4 (0x23 << 12)
 
+#define MASK_ADDR_BURGUNDY_CAPTURESELECTS (0x2A << 12)
 #define MASK_ADDR_BURGUNDY_OUTPUTSELECTS (0x2B << 12)
+#define MASK_ADDR_BURGUNDY_VOLMIX01 (0x2D << 12)
+#define MASK_ADDR_BURGUNDY_VOLMIX23 (0x2E << 12)
 #define MASK_ADDR_BURGUNDY_OUTPUTENABLES (0x2F << 12)
 
 #define MASK_ADDR_BURGUNDY_MASTER_VOLUME (0x30 << 12)
@@ -45,6 +49,10 @@
 #define MASK_ADDR_BURGUNDY_ATTENSPEAKER (0x62 << 12)
 #define MASK_ADDR_BURGUNDY_ATTENLINEOUT (0x63 << 12)
 #define MASK_ADDR_BURGUNDY_ATTENHP (0x64 << 12)
+#define MASK_ADDR_BURGUNDY_ATTENMONO (0x65 << 12)
+
+#define MASK_ADDR_BURGUNDY_HOSTIFAD (0x78 << 12)
+#define MASK_ADDR_BURGUNDY_HOSTIFEH (0x79 << 12)
 
 #define MASK_ADDR_BURGUNDY_VOLCD (MASK_ADDR_BURGUNDY_VOLCH1)
 #define MASK_ADDR_BURGUNDY_VOLLINE (MASK_ADDR_BURGUNDY_VOLCH2)
@@ -59,21 +67,22 @@
 
 /* These are all default values for the burgundy */
 #define DEF_BURGUNDY_INPSEL21 (0xAA)
-#define DEF_BURGUNDY_INPSEL3 (0x0A)
+#define DEF_BURGUNDY_INPSEL3_IMAC (0x0A)
+#define DEF_BURGUNDY_INPSEL3_PMAC (0x05)
 
 #define DEF_BURGUNDY_GAINCD (0x33)
 #define DEF_BURGUNDY_GAINLINE (0x44)
 #define DEF_BURGUNDY_GAINMIC (0x44)
 #define DEF_BURGUNDY_GAINMODEM (0x06)
 
-/* Remember: lowest volume here is 0x9b */
+/* Remember: lowest volume here is 0x9B (155) */
 #define DEF_BURGUNDY_VOLCD (0xCCCCCCCC)
 #define DEF_BURGUNDY_VOLLINE (0x00000000)
 #define DEF_BURGUNDY_VOLMIC (0x00000000)
 #define DEF_BURGUNDY_VOLMODEM (0xCCCCCCCC)
 
-#define DEF_BURGUNDY_OUTPUTSELECTS (0x010f010f)
-#define DEF_BURGUNDY_OUTPUTENABLES (0x0A)
+#define DEF_BURGUNDY_OUTPUTSELECTS (0x010F010F)
+#define DEF_BURGUNDY_OUTPUTENABLES (0x0100000A)
 
 /* #define DEF_BURGUNDY_MASTER_VOLUME (0xFFFFFFFF) */ /* too loud */
 #define DEF_BURGUNDY_MASTER_VOLUME (0xDDDDDDDD)
@@ -84,12 +93,22 @@
 #define DEF_BURGUNDY_ATTENLINEOUT (0xCC)
 #define DEF_BURGUNDY_ATTENHP (0xCC)
 
-/* OUTPUTENABLES bits */
+/* MORE_OUTPUTENABLES bits */
 #define BURGUNDY_OUTPUT_LEFT	0x02
 #define BURGUNDY_OUTPUT_RIGHT	0x04
+#define BURGUNDY_LINEOUT_LEFT	0x08
+#define BURGUNDY_LINEOUT_RIGHT	0x10
+#define BURGUNDY_HP_LEFT	0x20
+#define BURGUNDY_HP_RIGHT	0x40
 #define BURGUNDY_OUTPUT_INTERN	0x80
 
-/* volume offset */
+/* Headphone detection bits */
+#define BURGUNDY_HPDETECT_PMAC_BACK	0x04
+#define BURGUNDY_HPDETECT_IMAC_SIDE	0x04
+#define BURGUNDY_HPDETECT_IMAC_UPPER	0x08
+#define BURGUNDY_HPDETECT_IMAC_LOWER	0x01
+
+/* Volume offset */
 #define BURGUNDY_VOLUME_OFFSET	155
 
 #endif /* __BURGUNDY_H */
diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c
index 613a565..a38c0c7 100644
--- a/sound/ppc/pmac.c
+++ b/sound/ppc/pmac.c
@@ -214,7 +214,7 @@
 	int rate_index;
 	long offset;
 	struct pmac_stream *astr;
-	
+
 	rec->dma_size = snd_pcm_lib_buffer_bytes(subs);
 	rec->period_size = snd_pcm_lib_period_bytes(subs);
 	rec->nperiods = rec->dma_size / rec->period_size;
@@ -643,7 +643,7 @@
 	/* reset constraints */
 	astr->cur_freqs = chip->freqs_ok;
 	astr->cur_formats = chip->formats_ok;
-	
+
 	return 0;
 }
 
@@ -1300,9 +1300,9 @@
 
 	snd_pmac_sound_feature(chip, 1);
 
-	/* reset */
-	if (chip->model == PMAC_AWACS)
-		out_le32(&chip->awacs->control, 0x11);
+	/* reset & enable interrupts */
+	if (chip->model <= PMAC_BURGUNDY)
+		out_le32(&chip->awacs->control, chip->control_mask);
 
 	/* Powerbooks have odd ways of enabling inputs such as
 	   an expansion-bay CD or sound from an internal modem
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 2765852..a3b51df 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -29,6 +29,7 @@
 source "sound/soc/s3c24xx/Kconfig"
 source "sound/soc/sh/Kconfig"
 source "sound/soc/fsl/Kconfig"
+source "sound/soc/davinci/Kconfig"
 
 # Supported codecs
 source "sound/soc/codecs/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 4869c9a..e489dbd 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -1,4 +1,4 @@
 snd-soc-core-objs := soc-core.o soc-dapm.o
 
 obj-$(CONFIG_SND_SOC)	+= snd-soc-core.o
-obj-$(CONFIG_SND_SOC)	+= codecs/ at91/ pxa/ s3c24xx/ sh/ fsl/
+obj-$(CONFIG_SND_SOC)	+= codecs/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 898a7d3..3903ab7 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -18,6 +18,10 @@
 	tristate
 	depends on SND_SOC
 
+config SND_SOC_WM9713
+	tristate
+	depends on SND_SOC
+
 # Cirrus Logic CS4270 Codec
 config SND_SOC_CS4270
 	tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index c6e5338..4e1314c 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -3,6 +3,7 @@
 snd-soc-wm8750-objs := wm8750.o
 snd-soc-wm8753-objs := wm8753.o
 snd-soc-wm9712-objs := wm9712.o
+snd-soc-wm9713-objs := wm9713.o
 snd-soc-cs4270-objs := cs4270.o
 snd-soc-tlv320aic3x-objs := tlv320aic3x.o
 
@@ -11,5 +12,6 @@
 obj-$(CONFIG_SND_SOC_WM8750)	+= snd-soc-wm8750.o
 obj-$(CONFIG_SND_SOC_WM8753)	+= snd-soc-wm8753.o
 obj-$(CONFIG_SND_SOC_WM9712)	+= snd-soc-wm9712.o
+obj-$(CONFIG_SND_SOC_WM9713)	+= snd-soc-wm9713.o
 obj-$(CONFIG_SND_SOC_CS4270)	+= snd-soc-cs4270.o
 obj-$(CONFIG_SND_SOC_TLV320AIC3X)	+= snd-soc-tlv320aic3x.o
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
index 242130c..2a1ffe3 100644
--- a/sound/soc/codecs/ac97.c
+++ b/sound/soc/codecs/ac97.c
@@ -40,7 +40,8 @@
 }
 
 #define STD_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
-		SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+		SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\
+		SNDRV_PCM_RATE_48000)
 
 struct snd_soc_codec_dai ac97_dai = {
 	.name = "AC97 HiFi",
@@ -86,7 +87,7 @@
 	printk(KERN_INFO "AC97 SoC Audio Codec %s\n", AC97_VERSION);
 
 	socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-	if (socdev->codec == NULL)
+	if (!socdev->codec)
 		return -ENOMEM;
 	codec = socdev->codec;
 	mutex_init(&codec->mutex);
@@ -102,17 +103,17 @@
 
 	/* register pcms */
 	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-	if(ret < 0)
+	if (ret < 0)
 		goto err;
 
 	/* add codec as bus device for standard ac97 */
 	ret = snd_ac97_bus(codec->card, 0, &soc_ac97_ops, NULL, &ac97_bus);
-	if(ret < 0)
+	if (ret < 0)
 		goto bus_err;
 
 	memset(&ac97_template, 0, sizeof(struct snd_ac97_template));
 	ret = snd_ac97_mixer(ac97_bus, &ac97_template, &codec->ac97);
-	if(ret < 0)
+	if (ret < 0)
 		goto bus_err;
 
 	ret = snd_soc_register_card(socdev);
@@ -135,7 +136,7 @@
 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 	struct snd_soc_codec *codec = socdev->codec;
 
-	if(codec == NULL)
+	if (!codec)
 		return 0;
 
 	snd_soc_free_pcms(socdev);
@@ -145,11 +146,10 @@
 	return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_ac97= {
+struct snd_soc_codec_device soc_codec_dev_ac97 = {
 	.probe = 	ac97_soc_probe,
 	.remove = 	ac97_soc_remove,
 };
-
 EXPORT_SYMBOL_GPL(soc_codec_dev_ac97);
 
 MODULE_DESCRIPTION("Soc Generic AC97 driver");
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index bf2ab72..e73fcfd 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -372,7 +372,7 @@
 	struct snd_soc_device *socdev = rtd->socdev;
 	struct snd_soc_codec *codec = socdev->codec;
 	struct cs4270_private *cs4270 = codec->private_data;
-	unsigned int ret = 0;
+	int ret;
 	unsigned int i;
 	unsigned int rate;
 	unsigned int ratio;
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 889a897..630684f 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -660,33 +660,53 @@
 /* AIC3X codec mclk clock divider coefficients */
 static const struct aic3x_rate_divs aic3x_divs[] = {
 	/* 8k */
+	{12000000, 8000, 48000, 0xa, 16, 3840},
+	{19200000, 8000, 48000, 0xa, 10, 2400},
 	{22579200, 8000, 48000, 0xa, 8, 7075},
 	{33868800, 8000, 48000, 0xa, 5, 8049},
 	/* 11.025k */
+	{12000000, 11025, 44100, 0x6, 15, 528},
+	{19200000, 11025, 44100, 0x6, 9, 4080},
 	{22579200, 11025, 44100, 0x6, 8, 0},
 	{33868800, 11025, 44100, 0x6, 5, 3333},
 	/* 16k */
+	{12000000, 16000, 48000, 0x4, 16, 3840},
+	{19200000, 16000, 48000, 0x4, 10, 2400},
 	{22579200, 16000, 48000, 0x4, 8, 7075},
 	{33868800, 16000, 48000, 0x4, 5, 8049},
 	/* 22.05k */
+	{12000000, 22050, 44100, 0x2, 15, 528},
+	{19200000, 22050, 44100, 0x2, 9, 4080},
 	{22579200, 22050, 44100, 0x2, 8, 0},
 	{33868800, 22050, 44100, 0x2, 5, 3333},
 	/* 32k */
+	{12000000, 32000, 48000, 0x1, 16, 3840},
+	{19200000, 32000, 48000, 0x1, 10, 2400},
 	{22579200, 32000, 48000, 0x1, 8, 7075},
 	{33868800, 32000, 48000, 0x1, 5, 8049},
 	/* 44.1k */
+	{12000000, 44100, 44100, 0x0, 15, 528},
+	{19200000, 44100, 44100, 0x0, 9, 4080},
 	{22579200, 44100, 44100, 0x0, 8, 0},
 	{33868800, 44100, 44100, 0x0, 5, 3333},
 	/* 48k */
+	{12000000, 48000, 48000, 0x0, 16, 3840},
+	{19200000, 48000, 48000, 0x0, 10, 2400},
 	{22579200, 48000, 48000, 0x0, 8, 7075},
 	{33868800, 48000, 48000, 0x0, 5, 8049},
 	/* 64k */
+	{12000000, 64000, 96000, 0x1, 16, 3840},
+	{19200000, 64000, 96000, 0x1, 10, 2400},
 	{22579200, 64000, 96000, 0x1, 8, 7075},
 	{33868800, 64000, 96000, 0x1, 5, 8049},
 	/* 88.2k */
+	{12000000, 88200, 88200, 0x0, 15, 528},
+	{19200000, 88200, 88200, 0x0, 9, 4080},
 	{22579200, 88200, 88200, 0x0, 8, 0},
 	{33868800, 88200, 88200, 0x0, 5, 3333},
 	/* 96k */
+	{12000000, 96000, 96000, 0x0, 16, 3840},
+	{19200000, 96000, 96000, 0x0, 10, 2400},
 	{22579200, 96000, 96000, 0x0, 8, 7075},
 	{33868800, 96000, 96000, 0x0, 5, 8049},
 };
@@ -807,6 +827,8 @@
 	struct aic3x_priv *aic3x = codec->private_data;
 
 	switch (freq) {
+	case 12000000:
+	case 19200000:
 	case 22579200:
 	case 33868800:
 		aic3x->sysclk = freq;
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 9c33fe8..0cf9265 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -110,7 +110,7 @@
 	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
 	data[1] = value & 0x00ff;
 
-	wm8731_write_reg_cache (codec, reg, value);
+	wm8731_write_reg_cache(codec, reg, value);
 	if (codec->hw_write(codec->control_data, data, 2) == 2)
 		return 0;
 	else
@@ -154,8 +154,10 @@
 	int err, i;
 
 	for (i = 0; i < ARRAY_SIZE(wm8731_snd_controls); i++) {
-		if ((err = snd_ctl_add(codec->card,
-				snd_soc_cnew(&wm8731_snd_controls[i],codec, NULL))) < 0)
+		err = snd_ctl_add(codec->card,
+				  snd_soc_cnew(&wm8731_snd_controls[i],
+						codec, NULL));
+		if (err < 0)
 			return err;
 	}
 
@@ -221,15 +223,13 @@
 {
 	int i;
 
-	for(i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++) {
+	for (i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++)
 		snd_soc_dapm_new_control(codec, &wm8731_dapm_widgets[i]);
-	}
 
 	/* set up audio path interconnects */
-	for(i = 0; intercon[i][0] != NULL; i++) {
+	for (i = 0; intercon[i][0] != NULL; i++)
 		snd_soc_dapm_connect_input(codec, intercon[i][0],
 			intercon[i][1], intercon[i][2]);
-	}
 
 	snd_soc_dapm_new_widgets(codec);
 	return 0;
@@ -589,7 +589,7 @@
 
 static struct snd_soc_device *wm8731_socdev;
 
-#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 
 /*
  * WM8731 2 wire address is determined by GPIO5
@@ -651,7 +651,7 @@
 
 static int wm8731_i2c_detach(struct i2c_client *client)
 {
-	struct snd_soc_codec* codec = i2c_get_clientdata(client);
+	struct snd_soc_codec *codec = i2c_get_clientdata(client);
 	i2c_detach_client(client);
 	kfree(codec->reg_cache);
 	kfree(client);
@@ -709,7 +709,7 @@
 	INIT_LIST_HEAD(&codec->dapm_paths);
 
 	wm8731_socdev = socdev;
-#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	if (setup->i2c_address) {
 		normal_i2c[0] = setup->i2c_address;
 		codec->hw_write = (hw_write_t)i2c_master_send;
@@ -734,7 +734,7 @@
 
 	snd_soc_free_pcms(socdev);
 	snd_soc_dapm_free(socdev);
-#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	i2c_del_driver(&wm8731_i2c_driver);
 #endif
 	kfree(codec->private_data);
@@ -749,7 +749,6 @@
 	.suspend = 	wm8731_suspend,
 	.resume =	wm8731_resume,
 };
-
 EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731);
 
 MODULE_DESCRIPTION("ASoC WM8731 driver");
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index 77a857b..16cd5d4 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -110,7 +110,7 @@
 	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
 	data[1] = value & 0x00ff;
 
-	wm8750_write_reg_cache (codec, reg, value);
+	wm8750_write_reg_cache(codec, reg, value);
 	if (codec->hw_write(codec->control_data, data, 2) == 2)
 		return 0;
 	else
@@ -257,7 +257,8 @@
 
 	for (i = 0; i < ARRAY_SIZE(wm8750_snd_controls); i++) {
 		err = snd_ctl_add(codec->card,
-				snd_soc_cnew(&wm8750_snd_controls[i],codec, NULL));
+				snd_soc_cnew(&wm8750_snd_controls[i],
+						codec, NULL));
 		if (err < 0)
 			return err;
 	}
@@ -478,15 +479,13 @@
 {
 	int i;
 
-	for(i = 0; i < ARRAY_SIZE(wm8750_dapm_widgets); i++) {
+	for (i = 0; i < ARRAY_SIZE(wm8750_dapm_widgets); i++)
 		snd_soc_dapm_new_control(codec, &wm8750_dapm_widgets[i]);
-	}
 
 	/* set up audio path audio_mapnects */
-	for(i = 0; audio_map[i][0] != NULL; i++) {
+	for (i = 0; audio_map[i][0] != NULL; i++)
 		snd_soc_dapm_connect_input(codec, audio_map[i][0],
 			audio_map[i][1], audio_map[i][2]);
-	}
 
 	snd_soc_dapm_new_widgets(codec);
 	return 0;
@@ -714,8 +713,8 @@
 }
 
 #define WM8750_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
-		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
-		SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+	SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
+	SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
 
 #define WM8750_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 	SNDRV_PCM_FMTBIT_S24_LE)
@@ -784,7 +783,8 @@
 	if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) {
 		wm8750_dapm_event(codec, SNDRV_CTL_POWER_D2);
 		codec->dapm_state = SNDRV_CTL_POWER_D0;
-		schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000));
+		schedule_delayed_work(&codec->delayed_work,
+					msecs_to_jiffies(1000));
 	}
 
 	return 0;
@@ -864,7 +864,7 @@
    around */
 static struct snd_soc_device *wm8750_socdev;
 
-#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 
 /*
  * WM8731 2 wire address is determined by GPIO5
@@ -979,8 +979,8 @@
 	INIT_LIST_HEAD(&codec->dapm_paths);
 	wm8750_socdev = socdev;
 	INIT_DELAYED_WORK(&codec->delayed_work, wm8750_work);
-	
-#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	if (setup->i2c_address) {
 		normal_i2c[0] = setup->i2c_address;
 		codec->hw_write = (hw_write_t)i2c_master_send;
@@ -1025,7 +1025,7 @@
 	run_delayed_work(&codec->delayed_work);
 	snd_soc_free_pcms(socdev);
 	snd_soc_dapm_free(socdev);
-#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	i2c_del_driver(&wm8750_i2c_driver);
 #endif
 	kfree(codec->private_data);
@@ -1040,7 +1040,6 @@
 	.suspend = 	wm8750_suspend,
 	.resume =	wm8750_resume,
 };
-
 EXPORT_SYMBOL_GPL(soc_codec_dev_wm8750);
 
 MODULE_DESCRIPTION("ASoC WM8750 driver");
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index ddd9c71..76a5c7b 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -198,6 +198,7 @@
 static const char *wm8753_dai_mode[] = {"DAI 0", "DAI 1", "DAI 2", "DAI 3"};
 static const char *wm8753_dat_sel[] = {"Stereo", "Left ADC", "Right ADC",
 	"Channel Swap"};
+static const char *wm8753_rout2_phase[] = {"Non Inverted", "Inverted"};
 
 static const struct soc_enum wm8753_enum[] = {
 SOC_ENUM_SINGLE(WM8753_BASS, 7, 2, wm8753_base),
@@ -228,6 +229,7 @@
 SOC_ENUM_SINGLE(WM8753_MICBIAS, 6, 3, wm8753_mic_sel),
 SOC_ENUM_SINGLE(WM8753_IOCTL, 2, 4, wm8753_dai_mode),
 SOC_ENUM_SINGLE(WM8753_ADC, 7, 4, wm8753_dat_sel),
+SOC_ENUM_SINGLE(WM8753_OUTCTL, 2, 2, wm8753_rout2_phase),
 };
 
 
@@ -279,7 +281,7 @@
 
 SOC_SINGLE("Mono Bypass Playback Volume", WM8753_MOUTM1, 4, 7, 1),
 SOC_SINGLE("Mono Sidetone Playback Volume", WM8753_MOUTM2, 4, 7, 1),
-SOC_SINGLE("Mono Voice Playback Volume", WM8753_MOUTM2, 4, 7, 1),
+SOC_SINGLE("Mono Voice Playback Volume", WM8753_MOUTM2, 0, 7, 1),
 SOC_SINGLE("Mono Playback ZC Switch", WM8753_MOUTV, 7, 1, 0),
 
 SOC_ENUM("Bass Boost", wm8753_enum[0]),
@@ -330,6 +332,7 @@
 SOC_ENUM_EXT("DAI Mode", wm8753_enum[26], wm8753_get_dai, wm8753_set_dai),
 
 SOC_ENUM("ADC Data Select", wm8753_enum[27]),
+SOC_ENUM("ROUT2 Phase", wm8753_enum[28]),
 };
 
 /* add non dapm controls */
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index 524f745..d2d79e1 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -581,22 +581,14 @@
 
 	switch (event) {
 	case SNDRV_CTL_POWER_D0: /* full On */
-		/* liam - maybe enable thermal shutdown */
-		reg = ac97_read(codec, AC97_EXTENDED_MID) & 0xdfff;
-		ac97_write(codec, AC97_EXTENDED_MID, reg);
-		break;
 	case SNDRV_CTL_POWER_D1: /* partial On */
 	case SNDRV_CTL_POWER_D2: /* partial On */
 		break;
 	case SNDRV_CTL_POWER_D3hot: /* Off, with power */
-		/* enable master bias and vmid */
-		reg = ac97_read(codec, AC97_EXTENDED_MID) & 0xbbff;
-		ac97_write(codec, AC97_EXTENDED_MID, reg);
 		ac97_write(codec, AC97_POWERDOWN, 0x0000);
 		break;
 	case SNDRV_CTL_POWER_D3cold: /* Off, without power */
 		/* disable everything including AC link */
-		ac97_write(codec, AC97_EXTENDED_MID, 0xffff);
 		ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff);
 		ac97_write(codec, AC97_POWERDOWN, 0xffff);
 		break;
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
new file mode 100644
index 0000000..1f24116
--- /dev/null
+++ b/sound/soc/codecs/wm9713.c
@@ -0,0 +1,1300 @@
+/*
+ * wm9713.c  --  ALSA Soc WM9713 codec support
+ *
+ * Copyright 2006 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    4th Feb 2006   Initial version.
+ *
+ *  Features:-
+ *
+ *   o Support for AC97 Codec, Voice DAC and Aux DAC
+ *   o Support for DAPM
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include "wm9713.h"
+
+#define WM9713_VERSION "0.15"
+
+struct wm9713_priv {
+	u32 pll_in; /* PLL input frequency */
+	u32 pll_out; /* PLL output frequency */
+};
+
+static unsigned int ac97_read(struct snd_soc_codec *codec,
+	unsigned int reg);
+static int ac97_write(struct snd_soc_codec *codec,
+	unsigned int reg, unsigned int val);
+
+/*
+ * WM9713 register cache
+ * Reg 0x3c bit 15 is used by touch driver.
+ */
+static const u16 wm9713_reg[] = {
+	0x6174, 0x8080, 0x8080, 0x8080,
+	0xc880, 0xe808, 0xe808, 0x0808,
+	0x00da, 0x8000, 0xd600, 0xaaa0,
+	0xaaa0, 0xaaa0, 0x0000, 0x0000,
+	0x0f0f, 0x0040, 0x0000, 0x7f00,
+	0x0405, 0x0410, 0xbb80, 0xbb80,
+	0x0000, 0xbb80, 0x0000, 0x4523,
+	0x0000, 0x2000, 0x7eff, 0xffff,
+	0x0000, 0x0000, 0x0080, 0x0000,
+	0x0000, 0x0000, 0xfffe, 0xffff,
+	0x0000, 0x0000, 0x0000, 0xfffe,
+	0x4000, 0x0000, 0x0000, 0x0000,
+	0xb032, 0x3e00, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0006,
+	0x0001, 0x0000, 0x574d, 0x4c13,
+	0x0000, 0x0000, 0x0000
+};
+
+/* virtual HP mixers regs */
+#define HPL_MIXER	0x80
+#define HPR_MIXER	0x82
+#define MICB_MUX	0x82
+
+static const char *wm9713_mic_mixer[] = {"Stereo", "Mic 1", "Mic 2", "Mute"};
+static const char *wm9713_rec_mux[] = {"Stereo", "Left", "Right", "Mute"};
+static const char *wm9713_rec_src[] =
+	{"Mic 1", "Mic 2", "Line", "Mono In", "Headphone", "Speaker",
+	"Mono Out", "Zh"};
+static const char *wm9713_rec_gain[] = {"+1.5dB Steps", "+0.75dB Steps"};
+static const char *wm9713_alc_select[] = {"None", "Left", "Right", "Stereo"};
+static const char *wm9713_mono_pga[] = {"Vmid", "Zh", "Mono", "Inv",
+	"Mono Vmid", "Inv Vmid"};
+static const char *wm9713_spk_pga[] =
+	{"Vmid", "Zh", "Headphone", "Speaker", "Inv", "Headphone Vmid",
+	"Speaker Vmid", "Inv Vmid"};
+static const char *wm9713_hp_pga[] = {"Vmid", "Zh", "Headphone",
+	"Headphone Vmid"};
+static const char *wm9713_out3_pga[] = {"Vmid", "Zh", "Inv 1", "Inv 1 Vmid"};
+static const char *wm9713_out4_pga[] = {"Vmid", "Zh", "Inv 2", "Inv 2 Vmid"};
+static const char *wm9713_dac_inv[] =
+	{"Off", "Mono", "Speaker", "Left Headphone", "Right Headphone",
+	"Headphone Mono", "NC", "Vmid"};
+static const char *wm9713_bass[] = {"Linear Control", "Adaptive Boost"};
+static const char *wm9713_ng_type[] = {"Constant Gain", "Mute"};
+static const char *wm9713_mic_select[] = {"Mic 1", "Mic 2 A", "Mic 2 B"};
+static const char *wm9713_micb_select[] = {"MPB", "MPA"};
+
+static const struct soc_enum wm9713_enum[] = {
+SOC_ENUM_SINGLE(AC97_LINE, 3, 4, wm9713_mic_mixer), /* record mic mixer 0 */
+SOC_ENUM_SINGLE(AC97_VIDEO, 14, 4, wm9713_rec_mux), /* record mux hp 1 */
+SOC_ENUM_SINGLE(AC97_VIDEO, 9, 4, wm9713_rec_mux),  /* record mux mono 2 */
+SOC_ENUM_SINGLE(AC97_VIDEO, 3, 8, wm9713_rec_src),  /* record mux left 3 */
+SOC_ENUM_SINGLE(AC97_VIDEO, 0, 8, wm9713_rec_src),  /* record mux right 4*/
+SOC_ENUM_DOUBLE(AC97_CD, 14, 6, 2, wm9713_rec_gain), /* record step size 5 */
+SOC_ENUM_SINGLE(AC97_PCI_SVID, 14, 4, wm9713_alc_select), /* alc source select 6*/
+SOC_ENUM_SINGLE(AC97_REC_GAIN, 14, 4, wm9713_mono_pga), /* mono input select 7 */
+SOC_ENUM_SINGLE(AC97_REC_GAIN, 11, 8, wm9713_spk_pga), /* speaker left input select 8 */
+SOC_ENUM_SINGLE(AC97_REC_GAIN, 8, 8, wm9713_spk_pga), /* speaker right input select 9 */
+SOC_ENUM_SINGLE(AC97_REC_GAIN, 6, 3, wm9713_hp_pga), /* headphone left input 10 */
+SOC_ENUM_SINGLE(AC97_REC_GAIN, 4, 3, wm9713_hp_pga), /* headphone right input 11 */
+SOC_ENUM_SINGLE(AC97_REC_GAIN, 2, 4, wm9713_out3_pga), /* out 3 source 12 */
+SOC_ENUM_SINGLE(AC97_REC_GAIN, 0, 4, wm9713_out4_pga), /* out 4 source 13 */
+SOC_ENUM_SINGLE(AC97_REC_GAIN_MIC, 13, 8, wm9713_dac_inv), /* dac invert 1 14 */
+SOC_ENUM_SINGLE(AC97_REC_GAIN_MIC, 10, 8, wm9713_dac_inv), /* dac invert 2 15 */
+SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 15, 2, wm9713_bass), /* bass control 16 */
+SOC_ENUM_SINGLE(AC97_PCI_SVID, 5, 2, wm9713_ng_type), /* noise gate type 17 */
+SOC_ENUM_SINGLE(AC97_3D_CONTROL, 12, 3, wm9713_mic_select), /* mic selection 18 */
+SOC_ENUM_SINGLE(MICB_MUX, 0, 2, wm9713_micb_select), /* mic selection 19 */
+};
+
+static const struct snd_kcontrol_new wm9713_snd_ac97_controls[] = {
+SOC_DOUBLE("Speaker Playback Volume", AC97_MASTER, 8, 0, 31, 1),
+SOC_DOUBLE("Speaker Playback Switch", AC97_MASTER, 15, 7, 1, 1),
+SOC_DOUBLE("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1),
+SOC_DOUBLE("Headphone Playback Switch", AC97_HEADPHONE, 15, 7, 1, 1),
+SOC_DOUBLE("Line In Volume", AC97_PC_BEEP, 8, 0, 31, 1),
+SOC_DOUBLE("PCM Playback Volume", AC97_PHONE, 8, 0, 31, 1),
+SOC_SINGLE("Mic 1 Volume", AC97_MIC, 8, 31, 1),
+SOC_SINGLE("Mic 2 Volume", AC97_MIC, 0, 31, 1),
+
+SOC_SINGLE("Mic Boost (+20dB) Switch", AC97_LINE, 5, 1, 0),
+SOC_SINGLE("Mic Headphone Mixer Volume", AC97_LINE, 0, 7, 1),
+
+SOC_SINGLE("Capture Switch", AC97_CD, 15, 1, 1),
+SOC_ENUM("Capture Volume Steps", wm9713_enum[5]),
+SOC_DOUBLE("Capture Volume", AC97_CD, 8, 0, 31, 0),
+SOC_SINGLE("Capture ZC Switch", AC97_CD, 7, 1, 0),
+
+SOC_SINGLE("Capture to Headphone Volume", AC97_VIDEO, 11, 7, 1),
+SOC_SINGLE("Capture to Mono Boost (+20dB) Switch", AC97_VIDEO, 8, 1, 0),
+SOC_SINGLE("Capture ADC Boost (+20dB) Switch", AC97_VIDEO, 6, 1, 0),
+
+SOC_SINGLE("ALC Target Volume", AC97_CODEC_CLASS_REV, 12, 15, 0),
+SOC_SINGLE("ALC Hold Time", AC97_CODEC_CLASS_REV, 8, 15, 0),
+SOC_SINGLE("ALC Decay Time ", AC97_CODEC_CLASS_REV, 4, 15, 0),
+SOC_SINGLE("ALC Attack Time", AC97_CODEC_CLASS_REV, 0, 15, 0),
+SOC_ENUM("ALC Function", wm9713_enum[6]),
+SOC_SINGLE("ALC Max Volume", AC97_PCI_SVID, 11, 7, 0),
+SOC_SINGLE("ALC ZC Timeout", AC97_PCI_SVID, 9, 3, 0),
+SOC_SINGLE("ALC ZC Switch", AC97_PCI_SVID, 8, 1, 0),
+SOC_SINGLE("ALC NG Switch", AC97_PCI_SVID, 7, 1, 0),
+SOC_ENUM("ALC NG Type", wm9713_enum[17]),
+SOC_SINGLE("ALC NG Threshold", AC97_PCI_SVID, 0, 31, 0),
+
+SOC_DOUBLE("Speaker Playback ZC Switch", AC97_MASTER, 14, 6, 1, 0),
+SOC_DOUBLE("Headphone Playback ZC Switch", AC97_HEADPHONE, 14, 6, 1, 0),
+
+SOC_SINGLE("Out4 Playback Switch", AC97_MASTER_MONO, 15, 1, 1),
+SOC_SINGLE("Out4 Playback ZC Switch", AC97_MASTER_MONO, 14, 1, 0),
+SOC_SINGLE("Out4 Playback Volume", AC97_MASTER_MONO, 8, 63, 1),
+
+SOC_SINGLE("Out3 Playback Switch", AC97_MASTER_MONO, 7, 1, 1),
+SOC_SINGLE("Out3 Playback ZC Switch", AC97_MASTER_MONO, 6, 1, 0),
+SOC_SINGLE("Out3 Playback Volume", AC97_MASTER_MONO, 0, 63, 1),
+
+SOC_SINGLE("Mono Capture Volume", AC97_MASTER_TONE, 8, 31, 1),
+SOC_SINGLE("Mono Playback Switch", AC97_MASTER_TONE, 7, 1, 1),
+SOC_SINGLE("Mono Playback ZC Switch", AC97_MASTER_TONE, 6, 1, 0),
+SOC_SINGLE("Mono Playback Volume", AC97_MASTER_TONE, 0, 31, 1),
+
+SOC_SINGLE("PC Beep Playback Headphone Volume", AC97_AUX, 12, 7, 1),
+SOC_SINGLE("PC Beep Playback Speaker Volume", AC97_AUX, 8, 7, 1),
+SOC_SINGLE("PC Beep Playback Mono Volume", AC97_AUX, 4, 7, 1),
+
+SOC_SINGLE("Voice Playback Headphone Volume", AC97_PCM, 12, 7, 1),
+SOC_SINGLE("Voice Playback Master Volume", AC97_PCM, 8, 7, 1),
+SOC_SINGLE("Voice Playback Mono Volume", AC97_PCM, 4, 7, 1),
+
+SOC_SINGLE("Aux Playback Headphone Volume", AC97_REC_SEL, 12, 7, 1),
+SOC_SINGLE("Aux Playback Master Volume", AC97_REC_SEL, 8, 7, 1),
+SOC_SINGLE("Aux Playback Mono Volume", AC97_REC_SEL, 4, 7, 1),
+
+SOC_ENUM("Bass Control", wm9713_enum[16]),
+SOC_SINGLE("Bass Cut-off Switch", AC97_GENERAL_PURPOSE, 12, 1, 1),
+SOC_SINGLE("Tone Cut-off Switch", AC97_GENERAL_PURPOSE, 4, 1, 1),
+SOC_SINGLE("Playback Attenuate (-6dB) Switch", AC97_GENERAL_PURPOSE, 6, 1, 0),
+SOC_SINGLE("Bass Volume", AC97_GENERAL_PURPOSE, 8, 15, 1),
+SOC_SINGLE("Tone Volume", AC97_GENERAL_PURPOSE, 0, 15, 1),
+
+SOC_SINGLE("3D Upper Cut-off Switch", AC97_REC_GAIN_MIC, 5, 1, 0),
+SOC_SINGLE("3D Lower Cut-off Switch", AC97_REC_GAIN_MIC, 4, 1, 0),
+SOC_SINGLE("3D Depth", AC97_REC_GAIN_MIC, 0, 15, 1),
+};
+
+/* add non dapm controls */
+static int wm9713_add_controls(struct snd_soc_codec *codec)
+{
+	int err, i;
+
+	for (i = 0; i < ARRAY_SIZE(wm9713_snd_ac97_controls); i++) {
+		err = snd_ctl_add(codec->card,
+				snd_soc_cnew(&wm9713_snd_ac97_controls[i],
+					codec, NULL));
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+/* We have to create a fake left and right HP mixers because
+ * the codec only has a single control that is shared by both channels.
+ * This makes it impossible to determine the audio path using the current
+ * register map, thus we add a new (virtual) register to help determine the
+ * audio route within the device.
+ */
+static int mixer_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	u16 l, r, beep, tone, phone, rec, pcm, aux;
+
+	l = ac97_read(w->codec, HPL_MIXER);
+	r = ac97_read(w->codec, HPR_MIXER);
+	beep = ac97_read(w->codec, AC97_PC_BEEP);
+	tone = ac97_read(w->codec, AC97_MASTER_TONE);
+	phone = ac97_read(w->codec, AC97_PHONE);
+	rec = ac97_read(w->codec, AC97_REC_SEL);
+	pcm = ac97_read(w->codec, AC97_PCM);
+	aux = ac97_read(w->codec, AC97_AUX);
+
+	if (event & SND_SOC_DAPM_PRE_REG)
+		return 0;
+	if ((l & 0x1) || (r & 0x1))
+		ac97_write(w->codec, AC97_PC_BEEP, beep & 0x7fff);
+	else
+		ac97_write(w->codec, AC97_PC_BEEP, beep | 0x8000);
+
+	if ((l & 0x2) || (r & 0x2))
+		ac97_write(w->codec, AC97_MASTER_TONE, tone & 0x7fff);
+	else
+		ac97_write(w->codec, AC97_MASTER_TONE, tone | 0x8000);
+
+	if ((l & 0x4) || (r & 0x4))
+		ac97_write(w->codec, AC97_PHONE, phone & 0x7fff);
+	else
+		ac97_write(w->codec, AC97_PHONE, phone | 0x8000);
+
+	if ((l & 0x8) || (r & 0x8))
+		ac97_write(w->codec, AC97_REC_SEL, rec & 0x7fff);
+	else
+		ac97_write(w->codec, AC97_REC_SEL, rec | 0x8000);
+
+	if ((l & 0x10) || (r & 0x10))
+		ac97_write(w->codec, AC97_PCM, pcm & 0x7fff);
+	else
+		ac97_write(w->codec, AC97_PCM, pcm | 0x8000);
+
+	if ((l & 0x20) || (r & 0x20))
+		ac97_write(w->codec, AC97_AUX, aux & 0x7fff);
+	else
+		ac97_write(w->codec, AC97_AUX, aux | 0x8000);
+
+	return 0;
+}
+
+/* Left Headphone Mixers */
+static const struct snd_kcontrol_new wm9713_hpl_mixer_controls[] = {
+SOC_DAPM_SINGLE("PC Beep Playback Switch", HPL_MIXER, 5, 1, 0),
+SOC_DAPM_SINGLE("Voice Playback Switch", HPL_MIXER, 4, 1, 0),
+SOC_DAPM_SINGLE("Aux Playback Switch", HPL_MIXER, 3, 1, 0),
+SOC_DAPM_SINGLE("PCM Playback Switch", HPL_MIXER, 2, 1, 0),
+SOC_DAPM_SINGLE("MonoIn Playback Switch", HPL_MIXER, 1, 1, 0),
+SOC_DAPM_SINGLE("Bypass Playback Switch", HPL_MIXER, 0, 1, 0),
+};
+
+/* Right Headphone Mixers */
+static const struct snd_kcontrol_new wm9713_hpr_mixer_controls[] = {
+SOC_DAPM_SINGLE("PC Beep Playback Switch", HPR_MIXER, 5, 1, 0),
+SOC_DAPM_SINGLE("Voice Playback Switch", HPR_MIXER, 4, 1, 0),
+SOC_DAPM_SINGLE("Aux Playback Switch", HPR_MIXER, 3, 1, 0),
+SOC_DAPM_SINGLE("PCM Playback Switch", HPR_MIXER, 2, 1, 0),
+SOC_DAPM_SINGLE("MonoIn Playback Switch", HPR_MIXER, 1, 1, 0),
+SOC_DAPM_SINGLE("Bypass Playback Switch", HPR_MIXER, 0, 1, 0),
+};
+
+/* headphone capture mux */
+static const struct snd_kcontrol_new wm9713_hp_rec_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[1]);
+
+/* headphone mic mux */
+static const struct snd_kcontrol_new wm9713_hp_mic_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[0]);
+
+/* Speaker Mixer */
+static const struct snd_kcontrol_new wm9713_speaker_mixer_controls[] = {
+SOC_DAPM_SINGLE("PC Beep Playback Switch", AC97_AUX, 11, 1, 1),
+SOC_DAPM_SINGLE("Voice Playback Switch", AC97_PCM, 11, 1, 1),
+SOC_DAPM_SINGLE("Aux Playback Switch", AC97_REC_SEL, 11, 1, 1),
+SOC_DAPM_SINGLE("PCM Playback Switch", AC97_PHONE, 14, 1, 1),
+SOC_DAPM_SINGLE("MonoIn Playback Switch", AC97_MASTER_TONE, 14, 1, 1),
+SOC_DAPM_SINGLE("Bypass Playback Switch", AC97_PC_BEEP, 14, 1, 1),
+};
+
+/* Mono Mixer */
+static const struct snd_kcontrol_new wm9713_mono_mixer_controls[] = {
+SOC_DAPM_SINGLE("PC Beep Playback Switch", AC97_AUX, 7, 1, 1),
+SOC_DAPM_SINGLE("Voice Playback Switch", AC97_PCM, 7, 1, 1),
+SOC_DAPM_SINGLE("Aux Playback Switch", AC97_REC_SEL, 7, 1, 1),
+SOC_DAPM_SINGLE("PCM Playback Switch", AC97_PHONE, 13, 1, 1),
+SOC_DAPM_SINGLE("MonoIn Playback Switch", AC97_MASTER_TONE, 13, 1, 1),
+SOC_DAPM_SINGLE("Bypass Playback Switch", AC97_PC_BEEP, 13, 1, 1),
+SOC_DAPM_SINGLE("Mic 1 Sidetone Switch", AC97_LINE, 7, 1, 1),
+SOC_DAPM_SINGLE("Mic 2 Sidetone Switch", AC97_LINE, 6, 1, 1),
+};
+
+/* mono mic mux */
+static const struct snd_kcontrol_new wm9713_mono_mic_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[2]);
+
+/* mono output mux */
+static const struct snd_kcontrol_new wm9713_mono_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[7]);
+
+/* speaker left output mux */
+static const struct snd_kcontrol_new wm9713_hp_spkl_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[8]);
+
+/* speaker right output mux */
+static const struct snd_kcontrol_new wm9713_hp_spkr_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[9]);
+
+/* headphone left output mux */
+static const struct snd_kcontrol_new wm9713_hpl_out_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[10]);
+
+/* headphone right output mux */
+static const struct snd_kcontrol_new wm9713_hpr_out_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[11]);
+
+/* Out3 mux */
+static const struct snd_kcontrol_new wm9713_out3_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[12]);
+
+/* Out4 mux */
+static const struct snd_kcontrol_new wm9713_out4_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[13]);
+
+/* DAC inv mux 1 */
+static const struct snd_kcontrol_new wm9713_dac_inv1_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[14]);
+
+/* DAC inv mux 2 */
+static const struct snd_kcontrol_new wm9713_dac_inv2_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[15]);
+
+/* Capture source left */
+static const struct snd_kcontrol_new wm9713_rec_srcl_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[3]);
+
+/* Capture source right */
+static const struct snd_kcontrol_new wm9713_rec_srcr_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[4]);
+
+/* mic source */
+static const struct snd_kcontrol_new wm9713_mic_sel_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[18]);
+
+/* mic source B virtual control */
+static const struct snd_kcontrol_new wm9713_micb_sel_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[19]);
+
+static const struct snd_soc_dapm_widget wm9713_dapm_widgets[] = {
+SND_SOC_DAPM_MUX("Capture Headphone Mux", SND_SOC_NOPM, 0, 0,
+	&wm9713_hp_rec_mux_controls),
+SND_SOC_DAPM_MUX("Sidetone Mux", SND_SOC_NOPM, 0, 0,
+	&wm9713_hp_mic_mux_controls),
+SND_SOC_DAPM_MUX("Capture Mono Mux", SND_SOC_NOPM, 0, 0,
+	&wm9713_mono_mic_mux_controls),
+SND_SOC_DAPM_MUX("Mono Out Mux", SND_SOC_NOPM, 0, 0,
+	&wm9713_mono_mux_controls),
+SND_SOC_DAPM_MUX("Left Speaker Out Mux", SND_SOC_NOPM, 0, 0,
+	&wm9713_hp_spkl_mux_controls),
+SND_SOC_DAPM_MUX("Right Speaker Out Mux", SND_SOC_NOPM, 0, 0,
+	&wm9713_hp_spkr_mux_controls),
+SND_SOC_DAPM_MUX("Left Headphone Out Mux", SND_SOC_NOPM, 0, 0,
+	&wm9713_hpl_out_mux_controls),
+SND_SOC_DAPM_MUX("Right Headphone Out Mux", SND_SOC_NOPM, 0, 0,
+	&wm9713_hpr_out_mux_controls),
+SND_SOC_DAPM_MUX("Out 3 Mux", SND_SOC_NOPM, 0, 0,
+	&wm9713_out3_mux_controls),
+SND_SOC_DAPM_MUX("Out 4 Mux", SND_SOC_NOPM, 0, 0,
+	&wm9713_out4_mux_controls),
+SND_SOC_DAPM_MUX("DAC Inv Mux 1", SND_SOC_NOPM, 0, 0,
+	&wm9713_dac_inv1_mux_controls),
+SND_SOC_DAPM_MUX("DAC Inv Mux 2", SND_SOC_NOPM, 0, 0,
+	&wm9713_dac_inv2_mux_controls),
+SND_SOC_DAPM_MUX("Left Capture Source", SND_SOC_NOPM, 0, 0,
+	&wm9713_rec_srcl_mux_controls),
+SND_SOC_DAPM_MUX("Right Capture Source", SND_SOC_NOPM, 0, 0,
+	&wm9713_rec_srcr_mux_controls),
+SND_SOC_DAPM_MUX("Mic A Source", SND_SOC_NOPM, 0, 0,
+	&wm9713_mic_sel_mux_controls),
+SND_SOC_DAPM_MUX("Mic B Source", SND_SOC_NOPM, 0, 0,
+	&wm9713_micb_sel_mux_controls),
+SND_SOC_DAPM_MIXER_E("Left HP Mixer", AC97_EXTENDED_MID, 3, 1,
+	&wm9713_hpl_mixer_controls[0], ARRAY_SIZE(wm9713_hpl_mixer_controls),
+	mixer_event, SND_SOC_DAPM_POST_REG),
+SND_SOC_DAPM_MIXER_E("Right HP Mixer", AC97_EXTENDED_MID, 2, 1,
+	&wm9713_hpr_mixer_controls[0], ARRAY_SIZE(wm9713_hpr_mixer_controls),
+	mixer_event, SND_SOC_DAPM_POST_REG),
+SND_SOC_DAPM_MIXER("Mono Mixer", AC97_EXTENDED_MID, 0, 1,
+	&wm9713_mono_mixer_controls[0], ARRAY_SIZE(wm9713_mono_mixer_controls)),
+SND_SOC_DAPM_MIXER("Speaker Mixer", AC97_EXTENDED_MID, 1, 1,
+	&wm9713_speaker_mixer_controls[0],
+	ARRAY_SIZE(wm9713_speaker_mixer_controls)),
+SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback", AC97_EXTENDED_MID, 7, 1),
+SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback", AC97_EXTENDED_MID, 6, 1),
+SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("HP Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("Line Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("Capture Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_DAC("Voice DAC", "Voice Playback", AC97_EXTENDED_MID, 12, 1),
+SND_SOC_DAPM_DAC("Aux DAC", "Aux Playback", AC97_EXTENDED_MID, 11, 1),
+SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture", AC97_EXTENDED_MID, 5, 1),
+SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture", AC97_EXTENDED_MID, 4, 1),
+SND_SOC_DAPM_PGA("Left Headphone", AC97_EXTENDED_MSTATUS, 10, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Right Headphone", AC97_EXTENDED_MSTATUS, 9, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Left Speaker", AC97_EXTENDED_MSTATUS, 8, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Right Speaker", AC97_EXTENDED_MSTATUS, 7, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Out 3", AC97_EXTENDED_MSTATUS, 11, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Out 4", AC97_EXTENDED_MSTATUS, 12, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Mono Out", AC97_EXTENDED_MSTATUS, 13, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Left Line In", AC97_EXTENDED_MSTATUS, 6, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Right Line In", AC97_EXTENDED_MSTATUS, 5, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Mono In", AC97_EXTENDED_MSTATUS, 4, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Mic A PGA", AC97_EXTENDED_MSTATUS, 3, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Mic B PGA", AC97_EXTENDED_MSTATUS, 2, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Mic A Pre Amp", AC97_EXTENDED_MSTATUS, 1, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Mic B Pre Amp", AC97_EXTENDED_MSTATUS, 0, 1, NULL, 0),
+SND_SOC_DAPM_MICBIAS("Mic Bias", AC97_EXTENDED_MSTATUS, 14, 1),
+SND_SOC_DAPM_OUTPUT("MONO"),
+SND_SOC_DAPM_OUTPUT("HPL"),
+SND_SOC_DAPM_OUTPUT("HPR"),
+SND_SOC_DAPM_OUTPUT("SPKL"),
+SND_SOC_DAPM_OUTPUT("SPKR"),
+SND_SOC_DAPM_OUTPUT("OUT3"),
+SND_SOC_DAPM_OUTPUT("OUT4"),
+SND_SOC_DAPM_INPUT("LINEL"),
+SND_SOC_DAPM_INPUT("LINER"),
+SND_SOC_DAPM_INPUT("MONOIN"),
+SND_SOC_DAPM_INPUT("PCBEEP"),
+SND_SOC_DAPM_INPUT("MIC1"),
+SND_SOC_DAPM_INPUT("MIC2A"),
+SND_SOC_DAPM_INPUT("MIC2B"),
+SND_SOC_DAPM_VMID("VMID"),
+};
+
+static const char *audio_map[][3] = {
+	/* left HP mixer */
+	{"Left HP Mixer", "PC Beep Playback Switch", "PCBEEP"},
+	{"Left HP Mixer", "Voice Playback Switch",   "Voice DAC"},
+	{"Left HP Mixer", "Aux Playback Switch",     "Aux DAC"},
+	{"Left HP Mixer", "Bypass Playback Switch",  "Left Line In"},
+	{"Left HP Mixer", "PCM Playback Switch",     "Left DAC"},
+	{"Left HP Mixer", "MonoIn Playback Switch",  "Mono In"},
+	{"Left HP Mixer", NULL,  "Capture Headphone Mux"},
+
+	/* right HP mixer */
+	{"Right HP Mixer", "PC Beep Playback Switch", "PCBEEP"},
+	{"Right HP Mixer", "Voice Playback Switch",   "Voice DAC"},
+	{"Right HP Mixer", "Aux Playback Switch",     "Aux DAC"},
+	{"Right HP Mixer", "Bypass Playback Switch",  "Right Line In"},
+	{"Right HP Mixer", "PCM Playback Switch",     "Right DAC"},
+	{"Right HP Mixer", "MonoIn Playback Switch",  "Mono In"},
+	{"Right HP Mixer", NULL,  "Capture Headphone Mux"},
+
+	/* virtual mixer - mixes left & right channels for spk and mono */
+	{"AC97 Mixer", NULL, "Left DAC"},
+	{"AC97 Mixer", NULL, "Right DAC"},
+	{"Line Mixer", NULL, "Right Line In"},
+	{"Line Mixer", NULL, "Left Line In"},
+	{"HP Mixer", NULL, "Left HP Mixer"},
+	{"HP Mixer", NULL, "Right HP Mixer"},
+	{"Capture Mixer", NULL, "Left Capture Source"},
+	{"Capture Mixer", NULL, "Right Capture Source"},
+
+	/* speaker mixer */
+	{"Speaker Mixer", "PC Beep Playback Switch", "PCBEEP"},
+	{"Speaker Mixer", "Voice Playback Switch",   "Voice DAC"},
+	{"Speaker Mixer", "Aux Playback Switch",     "Aux DAC"},
+	{"Speaker Mixer", "Bypass Playback Switch",  "Line Mixer"},
+	{"Speaker Mixer", "PCM Playback Switch",     "AC97 Mixer"},
+	{"Speaker Mixer", "MonoIn Playback Switch",  "Mono In"},
+
+	/* mono mixer */
+	{"Mono Mixer", "PC Beep Playback Switch", "PCBEEP"},
+	{"Mono Mixer", "Voice Playback Switch",   "Voice DAC"},
+	{"Mono Mixer", "Aux Playback Switch",     "Aux DAC"},
+	{"Mono Mixer", "Bypass Playback Switch",  "Line Mixer"},
+	{"Mono Mixer", "PCM Playback Switch",     "AC97 Mixer"},
+	{"Mono Mixer", "Mic 1 Sidetone Switch", "Mic A PGA"},
+	{"Mono Mixer", "Mic 2 Sidetone Switch", "Mic B PGA"},
+	{"Mono Mixer", NULL,  "Capture Mono Mux"},
+
+	/* DAC inv mux 1 */
+	{"DAC Inv Mux 1", "Mono", "Mono Mixer"},
+	{"DAC Inv Mux 1", "Speaker", "Speaker Mixer"},
+	{"DAC Inv Mux 1", "Left Headphone", "Left HP Mixer"},
+	{"DAC Inv Mux 1", "Right Headphone", "Right HP Mixer"},
+	{"DAC Inv Mux 1", "Headphone Mono", "HP Mixer"},
+
+	/* DAC inv mux 2 */
+	{"DAC Inv Mux 2", "Mono", "Mono Mixer"},
+	{"DAC Inv Mux 2", "Speaker", "Speaker Mixer"},
+	{"DAC Inv Mux 2", "Left Headphone", "Left HP Mixer"},
+	{"DAC Inv Mux 2", "Right Headphone", "Right HP Mixer"},
+	{"DAC Inv Mux 2", "Headphone Mono", "HP Mixer"},
+
+	/* headphone left mux */
+	{"Left Headphone Out Mux", "Headphone", "Left HP Mixer"},
+
+	/* headphone right mux */
+	{"Right Headphone Out Mux", "Headphone", "Right HP Mixer"},
+
+	/* speaker left mux */
+	{"Left Speaker Out Mux", "Headphone", "Left HP Mixer"},
+	{"Left Speaker Out Mux", "Speaker", "Speaker Mixer"},
+	{"Left Speaker Out Mux", "Inv", "DAC Inv Mux 1"},
+
+	/* speaker right mux */
+	{"Right Speaker Out Mux", "Headphone", "Right HP Mixer"},
+	{"Right Speaker Out Mux", "Speaker", "Speaker Mixer"},
+	{"Right Speaker Out Mux", "Inv", "DAC Inv Mux 2"},
+
+	/* mono mux */
+	{"Mono Out Mux", "Mono", "Mono Mixer"},
+	{"Mono Out Mux", "Inv", "DAC Inv Mux 1"},
+
+	/* out 3 mux */
+	{"Out 3 Mux", "Inv 1", "DAC Inv Mux 1"},
+
+	/* out 4 mux */
+	{"Out 4 Mux", "Inv 2", "DAC Inv Mux 2"},
+
+	/* output pga */
+	{"HPL", NULL, "Left Headphone"},
+	{"Left Headphone", NULL, "Left Headphone Out Mux"},
+	{"HPR", NULL, "Right Headphone"},
+	{"Right Headphone", NULL, "Right Headphone Out Mux"},
+	{"OUT3", NULL, "Out 3"},
+	{"Out 3", NULL, "Out 3 Mux"},
+	{"OUT4", NULL, "Out 4"},
+	{"Out 4", NULL, "Out 4 Mux"},
+	{"SPKL", NULL, "Left Speaker"},
+	{"Left Speaker", NULL, "Left Speaker Out Mux"},
+	{"SPKR", NULL, "Right Speaker"},
+	{"Right Speaker", NULL, "Right Speaker Out Mux"},
+	{"MONO", NULL, "Mono Out"},
+	{"Mono Out", NULL, "Mono Out Mux"},
+
+	/* input pga */
+	{"Left Line In", NULL, "LINEL"},
+	{"Right Line In", NULL, "LINER"},
+	{"Mono In", NULL, "MONOIN"},
+	{"Mic A PGA", NULL, "Mic A Pre Amp"},
+	{"Mic B PGA", NULL, "Mic B Pre Amp"},
+
+	/* left capture select */
+	{"Left Capture Source", "Mic 1", "Mic A Pre Amp"},
+	{"Left Capture Source", "Mic 2", "Mic B Pre Amp"},
+	{"Left Capture Source", "Line", "LINEL"},
+	{"Left Capture Source", "Mono In", "MONOIN"},
+	{"Left Capture Source", "Headphone", "Left HP Mixer"},
+	{"Left Capture Source", "Speaker", "Speaker Mixer"},
+	{"Left Capture Source", "Mono Out", "Mono Mixer"},
+
+	/* right capture select */
+	{"Right Capture Source", "Mic 1", "Mic A Pre Amp"},
+	{"Right Capture Source", "Mic 2", "Mic B Pre Amp"},
+	{"Right Capture Source", "Line", "LINER"},
+	{"Right Capture Source", "Mono In", "MONOIN"},
+	{"Right Capture Source", "Headphone", "Right HP Mixer"},
+	{"Right Capture Source", "Speaker", "Speaker Mixer"},
+	{"Right Capture Source", "Mono Out", "Mono Mixer"},
+
+	/* left ADC */
+	{"Left ADC", NULL, "Left Capture Source"},
+
+	/* right ADC */
+	{"Right ADC", NULL, "Right Capture Source"},
+
+	/* mic */
+	{"Mic A Pre Amp", NULL, "Mic A Source"},
+	{"Mic A Source", "Mic 1", "MIC1"},
+	{"Mic A Source", "Mic 2 A", "MIC2A"},
+	{"Mic A Source", "Mic 2 B", "Mic B Source"},
+	{"Mic B Pre Amp", "MPB", "Mic B Source"},
+	{"Mic B Source", NULL, "MIC2B"},
+
+	/* headphone capture */
+	{"Capture Headphone Mux", "Stereo", "Capture Mixer"},
+	{"Capture Headphone Mux", "Left", "Left Capture Source"},
+	{"Capture Headphone Mux", "Right", "Right Capture Source"},
+
+	/* mono capture */
+	{"Capture Mono Mux", "Stereo", "Capture Mixer"},
+	{"Capture Mono Mux", "Left", "Left Capture Source"},
+	{"Capture Mono Mux", "Right", "Right Capture Source"},
+
+	{NULL, NULL, NULL},
+};
+
+static int wm9713_add_widgets(struct snd_soc_codec *codec)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(wm9713_dapm_widgets); i++)
+		snd_soc_dapm_new_control(codec, &wm9713_dapm_widgets[i]);
+
+	/* set up audio path audio_mapnects */
+	for (i = 0; audio_map[i][0] != NULL; i++)
+		snd_soc_dapm_connect_input(codec, audio_map[i][0],
+			audio_map[i][1], audio_map[i][2]);
+
+	snd_soc_dapm_new_widgets(codec);
+	return 0;
+}
+
+static unsigned int ac97_read(struct snd_soc_codec *codec,
+	unsigned int reg)
+{
+	u16 *cache = codec->reg_cache;
+
+	if (reg == AC97_RESET || reg == AC97_GPIO_STATUS ||
+		reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 ||
+		reg == AC97_CD)
+		return soc_ac97_ops.read(codec->ac97, reg);
+	else {
+		reg = reg >> 1;
+
+		if (reg > (ARRAY_SIZE(wm9713_reg)))
+			return -EIO;
+
+		return cache[reg];
+	}
+}
+
+static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
+	unsigned int val)
+{
+	u16 *cache = codec->reg_cache;
+	if (reg < 0x7c)
+		soc_ac97_ops.write(codec->ac97, reg, val);
+	reg = reg >> 1;
+	if (reg <= (ARRAY_SIZE(wm9713_reg)))
+		cache[reg] = val;
+
+	return 0;
+}
+
+/* PLL divisors */
+struct _pll_div {
+	u32 divsel:1;
+	u32 divctl:1;
+	u32 lf:1;
+	u32 n:4;
+	u32 k:24;
+};
+
+/* The size in bits of the PLL divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_PLL_SIZE ((1 << 22) * 10)
+
+static void pll_factors(struct _pll_div *pll_div, unsigned int source)
+{
+	u64 Kpart;
+	unsigned int K, Ndiv, Nmod, target;
+
+	/* The the PLL output is always 98.304MHz. */
+	target = 98304000;
+
+	/* If the input frequency is over 14.4MHz then scale it down. */
+	if (source > 14400000) {
+		source >>= 1;
+		pll_div->divsel = 1;
+
+		if (source > 14400000) {
+			source >>= 1;
+			pll_div->divctl = 1;
+		} else
+			pll_div->divctl = 0;
+
+	} else {
+		pll_div->divsel = 0;
+		pll_div->divctl = 0;
+	}
+
+	/* Low frequency sources require an additional divide in the
+	 * loop.
+	 */
+	if (source < 8192000) {
+		pll_div->lf = 1;
+		target >>= 2;
+	} else
+		pll_div->lf = 0;
+
+	Ndiv = target / source;
+	if ((Ndiv < 5) || (Ndiv > 12))
+		printk(KERN_WARNING
+			"WM9713 PLL N value %d out of recommended range!\n",
+			Ndiv);
+
+	pll_div->n = Ndiv;
+	Nmod = target % source;
+	Kpart = FIXED_PLL_SIZE * (long long)Nmod;
+
+	do_div(Kpart, source);
+
+	K = Kpart & 0xFFFFFFFF;
+
+	/* Check if we need to round */
+	if ((K % 10) >= 5)
+		K += 5;
+
+	/* Move down to proper range now rounding is done */
+	K /= 10;
+
+	pll_div->k = K;
+}
+
+/**
+ * Please note that changing the PLL input frequency may require
+ * resynchronisation with the AC97 controller.
+ */
+static int wm9713_set_pll(struct snd_soc_codec *codec,
+	int pll_id, unsigned int freq_in, unsigned int freq_out)
+{
+	struct wm9713_priv *wm9713 = codec->private_data;
+	u16 reg, reg2;
+	struct _pll_div pll_div;
+
+	/* turn PLL off ? */
+	if (freq_in == 0 || freq_out == 0) {
+		/* disable PLL power and select ext source */
+		reg = ac97_read(codec, AC97_HANDSET_RATE);
+		ac97_write(codec, AC97_HANDSET_RATE, reg | 0x0080);
+		reg = ac97_read(codec, AC97_EXTENDED_MID);
+		ac97_write(codec, AC97_EXTENDED_MID, reg | 0x0200);
+		wm9713->pll_out = 0;
+		return 0;
+	}
+
+	pll_factors(&pll_div, freq_in);
+
+	if (pll_div.k == 0) {
+		reg = (pll_div.n << 12) | (pll_div.lf << 11) |
+			(pll_div.divsel << 9) | (pll_div.divctl << 8);
+		ac97_write(codec, AC97_LINE1_LEVEL, reg);
+	} else {
+		/* write the fractional k to the reg 0x46 pages */
+		reg2 = (pll_div.n << 12) | (pll_div.lf << 11) | (1 << 10) |
+			(pll_div.divsel << 9) | (pll_div.divctl << 8);
+
+		/* K [21:20] */
+		reg = reg2 | (0x5 << 4) | (pll_div.k >> 20);
+		ac97_write(codec, AC97_LINE1_LEVEL, reg);
+
+		/* K [19:16] */
+		reg = reg2 | (0x4 << 4) | ((pll_div.k >> 16) & 0xf);
+		ac97_write(codec, AC97_LINE1_LEVEL, reg);
+
+		/* K [15:12] */
+		reg = reg2 | (0x3 << 4) | ((pll_div.k >> 12) & 0xf);
+		ac97_write(codec, AC97_LINE1_LEVEL, reg);
+
+		/* K [11:8] */
+		reg = reg2 | (0x2 << 4) | ((pll_div.k >> 8) & 0xf);
+		ac97_write(codec, AC97_LINE1_LEVEL, reg);
+
+		/* K [7:4] */
+		reg = reg2 | (0x1 << 4) | ((pll_div.k >> 4) & 0xf);
+		ac97_write(codec, AC97_LINE1_LEVEL, reg);
+
+		reg = reg2 | (0x0 << 4) | (pll_div.k & 0xf); /* K [3:0] */
+		ac97_write(codec, AC97_LINE1_LEVEL, reg);
+	}
+
+	/* turn PLL on and select as source */
+	reg = ac97_read(codec, AC97_EXTENDED_MID);
+	ac97_write(codec, AC97_EXTENDED_MID, reg & 0xfdff);
+	reg = ac97_read(codec, AC97_HANDSET_RATE);
+	ac97_write(codec, AC97_HANDSET_RATE, reg & 0xff7f);
+	wm9713->pll_out = freq_out;
+	wm9713->pll_in = freq_in;
+
+	/* wait 10ms AC97 link frames for the link to stabilise */
+	schedule_timeout_interruptible(msecs_to_jiffies(10));
+	return 0;
+}
+
+static int wm9713_set_dai_pll(struct snd_soc_codec_dai *codec_dai,
+		int pll_id, unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	return wm9713_set_pll(codec, pll_id, freq_in, freq_out);
+}
+
+/*
+ * Tristate the PCM DAI lines, tristate can be disabled by calling
+ * wm9713_set_dai_fmt()
+ */
+static int wm9713_set_dai_tristate(struct snd_soc_codec_dai *codec_dai,
+	int tristate)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 reg = ac97_read(codec, AC97_CENTER_LFE_MASTER) & 0x9fff;
+
+	if (tristate)
+		ac97_write(codec, AC97_CENTER_LFE_MASTER, reg);
+
+	return 0;
+}
+
+/*
+ * Configure WM9713 clock dividers.
+ * Voice DAC needs 256 FS
+ */
+static int wm9713_set_dai_clkdiv(struct snd_soc_codec_dai *codec_dai,
+		int div_id, int div)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 reg;
+
+	switch (div_id) {
+	case WM9713_PCMCLK_DIV:
+		reg = ac97_read(codec, AC97_HANDSET_RATE) & 0xf0ff;
+		ac97_write(codec, AC97_HANDSET_RATE, reg | div);
+		break;
+	case WM9713_CLKA_MULT:
+		reg = ac97_read(codec, AC97_HANDSET_RATE) & 0xfffd;
+		ac97_write(codec, AC97_HANDSET_RATE, reg | div);
+		break;
+	case WM9713_CLKB_MULT:
+		reg = ac97_read(codec, AC97_HANDSET_RATE) & 0xfffb;
+		ac97_write(codec, AC97_HANDSET_RATE, reg | div);
+		break;
+	case WM9713_HIFI_DIV:
+		reg = ac97_read(codec, AC97_HANDSET_RATE) & 0x8fff;
+		ac97_write(codec, AC97_HANDSET_RATE, reg | div);
+		break;
+	case WM9713_PCMBCLK_DIV:
+		reg = ac97_read(codec, AC97_CENTER_LFE_MASTER) & 0xf1ff;
+		ac97_write(codec, AC97_CENTER_LFE_MASTER, reg | div);
+		break;
+	case WM9713_PCMCLK_PLL_DIV:
+		reg = ac97_read(codec, AC97_LINE1_LEVEL) & 0xff80;
+		ac97_write(codec, AC97_LINE1_LEVEL, reg | 0x60 | div);
+		break;
+	case WM9713_HIFI_PLL_DIV:
+		reg = ac97_read(codec, AC97_LINE1_LEVEL) & 0xff80;
+		ac97_write(codec, AC97_LINE1_LEVEL, reg | 0x70 | div);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm9713_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 gpio = ac97_read(codec, AC97_GPIO_CFG) & 0xffc5;
+	u16 reg = 0x8000;
+
+	/* clock masters */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		reg |= 0x4000;
+		gpio |= 0x0010;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		reg |= 0x6000;
+		gpio |= 0x0018;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		reg |= 0x0200;
+		gpio |= 0x001a;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		gpio |= 0x0012;
+		break;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_IB_IF:
+		reg |= 0x00c0;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		reg |= 0x0080;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		reg |= 0x0040;
+		break;
+	}
+
+	/* DAI format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		reg |= 0x0002;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		reg |= 0x0001;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		reg |= 0x0003;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		reg |= 0x0043;
+		break;
+	}
+
+	ac97_write(codec, AC97_GPIO_CFG, gpio);
+	ac97_write(codec, AC97_CENTER_LFE_MASTER, reg);
+	return 0;
+}
+
+static int wm9713_pcm_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	u16 reg = ac97_read(codec, AC97_CENTER_LFE_MASTER) & 0xfff3;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		reg |= 0x0004;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		reg |= 0x0008;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		reg |= 0x000c;
+		break;
+	}
+
+	/* enable PCM interface in master mode */
+	ac97_write(codec, AC97_CENTER_LFE_MASTER, reg);
+	return 0;
+}
+
+static void wm9713_voiceshutdown(struct snd_pcm_substream *substream)
+{
+    struct snd_soc_pcm_runtime *rtd = substream->private_data;
+    struct snd_soc_device *socdev = rtd->socdev;
+    struct snd_soc_codec *codec = socdev->codec;
+    u16 status;
+
+    /* Gracefully shut down the voice interface. */
+    status = ac97_read(codec, AC97_EXTENDED_STATUS) | 0x1000;
+    ac97_write(codec, AC97_HANDSET_RATE, 0x0280);
+    schedule_timeout_interruptible(msecs_to_jiffies(1));
+    ac97_write(codec, AC97_HANDSET_RATE, 0x0F80);
+    ac97_write(codec, AC97_EXTENDED_MID, status);
+}
+
+static int ac97_hifi_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	int reg;
+	u16 vra;
+
+	vra = ac97_read(codec, AC97_EXTENDED_STATUS);
+	ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		reg = AC97_PCM_FRONT_DAC_RATE;
+	else
+		reg = AC97_PCM_LR_ADC_RATE;
+
+	return ac97_write(codec, reg, runtime->rate);
+}
+
+static int ac97_aux_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	u16 vra, xsle;
+
+	vra = ac97_read(codec, AC97_EXTENDED_STATUS);
+	ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1);
+	xsle = ac97_read(codec, AC97_PCI_SID);
+	ac97_write(codec, AC97_PCI_SID, xsle | 0x8000);
+
+	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+		return -ENODEV;
+
+	return ac97_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate);
+}
+
+#define WM9713_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+		SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\
+		SNDRV_PCM_RATE_48000)
+
+#define WM9713_PCM_FORMATS \
+	(SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \
+	 SNDRV_PCM_FORMAT_S24_LE)
+
+struct snd_soc_codec_dai wm9713_dai[] = {
+{
+	.name = "AC97 HiFi",
+	.type = SND_SOC_DAI_AC97_BUS,
+	.playback = {
+		.stream_name = "HiFi Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM9713_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.capture = {
+		.stream_name = "HiFi Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM9713_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.ops = {
+		.prepare = ac97_hifi_prepare,},
+	.dai_ops = {
+		.set_clkdiv = wm9713_set_dai_clkdiv,
+		.set_pll = wm9713_set_dai_pll,},
+	},
+	{
+	.name = "AC97 Aux",
+	.playback = {
+		.stream_name = "Aux Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = WM9713_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.ops = {
+		.prepare = ac97_aux_prepare,},
+	.dai_ops = {
+		.set_clkdiv = wm9713_set_dai_clkdiv,
+		.set_pll = wm9713_set_dai_pll,},
+	},
+	{
+	.name = "WM9713 Voice",
+	.playback = {
+		.stream_name = "Voice Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = WM9713_RATES,
+		.formats = WM9713_PCM_FORMATS,},
+	.capture = {
+		.stream_name = "Voice Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM9713_RATES,
+		.formats = WM9713_PCM_FORMATS,},
+	.ops = {
+		.hw_params = wm9713_pcm_hw_params,
+		.shutdown = wm9713_voiceshutdown,},
+	.dai_ops = {
+		.set_clkdiv = wm9713_set_dai_clkdiv,
+		.set_pll = wm9713_set_dai_pll,
+		.set_fmt = wm9713_set_dai_fmt,
+		.set_tristate = wm9713_set_dai_tristate,
+	},
+	},
+};
+EXPORT_SYMBOL_GPL(wm9713_dai);
+
+int wm9713_reset(struct snd_soc_codec *codec, int try_warm)
+{
+	if (try_warm && soc_ac97_ops.warm_reset) {
+		soc_ac97_ops.warm_reset(codec->ac97);
+		if (!(ac97_read(codec, 0) & 0x8000))
+			return 1;
+	}
+
+	soc_ac97_ops.reset(codec->ac97);
+	if (ac97_read(codec, 0) & 0x8000)
+		return -EIO;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm9713_reset);
+
+static int wm9713_dapm_event(struct snd_soc_codec *codec, int event)
+{
+	u16 reg;
+
+	switch (event) {
+	case SNDRV_CTL_POWER_D0: /* full On */
+		/* enable thermal shutdown */
+		reg = ac97_read(codec, AC97_EXTENDED_MID) & 0x1bff;
+		ac97_write(codec, AC97_EXTENDED_MID, reg);
+		break;
+	case SNDRV_CTL_POWER_D1: /* partial On */
+	case SNDRV_CTL_POWER_D2: /* partial On */
+		break;
+	case SNDRV_CTL_POWER_D3hot: /* Off, with power */
+		/* enable master bias and vmid */
+		reg = ac97_read(codec, AC97_EXTENDED_MID) & 0x3bff;
+		ac97_write(codec, AC97_EXTENDED_MID, reg);
+		ac97_write(codec, AC97_POWERDOWN, 0x0000);
+		break;
+	case SNDRV_CTL_POWER_D3cold: /* Off, without power */
+		/* disable everything including AC link */
+		ac97_write(codec, AC97_EXTENDED_MID, 0xffff);
+		ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff);
+		ac97_write(codec, AC97_POWERDOWN, 0xffff);
+		break;
+	}
+	codec->dapm_state = event;
+	return 0;
+}
+
+static int wm9713_soc_suspend(struct platform_device *pdev,
+	pm_message_t state)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+	u16 reg;
+
+	/* Disable everything except touchpanel - that will be handled
+	 * by the touch driver and left disabled if touch is not in
+	 * use. */
+	reg = ac97_read(codec, AC97_EXTENDED_MID);
+	ac97_write(codec, AC97_EXTENDED_MID, reg | 0x7fff);
+	ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff);
+	ac97_write(codec, AC97_POWERDOWN, 0x6f00);
+	ac97_write(codec, AC97_POWERDOWN, 0xffff);
+
+	return 0;
+}
+
+static int wm9713_soc_resume(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+	struct wm9713_priv *wm9713 = codec->private_data;
+	int i, ret;
+	u16 *cache = codec->reg_cache;
+
+	ret = wm9713_reset(codec, 1);
+	if (ret < 0) {
+		printk(KERN_ERR "could not reset AC97 codec\n");
+		return ret;
+	}
+
+	wm9713_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+
+	/* do we need to re-start the PLL ? */
+	if (wm9713->pll_out)
+		wm9713_set_pll(codec, 0, wm9713->pll_in, wm9713->pll_out);
+
+	/* only synchronise the codec if warm reset failed */
+	if (ret == 0) {
+		for (i = 2; i < ARRAY_SIZE(wm9713_reg) << 1; i += 2) {
+			if (i == AC97_POWERDOWN || i == AC97_EXTENDED_MID ||
+				i == AC97_EXTENDED_MSTATUS || i > 0x66)
+				continue;
+			soc_ac97_ops.write(codec->ac97, i, cache[i>>1]);
+		}
+	}
+
+	if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0)
+		wm9713_dapm_event(codec, SNDRV_CTL_POWER_D0);
+
+	return ret;
+}
+
+static int wm9713_soc_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec;
+	int ret = 0, reg;
+
+	printk(KERN_INFO "WM9713/WM9714 SoC Audio Codec %s\n", WM9713_VERSION);
+
+	socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+	if (socdev->codec == NULL)
+		return -ENOMEM;
+	codec = socdev->codec;
+	mutex_init(&codec->mutex);
+
+	codec->reg_cache = kmemdup(wm9713_reg, sizeof(wm9713_reg), GFP_KERNEL);
+	if (codec->reg_cache == NULL) {
+		ret = -ENOMEM;
+		goto cache_err;
+	}
+	codec->reg_cache_size = sizeof(wm9713_reg);
+	codec->reg_cache_step = 2;
+
+	codec->private_data = kzalloc(sizeof(struct wm9713_priv), GFP_KERNEL);
+	if (codec->private_data == NULL) {
+		ret = -ENOMEM;
+		goto priv_err;
+	}
+
+	codec->name = "WM9713";
+	codec->owner = THIS_MODULE;
+	codec->dai = wm9713_dai;
+	codec->num_dai = ARRAY_SIZE(wm9713_dai);
+	codec->write = ac97_write;
+	codec->read = ac97_read;
+	codec->dapm_event = wm9713_dapm_event;
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
+	if (ret < 0)
+		goto codec_err;
+
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0)
+		goto pcm_err;
+
+	/* do a cold reset for the controller and then try
+	 * a warm reset followed by an optional cold reset for codec */
+	wm9713_reset(codec, 0);
+	ret = wm9713_reset(codec, 1);
+	if (ret < 0) {
+		printk(KERN_ERR "AC97 link error\n");
+		goto reset_err;
+	}
+
+	wm9713_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+
+	/* unmute the adc - move to kcontrol */
+	reg = ac97_read(codec, AC97_CD) & 0x7fff;
+	ac97_write(codec, AC97_CD, reg);
+
+	wm9713_add_controls(codec);
+	wm9713_add_widgets(codec);
+	ret = snd_soc_register_card(socdev);
+	if (ret < 0)
+		goto reset_err;
+	return 0;
+
+reset_err:
+	snd_soc_free_pcms(socdev);
+
+pcm_err:
+	snd_soc_free_ac97_codec(codec);
+
+codec_err:
+	kfree(codec->private_data);
+
+priv_err:
+	kfree(codec->reg_cache);
+
+cache_err:
+	kfree(socdev->codec);
+	socdev->codec = NULL;
+	return ret;
+}
+
+static int wm9713_soc_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	if (codec == NULL)
+		return 0;
+
+	snd_soc_dapm_free(socdev);
+	snd_soc_free_pcms(socdev);
+	snd_soc_free_ac97_codec(codec);
+	kfree(codec->private_data);
+	kfree(codec->reg_cache);
+	kfree(codec->dai);
+	kfree(codec);
+	return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm9713 = {
+	.probe = 	wm9713_soc_probe,
+	.remove = 	wm9713_soc_remove,
+	.suspend =	wm9713_soc_suspend,
+	.resume = 	wm9713_soc_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm9713);
+
+MODULE_DESCRIPTION("ASoC WM9713/WM9714 driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm9713.h b/sound/soc/codecs/wm9713.h
new file mode 100644
index 0000000..d357b6c
--- /dev/null
+++ b/sound/soc/codecs/wm9713.h
@@ -0,0 +1,53 @@
+/*
+ * wm9713.h  --  WM9713 Soc Audio driver
+ */
+
+#ifndef _WM9713_H
+#define _WM9713_H
+
+/* clock inputs */
+#define WM9713_CLKA_PIN			0
+#define WM9713_CLKB_PIN			1
+
+/* clock divider ID's */
+#define WM9713_PCMCLK_DIV		0
+#define WM9713_CLKA_MULT		1
+#define WM9713_CLKB_MULT		2
+#define WM9713_HIFI_DIV			3
+#define WM9713_PCMBCLK_DIV		4
+#define WM9713_PCMCLK_PLL_DIV           5
+#define WM9713_HIFI_PLL_DIV             6
+
+/* Calculate the appropriate bit mask for the external PCM clock divider */
+#define WM9713_PCMDIV(x)	((x - 1) << 8)
+
+/* Calculate the appropriate bit mask for the external HiFi clock divider */
+#define WM9713_HIFIDIV(x)	((x - 1) << 12)
+
+/* MCLK clock mulitipliers */
+#define WM9713_CLKA_X1		(0 << 1)
+#define WM9713_CLKA_X2		(1 << 1)
+#define WM9713_CLKB_X1		(0 << 2)
+#define WM9713_CLKB_X2		(1 << 2)
+
+/* MCLK clock MUX */
+#define WM9713_CLK_MUX_A		(0 << 0)
+#define WM9713_CLK_MUX_B		(1 << 0)
+
+/* Voice DAI BCLK divider */
+#define WM9713_PCMBCLK_DIV_1	(0 << 9)
+#define WM9713_PCMBCLK_DIV_2	(1 << 9)
+#define WM9713_PCMBCLK_DIV_4	(2 << 9)
+#define WM9713_PCMBCLK_DIV_8	(3 << 9)
+#define WM9713_PCMBCLK_DIV_16	(4 << 9)
+
+#define WM9713_DAI_AC97_HIFI	0
+#define WM9713_DAI_AC97_AUX		1
+#define WM9713_DAI_PCM_VOICE	2
+
+extern struct snd_soc_codec_device soc_codec_dev_wm9713;
+extern struct snd_soc_codec_dai wm9713_dai[3];
+
+int wm9713_reset(struct snd_soc_codec *codec,  int try_warm);
+
+#endif
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig
new file mode 100644
index 0000000..20680c5
--- /dev/null
+++ b/sound/soc/davinci/Kconfig
@@ -0,0 +1,19 @@
+config SND_DAVINCI_SOC
+	tristate "SoC Audio for the TI DAVINCI chip"
+	depends on ARCH_DAVINCI && SND_SOC
+	help
+	  Say Y or M if you want to add support for codecs attached to
+	  the DAVINCI AC97 or I2S interface. You will also need
+	  to select the audio interfaces to support below.
+
+config SND_DAVINCI_SOC_I2S
+	tristate
+
+config SND_DAVINCI_SOC_EVM
+	tristate "SoC Audio support for DaVinci EVM"
+	depends on SND_DAVINCI_SOC && MACH_DAVINCI_EVM
+	select SND_DAVINCI_SOC_I2S
+	select SND_SOC_TLV320AIC3X
+	help
+	  Say Y if you want to add support for SoC audio on TI
+	  DaVinci EVM platform.
diff --git a/sound/soc/davinci/Makefile b/sound/soc/davinci/Makefile
new file mode 100644
index 0000000..ca772e5
--- /dev/null
+++ b/sound/soc/davinci/Makefile
@@ -0,0 +1,11 @@
+# DAVINCI Platform Support
+snd-soc-davinci-objs := davinci-pcm.o
+snd-soc-davinci-i2s-objs := davinci-i2s.o
+
+obj-$(CONFIG_SND_DAVINCI_SOC) += snd-soc-davinci.o
+obj-$(CONFIG_SND_DAVINCI_SOC_I2S) += snd-soc-davinci-i2s.o
+
+# DAVINCI Machine Support
+snd-soc-evm-objs := davinci-evm.o
+
+obj-$(CONFIG_SND_DAVINCI_SOC_EVM) += snd-soc-evm.o
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
new file mode 100644
index 0000000..fcd1652
--- /dev/null
+++ b/sound/soc/davinci/davinci-evm.c
@@ -0,0 +1,208 @@
+/*
+ * ASoC driver for TI DAVINCI EVM platform
+ *
+ * Author:      Vladimir Barinov, <vbarinov@ru.mvista.com>
+ * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <asm/dma.h>
+#include <asm/arch/hardware.h>
+
+#include "../codecs/tlv320aic3x.h"
+#include "davinci-pcm.h"
+#include "davinci-i2s.h"
+
+#define EVM_CODEC_CLOCK 22579200
+
+static int evm_hw_params(struct snd_pcm_substream *substream,
+			 struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+	int ret = 0;
+
+	/* set codec DAI configuration */
+	ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+					 SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0)
+		return ret;
+
+	/* set cpu DAI configuration */
+	ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM |
+				       SND_SOC_DAIFMT_IB_NF);
+	if (ret < 0)
+		return ret;
+
+	/* set the codec system clock */
+	ret = codec_dai->dai_ops.set_sysclk(codec_dai, 0, EVM_CODEC_CLOCK,
+					    SND_SOC_CLOCK_OUT);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_ops evm_ops = {
+	.hw_params = evm_hw_params,
+};
+
+/* davinci-evm machine dapm widgets */
+static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_LINE("Line Out", NULL),
+	SND_SOC_DAPM_MIC("Mic Jack", NULL),
+	SND_SOC_DAPM_LINE("Line In", NULL),
+};
+
+/* davinci-evm machine audio_mapnections to the codec pins */
+static const char *audio_map[][3] = {
+	/* Headphone connected to HPLOUT, HPROUT */
+	{"Headphone Jack", NULL, "HPLOUT"},
+	{"Headphone Jack", NULL, "HPROUT"},
+
+	/* Line Out connected to LLOUT, RLOUT */
+	{"Line Out", NULL, "LLOUT"},
+	{"Line Out", NULL, "RLOUT"},
+
+	/* Mic connected to (MIC3L | MIC3R) */
+	{"MIC3L", NULL, "Mic Bias 2V"},
+	{"MIC3R", NULL, "Mic Bias 2V"},
+	{"Mic Bias 2V", NULL, "Mic Jack"},
+
+	/* Line In connected to (LINE1L | LINE2L), (LINE1R | LINE2R) */
+	{"LINE1L", NULL, "Line In"},
+	{"LINE2L", NULL, "Line In"},
+	{"LINE1R", NULL, "Line In"},
+	{"LINE2R", NULL, "Line In"},
+
+	{NULL, NULL, NULL},
+};
+
+/* Logic for a aic3x as connected on a davinci-evm */
+static int evm_aic3x_init(struct snd_soc_codec *codec)
+{
+	int i;
+
+	/* Add davinci-evm specific widgets */
+	for (i = 0; i < ARRAY_SIZE(aic3x_dapm_widgets); i++)
+		snd_soc_dapm_new_control(codec, &aic3x_dapm_widgets[i]);
+
+	/* Set up davinci-evm specific audio path audio_map */
+	for (i = 0; audio_map[i][0] != NULL; i++)
+		snd_soc_dapm_connect_input(codec, audio_map[i][0],
+					   audio_map[i][1], audio_map[i][2]);
+
+	/* not connected */
+	snd_soc_dapm_set_endpoint(codec, "MONO_LOUT", 0);
+	snd_soc_dapm_set_endpoint(codec, "HPLCOM", 0);
+	snd_soc_dapm_set_endpoint(codec, "HPRCOM", 0);
+
+	/* always connected */
+	snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 1);
+	snd_soc_dapm_set_endpoint(codec, "Line Out", 1);
+	snd_soc_dapm_set_endpoint(codec, "Mic Jack", 1);
+	snd_soc_dapm_set_endpoint(codec, "Line In", 1);
+
+	snd_soc_dapm_sync_endpoints(codec);
+
+	return 0;
+}
+
+/* davinci-evm digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link evm_dai = {
+	.name = "TLV320AIC3X",
+	.stream_name = "AIC3X",
+	.cpu_dai = &davinci_i2s_dai,
+	.codec_dai = &aic3x_dai,
+	.init = evm_aic3x_init,
+	.ops = &evm_ops,
+};
+
+/* davinci-evm audio machine driver */
+static struct snd_soc_machine snd_soc_machine_evm = {
+	.name = "DaVinci EVM",
+	.dai_link = &evm_dai,
+	.num_links = 1,
+};
+
+/* evm audio private data */
+static struct aic3x_setup_data evm_aic3x_setup = {
+	.i2c_address = 0x1b,
+};
+
+/* evm audio subsystem */
+static struct snd_soc_device evm_snd_devdata = {
+	.machine = &snd_soc_machine_evm,
+	.platform = &davinci_soc_platform,
+	.codec_dev = &soc_codec_dev_aic3x,
+	.codec_data = &evm_aic3x_setup,
+};
+
+static struct resource evm_snd_resources[] = {
+	{
+		.start = DAVINCI_MCBSP_BASE,
+		.end = DAVINCI_MCBSP_BASE + SZ_8K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct evm_snd_platform_data evm_snd_data = {
+	.tx_dma_ch	= DM644X_DMACH_MCBSP_TX,
+	.rx_dma_ch	= DM644X_DMACH_MCBSP_RX,
+};
+
+static struct platform_device *evm_snd_device;
+
+static int __init evm_init(void)
+{
+	int ret;
+
+	evm_snd_device = platform_device_alloc("soc-audio", 0);
+	if (!evm_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(evm_snd_device, &evm_snd_devdata);
+	evm_snd_devdata.dev = &evm_snd_device->dev;
+	evm_snd_device->dev.platform_data = &evm_snd_data;
+
+	ret = platform_device_add_resources(evm_snd_device, evm_snd_resources,
+					    ARRAY_SIZE(evm_snd_resources));
+	if (ret) {
+		platform_device_put(evm_snd_device);
+		return ret;
+	}
+
+	ret = platform_device_add(evm_snd_device);
+	if (ret)
+		platform_device_put(evm_snd_device);
+
+	return ret;
+}
+
+static void __exit evm_exit(void)
+{
+	platform_device_unregister(evm_snd_device);
+}
+
+module_init(evm_init);
+module_exit(evm_exit);
+
+MODULE_AUTHOR("Vladimir Barinov");
+MODULE_DESCRIPTION("TI DAVINCI EVM ASoC driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c
new file mode 100644
index 0000000..c421774
--- /dev/null
+++ b/sound/soc/davinci/davinci-i2s.c
@@ -0,0 +1,407 @@
+/*
+ * ALSA SoC I2S (McBSP) Audio Layer for TI DAVINCI processor
+ *
+ * Author:      Vladimir Barinov, <vbarinov@ru.mvista.com>
+ * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include "davinci-pcm.h"
+
+#define DAVINCI_MCBSP_DRR_REG	0x00
+#define DAVINCI_MCBSP_DXR_REG	0x04
+#define DAVINCI_MCBSP_SPCR_REG	0x08
+#define DAVINCI_MCBSP_RCR_REG	0x0c
+#define DAVINCI_MCBSP_XCR_REG	0x10
+#define DAVINCI_MCBSP_SRGR_REG	0x14
+#define DAVINCI_MCBSP_PCR_REG	0x24
+
+#define DAVINCI_MCBSP_SPCR_RRST		(1 << 0)
+#define DAVINCI_MCBSP_SPCR_RINTM(v)	((v) << 4)
+#define DAVINCI_MCBSP_SPCR_XRST		(1 << 16)
+#define DAVINCI_MCBSP_SPCR_XINTM(v)	((v) << 20)
+#define DAVINCI_MCBSP_SPCR_GRST		(1 << 22)
+#define DAVINCI_MCBSP_SPCR_FRST		(1 << 23)
+#define DAVINCI_MCBSP_SPCR_FREE		(1 << 25)
+
+#define DAVINCI_MCBSP_RCR_RWDLEN1(v)	((v) << 5)
+#define DAVINCI_MCBSP_RCR_RFRLEN1(v)	((v) << 8)
+#define DAVINCI_MCBSP_RCR_RDATDLY(v)	((v) << 16)
+#define DAVINCI_MCBSP_RCR_RWDLEN2(v)	((v) << 21)
+
+#define DAVINCI_MCBSP_XCR_XWDLEN1(v)	((v) << 5)
+#define DAVINCI_MCBSP_XCR_XFRLEN1(v)	((v) << 8)
+#define DAVINCI_MCBSP_XCR_XDATDLY(v)	((v) << 16)
+#define DAVINCI_MCBSP_XCR_XFIG		(1 << 18)
+#define DAVINCI_MCBSP_XCR_XWDLEN2(v)	((v) << 21)
+
+#define DAVINCI_MCBSP_SRGR_FWID(v)	((v) << 8)
+#define DAVINCI_MCBSP_SRGR_FPER(v)	((v) << 16)
+#define DAVINCI_MCBSP_SRGR_FSGM		(1 << 28)
+
+#define DAVINCI_MCBSP_PCR_CLKRP		(1 << 0)
+#define DAVINCI_MCBSP_PCR_CLKXP		(1 << 1)
+#define DAVINCI_MCBSP_PCR_FSRP		(1 << 2)
+#define DAVINCI_MCBSP_PCR_FSXP		(1 << 3)
+#define DAVINCI_MCBSP_PCR_CLKRM		(1 << 8)
+#define DAVINCI_MCBSP_PCR_CLKXM		(1 << 9)
+#define DAVINCI_MCBSP_PCR_FSRM		(1 << 10)
+#define DAVINCI_MCBSP_PCR_FSXM		(1 << 11)
+
+#define MOD_REG_BIT(val, mask, set) do { \
+	if (set) { \
+		val |= mask; \
+	} else { \
+		val &= ~mask; \
+	} \
+} while (0)
+
+enum {
+	DAVINCI_MCBSP_WORD_8 = 0,
+	DAVINCI_MCBSP_WORD_12,
+	DAVINCI_MCBSP_WORD_16,
+	DAVINCI_MCBSP_WORD_20,
+	DAVINCI_MCBSP_WORD_24,
+	DAVINCI_MCBSP_WORD_32,
+};
+
+static struct davinci_pcm_dma_params davinci_i2s_pcm_out = {
+	.name = "I2S PCM Stereo out",
+};
+
+static struct davinci_pcm_dma_params davinci_i2s_pcm_in = {
+	.name = "I2S PCM Stereo in",
+};
+
+struct davinci_mcbsp_dev {
+	void __iomem			*base;
+	struct clk			*clk;
+	struct davinci_pcm_dma_params	*dma_params[2];
+};
+
+static inline void davinci_mcbsp_write_reg(struct davinci_mcbsp_dev *dev,
+					   int reg, u32 val)
+{
+	__raw_writel(val, dev->base + reg);
+}
+
+static inline u32 davinci_mcbsp_read_reg(struct davinci_mcbsp_dev *dev, int reg)
+{
+	return __raw_readl(dev->base + reg);
+}
+
+static void davinci_mcbsp_start(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data;
+	u32 w;
+
+	/* Start the sample generator and enable transmitter/receiver */
+	w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
+	MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_GRST, 1);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 1);
+	else
+		MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_RRST, 1);
+	davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
+
+	/* Start frame sync */
+	w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
+	MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_FRST, 1);
+	davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
+}
+
+static void davinci_mcbsp_stop(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data;
+	u32 w;
+
+	/* Reset transmitter/receiver and sample rate/frame sync generators */
+	w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
+	MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_GRST |
+		       DAVINCI_MCBSP_SPCR_FRST, 0);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 0);
+	else
+		MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_RRST, 0);
+	davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
+}
+
+static int davinci_i2s_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+	struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data;
+
+	cpu_dai->dma_data = dev->dma_params[substream->stream];
+
+	return 0;
+}
+
+static int davinci_i2s_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai,
+				   unsigned int fmt)
+{
+	struct davinci_mcbsp_dev *dev = cpu_dai->private_data;
+	u32 w;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG,
+					DAVINCI_MCBSP_PCR_FSXM |
+					DAVINCI_MCBSP_PCR_FSRM |
+					DAVINCI_MCBSP_PCR_CLKXM |
+					DAVINCI_MCBSP_PCR_CLKRM);
+		davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG,
+					DAVINCI_MCBSP_SRGR_FSGM);
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_IB_NF:
+		w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_PCR_REG);
+		MOD_REG_BIT(w, DAVINCI_MCBSP_PCR_CLKXP |
+			       DAVINCI_MCBSP_PCR_CLKRP, 1);
+		davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, w);
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_PCR_REG);
+		MOD_REG_BIT(w, DAVINCI_MCBSP_PCR_FSXP |
+			       DAVINCI_MCBSP_PCR_FSRP, 1);
+		davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, w);
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_PCR_REG);
+		MOD_REG_BIT(w, DAVINCI_MCBSP_PCR_CLKXP |
+			       DAVINCI_MCBSP_PCR_CLKRP |
+			       DAVINCI_MCBSP_PCR_FSXP |
+			       DAVINCI_MCBSP_PCR_FSRP, 1);
+		davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, w);
+		break;
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct davinci_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data;
+	struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data;
+	struct snd_interval *i = NULL;
+	int mcbsp_word_length;
+	u32 w;
+
+	/* general line settings */
+	davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG,
+				DAVINCI_MCBSP_SPCR_RINTM(3) |
+				DAVINCI_MCBSP_SPCR_XINTM(3) |
+				DAVINCI_MCBSP_SPCR_FREE);
+	davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG,
+				DAVINCI_MCBSP_RCR_RFRLEN1(1) |
+				DAVINCI_MCBSP_RCR_RDATDLY(1));
+	davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG,
+				DAVINCI_MCBSP_XCR_XFRLEN1(1) |
+				DAVINCI_MCBSP_XCR_XDATDLY(1) |
+				DAVINCI_MCBSP_XCR_XFIG);
+
+	i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
+	w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SRGR_REG);
+	MOD_REG_BIT(w, DAVINCI_MCBSP_SRGR_FWID(snd_interval_value(i) - 1), 1);
+	davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, w);
+
+	i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_FRAME_BITS);
+	w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SRGR_REG);
+	MOD_REG_BIT(w, DAVINCI_MCBSP_SRGR_FPER(snd_interval_value(i) - 1), 1);
+	davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, w);
+
+	/* Determine xfer data type */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:
+		dma_params->data_type = 1;
+		mcbsp_word_length = DAVINCI_MCBSP_WORD_8;
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+		dma_params->data_type = 2;
+		mcbsp_word_length = DAVINCI_MCBSP_WORD_16;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		dma_params->data_type = 4;
+		mcbsp_word_length = DAVINCI_MCBSP_WORD_32;
+		break;
+	default:
+		printk(KERN_WARNING "davinci-i2s: unsupported PCM format");
+		return -EINVAL;
+	}
+
+	w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_RCR_REG);
+	MOD_REG_BIT(w, DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) |
+		       DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length), 1);
+	davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, w);
+
+	w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_XCR_REG);
+	MOD_REG_BIT(w, DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) |
+		       DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length), 1);
+	davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, w);
+
+	return 0;
+}
+
+static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		davinci_mcbsp_start(substream);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		davinci_mcbsp_stop(substream);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int davinci_i2s_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_machine *machine = socdev->machine;
+	struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai;
+	struct davinci_mcbsp_dev *dev;
+	struct resource *mem, *ioarea;
+	struct evm_snd_platform_data *pdata;
+	int ret;
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem) {
+		dev_err(&pdev->dev, "no mem resource?\n");
+		return -ENODEV;
+	}
+
+	ioarea = request_mem_region(mem->start, (mem->end - mem->start) + 1,
+				    pdev->name);
+	if (!ioarea) {
+		dev_err(&pdev->dev, "McBSP region already claimed\n");
+		return -EBUSY;
+	}
+
+	dev = kzalloc(sizeof(struct davinci_mcbsp_dev), GFP_KERNEL);
+	if (!dev) {
+		ret = -ENOMEM;
+		goto err_release_region;
+	}
+
+	cpu_dai->private_data = dev;
+
+	dev->clk = clk_get(&pdev->dev, "McBSPCLK");
+	if (IS_ERR(dev->clk)) {
+		ret = -ENODEV;
+		goto err_free_mem;
+	}
+	clk_enable(dev->clk);
+
+	dev->base = (void __iomem *)IO_ADDRESS(mem->start);
+	pdata = pdev->dev.platform_data;
+
+	dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK] = &davinci_i2s_pcm_out;
+	dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK]->channel = pdata->tx_dma_ch;
+	dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK]->dma_addr =
+	    (dma_addr_t)(io_v2p(dev->base) + DAVINCI_MCBSP_DXR_REG);
+
+	dev->dma_params[SNDRV_PCM_STREAM_CAPTURE] = &davinci_i2s_pcm_in;
+	dev->dma_params[SNDRV_PCM_STREAM_CAPTURE]->channel = pdata->rx_dma_ch;
+	dev->dma_params[SNDRV_PCM_STREAM_CAPTURE]->dma_addr =
+	    (dma_addr_t)(io_v2p(dev->base) + DAVINCI_MCBSP_DRR_REG);
+
+	return 0;
+
+err_free_mem:
+	kfree(dev);
+err_release_region:
+	release_mem_region(mem->start, (mem->end - mem->start) + 1);
+
+	return ret;
+}
+
+static void davinci_i2s_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_machine *machine = socdev->machine;
+	struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai;
+	struct davinci_mcbsp_dev *dev = cpu_dai->private_data;
+	struct resource *mem;
+
+	clk_disable(dev->clk);
+	clk_put(dev->clk);
+	dev->clk = NULL;
+
+	kfree(dev);
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(mem->start, (mem->end - mem->start) + 1);
+}
+
+#define DAVINCI_I2S_RATES	SNDRV_PCM_RATE_8000_96000
+
+struct snd_soc_cpu_dai davinci_i2s_dai = {
+	.name = "davinci-i2s",
+	.id = 0,
+	.type = SND_SOC_DAI_I2S,
+	.probe = davinci_i2s_probe,
+	.remove = davinci_i2s_remove,
+	.playback = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = DAVINCI_I2S_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.capture = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = DAVINCI_I2S_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.ops = {
+		.startup = davinci_i2s_startup,
+		.trigger = davinci_i2s_trigger,
+		.hw_params = davinci_i2s_hw_params,},
+	.dai_ops = {
+		.set_fmt = davinci_i2s_set_dai_fmt,
+	},
+};
+EXPORT_SYMBOL_GPL(davinci_i2s_dai);
+
+MODULE_AUTHOR("Vladimir Barinov");
+MODULE_DESCRIPTION("TI DAVINCI I2S (McBSP) SoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/davinci/davinci-i2s.h b/sound/soc/davinci/davinci-i2s.h
new file mode 100644
index 0000000..9592d17
--- /dev/null
+++ b/sound/soc/davinci/davinci-i2s.h
@@ -0,0 +1,17 @@
+/*
+ * ALSA SoC I2S (McBSP) Audio Layer for TI DAVINCI processor
+ *
+ * Author:      Vladimir Barinov, <vbarinov@ru.mvista.com>
+ * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _DAVINCI_I2S_H
+#define _DAVINCI_I2S_H
+
+extern struct snd_soc_cpu_dai davinci_i2s_dai;
+
+#endif
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c
new file mode 100644
index 0000000..6a76927
--- /dev/null
+++ b/sound/soc/davinci/davinci-pcm.c
@@ -0,0 +1,389 @@
+/*
+ * ALSA PCM interface for the TI DAVINCI processor
+ *
+ * Author:      Vladimir Barinov, <vbarinov@ru.mvista.com>
+ * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/dma.h>
+
+#include "davinci-pcm.h"
+
+#define DAVINCI_PCM_DEBUG 0
+#if DAVINCI_PCM_DEBUG
+#define DPRINTK(x...) printk(KERN_DEBUG x)
+#else
+#define DPRINTK(x...)
+#endif
+
+static struct snd_pcm_hardware davinci_pcm_hardware = {
+	.info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+		 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+		 SNDRV_PCM_INFO_PAUSE),
+	.formats = (SNDRV_PCM_FMTBIT_S16_LE),
+	.rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+		  SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+		  SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+		  SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+		  SNDRV_PCM_RATE_KNOT),
+	.rate_min = 8000,
+	.rate_max = 96000,
+	.channels_min = 2,
+	.channels_max = 2,
+	.buffer_bytes_max = 128 * 1024,
+	.period_bytes_min = 32,
+	.period_bytes_max = 8 * 1024,
+	.periods_min = 16,
+	.periods_max = 255,
+	.fifo_size = 0,
+};
+
+struct davinci_runtime_data {
+	spinlock_t lock;
+	int period;		/* current DMA period */
+	int master_lch;		/* Master DMA channel */
+	int slave_lch;		/* Slave DMA channel */
+	struct davinci_pcm_dma_params *params;	/* DMA params */
+};
+
+static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
+{
+	struct davinci_runtime_data *prtd = substream->runtime->private_data;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int lch = prtd->slave_lch;
+	unsigned int period_size;
+	unsigned int dma_offset;
+	dma_addr_t dma_pos;
+	dma_addr_t src, dst;
+	unsigned short src_bidx, dst_bidx;
+	unsigned int data_type;
+	unsigned int count;
+
+	period_size = snd_pcm_lib_period_bytes(substream);
+	dma_offset = prtd->period * period_size;
+	dma_pos = runtime->dma_addr + dma_offset;
+
+	DPRINTK("audio_set_dma_params_play channel = %d dma_ptr = %x "
+		"period_size=%x\n", lch, dma_pos, period_size);
+
+	data_type = prtd->params->data_type;
+	count = period_size / data_type;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		src = dma_pos;
+		dst = prtd->params->dma_addr;
+		src_bidx = data_type;
+		dst_bidx = 0;
+	} else {
+		src = prtd->params->dma_addr;
+		dst = dma_pos;
+		src_bidx = 0;
+		dst_bidx = data_type;
+	}
+
+	davinci_set_dma_src_params(lch, src, INCR, W8BIT);
+	davinci_set_dma_dest_params(lch, dst, INCR, W8BIT);
+	davinci_set_dma_src_index(lch, src_bidx, 0);
+	davinci_set_dma_dest_index(lch, dst_bidx, 0);
+	davinci_set_dma_transfer_params(lch, data_type, count, 1, 0, ASYNC);
+
+	prtd->period++;
+	if (unlikely(prtd->period >= runtime->periods))
+		prtd->period = 0;
+}
+
+static void davinci_pcm_dma_irq(int lch, u16 ch_status, void *data)
+{
+	struct snd_pcm_substream *substream = data;
+	struct davinci_runtime_data *prtd = substream->runtime->private_data;
+
+	DPRINTK("lch=%d, status=0x%x\n", lch, ch_status);
+
+	if (unlikely(ch_status != DMA_COMPLETE))
+		return;
+
+	if (snd_pcm_running(substream)) {
+		snd_pcm_period_elapsed(substream);
+
+		spin_lock(&prtd->lock);
+		davinci_pcm_enqueue_dma(substream);
+		spin_unlock(&prtd->lock);
+	}
+}
+
+static int davinci_pcm_dma_request(struct snd_pcm_substream *substream)
+{
+	struct davinci_runtime_data *prtd = substream->runtime->private_data;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct davinci_pcm_dma_params *dma_data = rtd->dai->cpu_dai->dma_data;
+	int tcc = TCC_ANY;
+	int ret;
+
+	if (!dma_data)
+		return -ENODEV;
+
+	prtd->params = dma_data;
+
+	/* Request master DMA channel */
+	ret = davinci_request_dma(prtd->params->channel, prtd->params->name,
+				  davinci_pcm_dma_irq, substream,
+				  &prtd->master_lch, &tcc, EVENTQ_0);
+	if (ret)
+		return ret;
+
+	/* Request slave DMA channel */
+	ret = davinci_request_dma(PARAM_ANY, "Link",
+				  NULL, NULL, &prtd->slave_lch, &tcc, EVENTQ_0);
+	if (ret) {
+		davinci_free_dma(prtd->master_lch);
+		return ret;
+	}
+
+	/* Link slave DMA channel in loopback */
+	davinci_dma_link_lch(prtd->slave_lch, prtd->slave_lch);
+
+	return 0;
+}
+
+static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct davinci_runtime_data *prtd = substream->runtime->private_data;
+	int ret = 0;
+
+	spin_lock(&prtd->lock);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		davinci_start_dma(prtd->master_lch);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		davinci_stop_dma(prtd->master_lch);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	spin_unlock(&prtd->lock);
+
+	return ret;
+}
+
+static int davinci_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct davinci_runtime_data *prtd = substream->runtime->private_data;
+	struct paramentry_descriptor temp;
+
+	prtd->period = 0;
+	davinci_pcm_enqueue_dma(substream);
+
+	/* Get slave channel dma params for master channel startup */
+	davinci_get_dma_params(prtd->slave_lch, &temp);
+	davinci_set_dma_params(prtd->master_lch, &temp);
+
+	return 0;
+}
+
+static snd_pcm_uframes_t
+davinci_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct davinci_runtime_data *prtd = runtime->private_data;
+	unsigned int offset;
+	dma_addr_t count;
+	dma_addr_t src, dst;
+
+	spin_lock(&prtd->lock);
+
+	davinci_dma_getposition(prtd->master_lch, &src, &dst);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		count = src - runtime->dma_addr;
+	else
+		count = dst - runtime->dma_addr;;
+
+	spin_unlock(&prtd->lock);
+
+	offset = bytes_to_frames(runtime, count);
+	if (offset >= runtime->buffer_size)
+		offset = 0;
+
+	return offset;
+}
+
+static int davinci_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct davinci_runtime_data *prtd;
+	int ret = 0;
+
+	snd_soc_set_runtime_hwparams(substream, &davinci_pcm_hardware);
+
+	prtd = kzalloc(sizeof(struct davinci_runtime_data), GFP_KERNEL);
+	if (prtd == NULL)
+		return -ENOMEM;
+
+	spin_lock_init(&prtd->lock);
+
+	runtime->private_data = prtd;
+
+	ret = davinci_pcm_dma_request(substream);
+	if (ret) {
+		printk(KERN_ERR "davinci_pcm: Failed to get dma channels\n");
+		kfree(prtd);
+	}
+
+	return ret;
+}
+
+static int davinci_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct davinci_runtime_data *prtd = runtime->private_data;
+
+	davinci_dma_unlink_lch(prtd->slave_lch, prtd->slave_lch);
+
+	davinci_free_dma(prtd->slave_lch);
+	davinci_free_dma(prtd->master_lch);
+
+	kfree(prtd);
+
+	return 0;
+}
+
+static int davinci_pcm_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *hw_params)
+{
+	return snd_pcm_lib_malloc_pages(substream,
+					params_buffer_bytes(hw_params));
+}
+
+static int davinci_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static int davinci_pcm_mmap(struct snd_pcm_substream *substream,
+			    struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	return dma_mmap_writecombine(substream->pcm->card->dev, vma,
+				     runtime->dma_area,
+				     runtime->dma_addr,
+				     runtime->dma_bytes);
+}
+
+struct snd_pcm_ops davinci_pcm_ops = {
+	.open = 	davinci_pcm_open,
+	.close = 	davinci_pcm_close,
+	.ioctl = 	snd_pcm_lib_ioctl,
+	.hw_params = 	davinci_pcm_hw_params,
+	.hw_free = 	davinci_pcm_hw_free,
+	.prepare = 	davinci_pcm_prepare,
+	.trigger = 	davinci_pcm_trigger,
+	.pointer = 	davinci_pcm_pointer,
+	.mmap = 	davinci_pcm_mmap,
+};
+
+static int davinci_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+	size_t size = davinci_pcm_hardware.buffer_bytes_max;
+
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->private_data = NULL;
+	buf->area = dma_alloc_writecombine(pcm->card->dev, size,
+					   &buf->addr, GFP_KERNEL);
+
+	DPRINTK("preallocate_dma_buffer: area=%p, addr=%p, size=%d\n",
+		(void *) buf->area, (void *) buf->addr, size);
+
+	if (!buf->area)
+		return -ENOMEM;
+
+	buf->bytes = size;
+	return 0;
+}
+
+static void davinci_pcm_free(struct snd_pcm *pcm)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int stream;
+
+	for (stream = 0; stream < 2; stream++) {
+		substream = pcm->streams[stream].substream;
+		if (!substream)
+			continue;
+
+		buf = &substream->dma_buffer;
+		if (!buf->area)
+			continue;
+
+		dma_free_writecombine(pcm->card->dev, buf->bytes,
+				      buf->area, buf->addr);
+		buf->area = NULL;
+	}
+}
+
+static u64 davinci_pcm_dmamask = 0xffffffff;
+
+static int davinci_pcm_new(struct snd_card *card,
+			   struct snd_soc_codec_dai *dai, struct snd_pcm *pcm)
+{
+	int ret;
+
+	if (!card->dev->dma_mask)
+		card->dev->dma_mask = &davinci_pcm_dmamask;
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = 0xffffffff;
+
+	if (dai->playback.channels_min) {
+		ret = davinci_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_PLAYBACK);
+		if (ret)
+			return ret;
+	}
+
+	if (dai->capture.channels_min) {
+		ret = davinci_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_CAPTURE);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+struct snd_soc_platform davinci_soc_platform = {
+	.name = 	"davinci-audio",
+	.pcm_ops = 	&davinci_pcm_ops,
+	.pcm_new = 	davinci_pcm_new,
+	.pcm_free = 	davinci_pcm_free,
+};
+EXPORT_SYMBOL_GPL(davinci_soc_platform);
+
+MODULE_AUTHOR("Vladimir Barinov");
+MODULE_DESCRIPTION("TI DAVINCI PCM DMA module");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h
new file mode 100644
index 0000000..8d6a45e
--- /dev/null
+++ b/sound/soc/davinci/davinci-pcm.h
@@ -0,0 +1,29 @@
+/*
+ * ALSA PCM interface for the TI DAVINCI processor
+ *
+ * Author:      Vladimir Barinov, <vbarinov@ru.mvista.com>
+ * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _DAVINCI_PCM_H
+#define _DAVINCI_PCM_H
+
+struct davinci_pcm_dma_params {
+	char *name;		/* stream identifier */
+	int channel;		/* sync dma channel ID */
+	dma_addr_t dma_addr;	/* device physical address for DMA */
+	unsigned int data_type;	/* xfer data type */
+};
+
+struct evm_snd_platform_data {
+	int tx_dma_ch;
+	int rx_dma_ch;
+};
+
+extern struct snd_soc_platform davinci_soc_platform;
+
+#endif
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index 652514f..78de716 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -20,7 +20,6 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 145ad13..b2a11b0 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -15,7 +15,6 @@
 #include <linux/device.h>
 #include <linux/delay.h>
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c
index 1a70a6a..7f32a11 100644
--- a/sound/soc/pxa/corgi.c
+++ b/sound/soc/pxa/corgi.c
@@ -297,21 +297,19 @@
 	/* Add corgi specific controls */
 	for (i = 0; i < ARRAY_SIZE(wm8731_corgi_controls); i++) {
 		err = snd_ctl_add(codec->card,
-			snd_soc_cnew(&wm8731_corgi_controls[i],codec, NULL));
+			snd_soc_cnew(&wm8731_corgi_controls[i], codec, NULL));
 		if (err < 0)
 			return err;
 	}
 
 	/* Add corgi specific widgets */
-	for(i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++) {
+	for (i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++)
 		snd_soc_dapm_new_control(codec, &wm8731_dapm_widgets[i]);
-	}
 
 	/* Set up corgi specific audio path audio_map */
-	for(i = 0; audio_map[i][0] != NULL; i++) {
+	for (i = 0; audio_map[i][0] != NULL; i++)
 		snd_soc_dapm_connect_input(codec, audio_map[i][0],
 			audio_map[i][1], audio_map[i][2]);
-	}
 
 	snd_soc_dapm_sync_endpoints(codec);
 	return 0;
@@ -353,7 +351,8 @@
 {
 	int ret;
 
-	if (!(machine_is_corgi() || machine_is_shepherd() || machine_is_husky()))
+	if (!(machine_is_corgi() || machine_is_shepherd() ||
+	      machine_is_husky()))
 		return -ENODEV;
 
 	corgi_snd_device = platform_device_alloc("soc-audio", -1);
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c
index 4fbf8bb..7e830b2 100644
--- a/sound/soc/pxa/poodle.c
+++ b/sound/soc/pxa/poodle.c
@@ -257,21 +257,19 @@
 	/* Add poodle specific controls */
 	for (i = 0; i < ARRAY_SIZE(wm8731_poodle_controls); i++) {
 		err = snd_ctl_add(codec->card,
-			snd_soc_cnew(&wm8731_poodle_controls[i],codec, NULL));
+			snd_soc_cnew(&wm8731_poodle_controls[i], codec, NULL));
 		if (err < 0)
 			return err;
 	}
 
 	/* Add poodle specific widgets */
-	for (i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++) {
+	for (i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++)
 		snd_soc_dapm_new_control(codec, &wm8731_dapm_widgets[i]);
-	}
 
 	/* Set up poodle specific audio path audio_map */
-	for (i = 0; audio_map[i][0] != NULL; i++) {
+	for (i = 0; audio_map[i][0] != NULL; i++)
 		snd_soc_dapm_connect_input(codec, audio_map[i][0],
 			audio_map[i][1], audio_map[i][2]);
-	}
 
 	snd_soc_dapm_sync_endpoints(codec);
 	return 0;
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c
index e173799..97ec2d9 100644
--- a/sound/soc/pxa/pxa2xx-ac97.c
+++ b/sound/soc/pxa/pxa2xx-ac97.c
@@ -61,7 +61,7 @@
 	mutex_lock(&car_mutex);
 
 	/* set up primary or secondary codec/modem space */
-#ifdef CONFIG_PXA27x
+#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
 	reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE;
 #else
 	if (reg == AC97_GPIO_STATUS)
@@ -87,7 +87,7 @@
 	wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1);
 	if (!((GSR | gsr_bits) & GSR_SDONE)) {
 		printk(KERN_ERR "%s: read error (ac97_reg=%x GSR=%#lx)\n",
-				__FUNCTION__, reg, GSR | gsr_bits);
+				__func__, reg, GSR | gsr_bits);
 		val = -1;
 		goto out;
 	}
@@ -111,7 +111,7 @@
 	mutex_lock(&car_mutex);
 
 	/* set up primary or secondary codec/modem space */
-#ifdef CONFIG_PXA27x
+#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
 	reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE;
 #else
 	if (reg == AC97_GPIO_STATUS)
@@ -127,13 +127,16 @@
 	wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_CDONE, 1);
 	if (!((GSR | gsr_bits) & GSR_CDONE))
 		printk(KERN_ERR "%s: write error (ac97_reg=%x GSR=%#lx)\n",
-				__FUNCTION__, reg, GSR | gsr_bits);
+				__func__, reg, GSR | gsr_bits);
 
 	mutex_unlock(&car_mutex);
 }
 
 static void pxa2xx_ac97_warm_reset(struct snd_ac97 *ac97)
 {
+#ifdef CONFIG_PXA3xx
+	int timeout = 100;
+#endif
 	gsr_bits = 0;
 
 #ifdef CONFIG_PXA27x
@@ -144,6 +147,11 @@
 	GCR |= GCR_WARM_RST;
 	pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
 	udelay(500);
+#elif defined(CONFIG_PXA3xx)
+	/* Can't use interrupts */
+	GCR |= GCR_WARM_RST;
+	while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--)
+		mdelay(1);
 #else
 	GCR |= GCR_WARM_RST | GCR_PRIRDY_IEN | GCR_SECRDY_IEN;
 	wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
@@ -151,7 +159,7 @@
 
 	if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)))
 		printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n",
-				 __FUNCTION__, gsr_bits);
+				 __func__, gsr_bits);
 
 	GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
 	GCR |= GCR_SDONE_IE|GCR_CDONE_IE;
@@ -159,6 +167,16 @@
 
 static void pxa2xx_ac97_cold_reset(struct snd_ac97 *ac97)
 {
+#ifdef CONFIG_PXA3xx
+	int timeout = 1000;
+
+	/* Hold CLKBPB for 100us */
+	GCR = 0;
+	GCR = GCR_CLKBPB;
+	udelay(100);
+	GCR = 0;
+#endif
+
 	GCR &=  GCR_COLD_RST;  /* clear everything but nCRST */
 	GCR &= ~GCR_COLD_RST;  /* then assert nCRST */
 
@@ -170,6 +188,13 @@
 	clk_disable(ac97conf_clk);
 	GCR = GCR_COLD_RST;
 	udelay(50);
+#elif defined(CONFIG_PXA3xx)
+	/* Can't use interrupts on PXA3xx */
+	GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
+
+	GCR = GCR_WARM_RST | GCR_COLD_RST;
+	while (!(GSR & (GSR_PCR | GSR_SCR)) && timeout--)
+		mdelay(10);
 #else
 	GCR = GCR_COLD_RST;
 	GCR |= GCR_CDONE_IE|GCR_SDONE_IE;
@@ -178,7 +203,7 @@
 
 	if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)))
 		printk(KERN_INFO "%s: cold reset timeout (GSR=%#lx)\n",
-				 __FUNCTION__, gsr_bits);
+				 __func__, gsr_bits);
 
 	GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
 	GCR |= GCR_SDONE_IE|GCR_CDONE_IE;
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c
index daeaa4c..01ad7bf 100644
--- a/sound/soc/pxa/pxa2xx-pcm.c
+++ b/sound/soc/pxa/pxa2xx-pcm.c
@@ -64,8 +64,8 @@
 	if (dcsr & DCSR_ENDINTR) {
 		snd_pcm_period_elapsed(substream);
 	} else {
-		printk( KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n",
-			prtd->params->name, dma_ch, dcsr );
+		printk(KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n",
+			prtd->params->name, dma_ch, dcsr);
 	}
 }
 
@@ -84,8 +84,8 @@
 
 	/* return if this is a bufferless transfer e.g.
 	 * codec <--> BT codec or GSM modem -- lg FIXME */
-	 if (!dma)
-	 	return 0;
+	if (!dma)
+		return 0;
 
 	/* this may get called several times by oss emulation
 	 * with different params */
@@ -363,7 +363,6 @@
 	.pcm_new	= pxa2xx_pcm_new,
 	.pcm_free	= pxa2xx_pcm_free_dma_buffers,
 };
-
 EXPORT_SYMBOL_GPL(pxa2xx_soc_platform);
 
 MODULE_AUTHOR("Nicolas Pitre");
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c
index ecca390..d8b8372 100644
--- a/sound/soc/pxa/spitz.c
+++ b/sound/soc/pxa/spitz.c
@@ -313,15 +313,13 @@
 	}
 
 	/* Add spitz specific widgets */
-	for (i = 0; i < ARRAY_SIZE(wm8750_dapm_widgets); i++) {
+	for (i = 0; i < ARRAY_SIZE(wm8750_dapm_widgets); i++)
 		snd_soc_dapm_new_control(codec, &wm8750_dapm_widgets[i]);
-	}
 
 	/* Set up spitz specific audio path audio_map */
-	for (i = 0; audio_map[i][0] != NULL; i++) {
+	for (i = 0; audio_map[i][0] != NULL; i++)
 		snd_soc_dapm_connect_input(codec, audio_map[i][0],
 			audio_map[i][1], audio_map[i][2]);
-	}
 
 	snd_soc_dapm_sync_endpoints(codec);
 	return 0;
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c
index 6ee115c..962cc20 100644
--- a/sound/soc/s3c24xx/neo1973_wm8753.c
+++ b/sound/soc/s3c24xx/neo1973_wm8753.c
@@ -659,6 +659,7 @@
 
 static void __exit neo1973_exit(void)
 {
+	i2c_del_driver(&lm4857_i2c_driver);
 	platform_device_unregister(neo1973_snd_device);
 }
 
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c
index 0a3c630..4ebcd6a 100644
--- a/sound/soc/s3c24xx/s3c24xx-i2s.c
+++ b/sound/soc/s3c24xx/s3c24xx-i2s.c
@@ -25,6 +25,7 @@
 #include <linux/delay.h>
 #include <linux/clk.h>
 #include <linux/jiffies.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -32,7 +33,6 @@
 #include <sound/soc.h>
 
 #include <asm/hardware.h>
-#include <asm/io.h>
 #include <asm/arch/regs-gpio.h>
 #include <asm/arch/regs-clock.h>
 #include <asm/arch/audio.h>
@@ -46,7 +46,7 @@
 
 #define S3C24XX_I2S_DEBUG 0
 #if S3C24XX_I2S_DEBUG
-#define DBG(x...) printk(KERN_DEBUG x)
+#define DBG(x...) printk(KERN_DEBUG "s3c24xx-i2s: " x)
 #else
 #define DBG(x...)
 #endif
@@ -89,7 +89,7 @@
 	u32 iiscon;
 	u32 iismod;
 
-	DBG("Entered %s\n", __FUNCTION__);
+	DBG("Entered %s\n", __func__);
 
 	iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
 	iiscon  = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
@@ -134,7 +134,7 @@
 	u32 iiscon;
 	u32 iismod;
 
-	DBG("Entered %s\n", __FUNCTION__);
+	DBG("Entered %s\n", __func__);
 
 	iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
 	iiscon  = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
@@ -159,10 +159,10 @@
 		 * DMA engine will simply freeze randomly.
 		 */
 
-        iisfcon &= ~S3C2410_IISFCON_RXENABLE;
-        iisfcon &= ~S3C2410_IISFCON_RXDMA;
-        iiscon  |= S3C2410_IISCON_RXIDLE;
-        iiscon  &= ~S3C2410_IISCON_RXDMAEN;
+		iisfcon &= ~S3C2410_IISFCON_RXENABLE;
+		iisfcon &= ~S3C2410_IISFCON_RXDMA;
+		iiscon  |= S3C2410_IISCON_RXIDLE;
+		iiscon  &= ~S3C2410_IISCON_RXDMAEN;
 		iismod  &= ~S3C2410_IISMOD_RXMODE;
 
 		writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
@@ -182,7 +182,7 @@
 	u32 iiscon;
 	unsigned long timeout = jiffies + msecs_to_jiffies(5);
 
-	DBG("Entered %s\n", __FUNCTION__);
+	DBG("Entered %s\n", __func__);
 
 	while (1) {
 		iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
@@ -201,7 +201,7 @@
  */
 static inline int s3c24xx_snd_is_clkmaster(void)
 {
-	DBG("Entered %s\n", __FUNCTION__);
+	DBG("Entered %s\n", __func__);
 
 	return (readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & S3C2410_IISMOD_SLAVE) ? 0:1;
 }
@@ -214,7 +214,7 @@
 {
 	u32 iismod;
 
-	DBG("Entered %s\n", __FUNCTION__);
+	DBG("Entered %s\n", __func__);
 
 	iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
 	DBG("hw_params r: IISMOD: %lx \n", iismod);
@@ -250,7 +250,7 @@
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	u32 iismod;
 
-	DBG("Entered %s\n", __FUNCTION__);
+	DBG("Entered %s\n", __func__);
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		rtd->dai->cpu_dai->dma_data = &s3c24xx_i2s_pcm_stereo_out;
@@ -278,7 +278,7 @@
 {
 	int ret = 0;
 
-	DBG("Entered %s\n", __FUNCTION__);
+	DBG("Entered %s\n", __func__);
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
@@ -320,7 +320,7 @@
 {
 	u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
 
-	DBG("Entered %s\n", __FUNCTION__);
+	DBG("Entered %s\n", __func__);
 
 	iismod &= ~S3C2440_IISMOD_MPLL;
 
@@ -346,7 +346,7 @@
 {
 	u32 reg;
 
-	DBG("Entered %s\n", __FUNCTION__);
+	DBG("Entered %s\n", __func__);
 
 	switch (div_id) {
 	case S3C24XX_DIV_BCLK:
@@ -381,13 +381,13 @@
 
 static int s3c24xx_i2s_probe(struct platform_device *pdev)
 {
-	DBG("Entered %s\n", __FUNCTION__);
+	DBG("Entered %s\n", __func__);
 
 	s3c24xx_i2s.regs = ioremap(S3C2410_PA_IIS, 0x100);
 	if (s3c24xx_i2s.regs == NULL)
 		return -ENXIO;
 
-	s3c24xx_i2s.iis_clk=clk_get(&pdev->dev, "iis");
+	s3c24xx_i2s.iis_clk = clk_get(&pdev->dev, "iis");
 	if (s3c24xx_i2s.iis_clk == NULL) {
 		DBG("failed to get iis_clock\n");
 		iounmap(s3c24xx_i2s.regs);
@@ -411,9 +411,11 @@
 }
 
 #ifdef CONFIG_PM
-int s3c24xx_i2s_suspend(struct platform_device *pdev,
+static int s3c24xx_i2s_suspend(struct platform_device *pdev,
 		struct snd_soc_cpu_dai *cpu_dai)
 {
+	DBG("Entered %s\n", __func__);
+
 	s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
 	s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
 	s3c24xx_i2s.iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
@@ -424,9 +426,10 @@
 	return 0;
 }
 
-int s3c24xx_i2s_resume(struct platform_device *pdev,
+static int s3c24xx_i2s_resume(struct platform_device *pdev,
 		struct snd_soc_cpu_dai *cpu_dai)
 {
+	DBG("Entered %s\n", __func__);
 	clk_enable(s3c24xx_i2s.iis_clk);
 
 	writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c
index 29a6c82f..49580fb 100644
--- a/sound/soc/s3c24xx/s3c24xx-pcm.c
+++ b/sound/soc/s3c24xx/s3c24xx-pcm.c
@@ -39,7 +39,7 @@
 
 #define S3C24XX_PCM_DEBUG 0
 #if S3C24XX_PCM_DEBUG
-#define DBG(x...) printk(KERN_DEBUG x)
+#define DBG(x...) printk(KERN_DEBUG "s3c24xx-pcm: " x)
 #else
 #define DBG(x...)
 #endif
@@ -88,7 +88,7 @@
 	dma_addr_t pos = prtd->dma_pos;
 	int ret;
 
-	DBG("Entered %s\n", __FUNCTION__);
+	DBG("Entered %s\n", __func__);
 
 	while (prtd->dma_loaded < prtd->dma_limit) {
 		unsigned long len = prtd->dma_period;
@@ -98,7 +98,7 @@
 		if ((pos + len) > prtd->dma_end) {
 			len  = prtd->dma_end - pos;
 			DBG(KERN_DEBUG "%s: corrected dma len %ld\n",
-			       __FUNCTION__, len);
+			       __func__, len);
 		}
 
 		ret = s3c2410_dma_enqueue(prtd->params->channel, 
@@ -123,7 +123,7 @@
 	struct snd_pcm_substream *substream = dev_id;
 	struct s3c24xx_runtime_data *prtd;
 
-	DBG("Entered %s\n", __FUNCTION__);
+	DBG("Entered %s\n", __func__);
 
 	if (result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR)
 		return;
@@ -152,7 +152,7 @@
 	unsigned long totbytes = params_buffer_bytes(params);
 	int ret=0;
 
-	DBG("Entered %s\n", __FUNCTION__);
+	DBG("Entered %s\n", __func__);
 
 	/* return if this is a bufferless transfer e.g.
 	 * codec <--> BT codec or GSM modem -- lg FIXME */
@@ -200,7 +200,7 @@
 {
 	struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
 
-	DBG("Entered %s\n", __FUNCTION__);
+	DBG("Entered %s\n", __func__);
 
 	/* TODO - do we need to ensure DMA flushed */
 	snd_pcm_set_runtime_buffer(substream, NULL);
@@ -218,7 +218,7 @@
 	struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
 	int ret = 0;
 
-	DBG("Entered %s\n", __FUNCTION__);
+	DBG("Entered %s\n", __func__);
 
 	/* return if this is a bufferless transfer e.g.
 	 * codec <--> BT codec or GSM modem -- lg FIXME */
@@ -263,7 +263,7 @@
 	struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
 	int ret = 0;
 
-	DBG("Entered %s\n", __FUNCTION__);
+	DBG("Entered %s\n", __func__);
 
 	spin_lock(&prtd->lock);
 
@@ -301,7 +301,7 @@
 	unsigned long res;
 	dma_addr_t src, dst;
 
-	DBG("Entered %s\n", __FUNCTION__);
+	DBG("Entered %s\n", __func__);
 
 	spin_lock(&prtd->lock);
 	s3c2410_dma_getposition(prtd->params->channel, &src, &dst);
@@ -334,7 +334,7 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct s3c24xx_runtime_data *prtd;
 
-	DBG("Entered %s\n", __FUNCTION__);
+	DBG("Entered %s\n", __func__);
 
 	snd_soc_set_runtime_hwparams(substream, &s3c24xx_pcm_hardware);
 
@@ -353,7 +353,7 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct s3c24xx_runtime_data *prtd = runtime->private_data;
 
-	DBG("Entered %s\n", __FUNCTION__);
+	DBG("Entered %s\n", __func__);
 
 	if (prtd)
 		kfree(prtd);
@@ -368,7 +368,7 @@
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 
-	DBG("Entered %s\n", __FUNCTION__);
+	DBG("Entered %s\n", __func__);
 
 	return dma_mmap_writecombine(substream->pcm->card->dev, vma,
                                      runtime->dma_area,
@@ -394,7 +394,7 @@
 	struct snd_dma_buffer *buf = &substream->dma_buffer;
 	size_t size = s3c24xx_pcm_hardware.buffer_bytes_max;
 
-	DBG("Entered %s\n", __FUNCTION__);
+	DBG("Entered %s\n", __func__);
 
 	buf->dev.type = SNDRV_DMA_TYPE_DEV;
 	buf->dev.dev = pcm->card->dev;
@@ -413,7 +413,7 @@
 	struct snd_dma_buffer *buf;
 	int stream;
 
-	DBG("Entered %s\n", __FUNCTION__);
+	DBG("Entered %s\n", __func__);
 
 	for (stream = 0; stream < 2; stream++) {
 		substream = pcm->streams[stream].substream;
@@ -437,7 +437,7 @@
 {
 	int ret = 0;
 
-	DBG("Entered %s\n", __FUNCTION__);
+	DBG("Entered %s\n", __func__);
 
 	if (!card->dev->dma_mask)
 		card->dev->dma_mask = &s3c24xx_pcm_dmamask;
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
index f03220d2..4c1e013 100644
--- a/sound/soc/sh/Kconfig
+++ b/sound/soc/sh/Kconfig
@@ -1,4 +1,5 @@
 menu "SoC Audio support for SuperH"
+	depends on SUPERH
 
 config SND_SOC_PCM_SH7760
 	tristate "SoC Audio support for Renesas SH7760"
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 9eb5479..e148db9 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -839,6 +839,7 @@
 static struct platform_driver soc_driver = {
 	.driver		= {
 		.name		= "soc-audio",
+		.owner		= THIS_MODULE,
 	},
 	.probe		= soc_probe,
 	.remove		= soc_remove,
@@ -1601,3 +1602,4 @@
 MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
 MODULE_DESCRIPTION("ALSA SoC Core");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:soc-audio");
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 620d7ea..af3326c 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -226,7 +226,7 @@
 		snd_soc_write(codec, widget->reg, new);
 		pop_wait(POP_TIME);
 	}
-	dbg("reg old %x new %x change %d\n", old, new, change);
+	dbg("reg %x old %x new %x change %d\n", widget->reg, old, new, change);
 	return change;
 }
 
@@ -1288,7 +1288,7 @@
 	mutex_unlock(&codec->mutex);
 
 	dapm_power_widgets(codec, event);
-	dump_dapm(codec, __FUNCTION__);
+	dump_dapm(codec, __func__);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event);
@@ -1334,10 +1334,11 @@
 	list_for_each_entry(w, &codec->dapm_widgets, list) {
 		if (!strcmp(w->name, endpoint)) {
 			w->connected = status;
+			return 0;
 		}
 	}
 
-	return 0;
+	return -ENODEV;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_set_endpoint);
 
diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c
index 89d6e9c..09802e8 100644
--- a/sound/spi/at73c213.c
+++ b/sound/spi/at73c213.c
@@ -118,7 +118,7 @@
 	.rates		= SNDRV_PCM_RATE_CONTINUOUS,
 	.rate_min	= 8000,  /* Replaced by chip->bitrate later. */
 	.rate_max	= 50000, /* Replaced by chip->bitrate later. */
-	.channels_min	= 2,
+	.channels_min	= 1,
 	.channels_max	= 2,
 	.buffer_bytes_max = 64 * 1024 - 1,
 	.period_bytes_min = 512,
@@ -133,7 +133,8 @@
 static int snd_at73c213_set_bitrate(struct snd_at73c213 *chip)
 {
 	unsigned long ssc_rate = clk_get_rate(chip->ssc->clk);
-	unsigned long dac_rate_new, ssc_div, status;
+	unsigned long dac_rate_new, ssc_div;
+	int status;
 	unsigned long ssc_div_max, ssc_div_min;
 	int max_tries;
 
@@ -209,7 +210,13 @@
 {
 	struct snd_at73c213 *chip = snd_pcm_substream_chip(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
+	int err;
 
+	/* ensure buffer_size is a multiple of period_size */
+	err = snd_pcm_hw_constraint_integer(runtime,
+					SNDRV_PCM_HW_PARAM_PERIODS);
+	if (err < 0)
+		return err;
 	snd_at73c213_playback_hw.rate_min = chip->bitrate;
 	snd_at73c213_playback_hw.rate_max = chip->bitrate;
 	runtime->hw = snd_at73c213_playback_hw;
@@ -228,6 +235,14 @@
 static int snd_at73c213_pcm_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_pcm_hw_params *hw_params)
 {
+	struct snd_at73c213 *chip = snd_pcm_substream_chip(substream);
+	int channels = params_channels(hw_params);
+	int val;
+
+	val = ssc_readl(chip->ssc->regs, TFMR);
+	val = SSC_BFINS(TFMR_DATNB, channels - 1, val);
+	ssc_writel(chip->ssc->regs, TFMR, val);
+
 	return snd_pcm_lib_malloc_pages(substream,
 					params_buffer_bytes(hw_params));
 }
@@ -249,10 +264,12 @@
 
 	ssc_writel(chip->ssc->regs, PDC_TPR,
 			(long)runtime->dma_addr);
-	ssc_writel(chip->ssc->regs, PDC_TCR, runtime->period_size * 2);
+	ssc_writel(chip->ssc->regs, PDC_TCR,
+			runtime->period_size * runtime->channels);
 	ssc_writel(chip->ssc->regs, PDC_TNPR,
 			(long)runtime->dma_addr + block_size);
-	ssc_writel(chip->ssc->regs, PDC_TNCR, runtime->period_size * 2);
+	ssc_writel(chip->ssc->regs, PDC_TNCR,
+			runtime->period_size * runtime->channels);
 
 	return 0;
 }
@@ -314,15 +331,6 @@
 	.pointer	= snd_at73c213_pcm_pointer,
 };
 
-static void snd_at73c213_pcm_free(struct snd_pcm *pcm)
-{
-	struct snd_at73c213 *chip = snd_pcm_chip(pcm);
-	if (chip->pcm) {
-		snd_pcm_lib_preallocate_free_for_all(chip->pcm);
-		chip->pcm = NULL;
-	}
-}
-
 static int __devinit snd_at73c213_pcm_new(struct snd_at73c213 *chip, int device)
 {
 	struct snd_pcm *pcm;
@@ -334,7 +342,6 @@
 		goto out;
 
 	pcm->private_data = chip;
-	pcm->private_free = snd_at73c213_pcm_free;
 	pcm->info_flags = SNDRV_PCM_INFO_BLOCK_TRANSFER;
 	strcpy(pcm->name, "at73c213");
 	chip->pcm = pcm;
@@ -375,7 +382,8 @@
 
 		ssc_writel(chip->ssc->regs, PDC_TNPR,
 				(long)runtime->dma_addr + offset);
-		ssc_writel(chip->ssc->regs, PDC_TNCR, runtime->period_size * 2);
+		ssc_writel(chip->ssc->regs, PDC_TNCR,
+				runtime->period_size * runtime->channels);
 		retval = IRQ_HANDLED;
 	}
 
@@ -737,7 +745,7 @@
 /*
  * Device functions
  */
-static int snd_at73c213_ssc_init(struct snd_at73c213 *chip)
+static int __devinit snd_at73c213_ssc_init(struct snd_at73c213 *chip)
 {
 	/*
 	 * Continuous clock output.
@@ -767,7 +775,7 @@
 	return 0;
 }
 
-static int snd_at73c213_chip_init(struct snd_at73c213 *chip)
+static int __devinit snd_at73c213_chip_init(struct snd_at73c213 *chip)
 {
 	int retval;
 	unsigned char dac_ctrl = 0;
@@ -933,7 +941,7 @@
 	return retval;
 }
 
-static int snd_at73c213_probe(struct spi_device *spi)
+static int __devinit snd_at73c213_probe(struct spi_device *spi)
 {
 	struct snd_card			*card;
 	struct snd_at73c213		*chip;
diff --git a/sound/usb/caiaq/caiaq-audio.c b/sound/usb/caiaq/caiaq-audio.c
index 9cc4cd8..24970a5 100644
--- a/sound/usb/caiaq/caiaq-audio.c
+++ b/sound/usb/caiaq/caiaq-audio.c
@@ -1,5 +1,5 @@
 /*
- *   Copyright (c) 2006,2007 Daniel Mack, Karsten Wiese
+ *   Copyright (c) 2006-2008 Daniel Mack, Karsten Wiese
  *
  *   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
@@ -39,7 +39,8 @@
 #define BYTES_PER_SAMPLE	3
 #define BYTES_PER_SAMPLE_USB	4
 #define MAX_BUFFER_SIZE		(128*1024)
-				 
+#define MAX_ENDPOINT_SIZE	512
+
 #define ENDPOINT_CAPTURE	2
 #define ENDPOINT_PLAYBACK	6
 
@@ -77,10 +78,15 @@
 deactivate_substream(struct snd_usb_caiaqdev *dev,
 		     struct snd_pcm_substream *sub)
 {
+	unsigned long flags;
+	spin_lock_irqsave(&dev->spinlock, flags);
+
 	if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		dev->sub_playback[sub->number] = NULL;
 	else
 		dev->sub_capture[sub->number] = NULL;
+
+	spin_unlock_irqrestore(&dev->spinlock, flags);
 }
 
 static int
@@ -97,13 +103,13 @@
 {
 	int i, ret;
 
-	debug("stream_start(%p)\n", dev);
-	spin_lock_irq(&dev->spinlock);
-	if (dev->streaming) {
-		spin_unlock_irq(&dev->spinlock);
-		return -EINVAL;
-	}
+	debug("%s(%p)\n", __func__, dev);
 
+	if (dev->streaming)
+		return -EINVAL;
+
+	memset(dev->sub_playback, 0, sizeof(dev->sub_playback));
+	memset(dev->sub_capture, 0, sizeof(dev->sub_capture));
 	dev->input_panic = 0;
 	dev->output_panic = 0;
 	dev->first_packet = 1;
@@ -112,37 +118,35 @@
 	for (i = 0; i < N_URBS; i++) {
 		ret = usb_submit_urb(dev->data_urbs_in[i], GFP_ATOMIC);
 		if (ret) {
-			log("unable to trigger initial read #%d! (ret = %d)\n",
-				i, ret);
+			log("unable to trigger read #%d! (ret %d)\n", i, ret);
 			dev->streaming = 0;
-			spin_unlock_irq(&dev->spinlock);
 			return -EPIPE;
 		}
 	}
 	
-	spin_unlock_irq(&dev->spinlock);
 	return 0;
 }
 
 static void stream_stop(struct snd_usb_caiaqdev *dev)
 {
 	int i;
-	
-	debug("stream_stop(%p)\n", dev);
+
+	debug("%s(%p)\n", __func__, dev);
 	if (!dev->streaming)
 		return;
 	
 	dev->streaming = 0;
+
 	for (i = 0; i < N_URBS; i++) {
-		usb_unlink_urb(dev->data_urbs_in[i]);
-		usb_unlink_urb(dev->data_urbs_out[i]);
+		usb_kill_urb(dev->data_urbs_in[i]);
+		usb_kill_urb(dev->data_urbs_out[i]);
 	}
 }
 
 static int snd_usb_caiaq_substream_open(struct snd_pcm_substream *substream)
 {
 	struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(substream);
-	debug("snd_usb_caiaq_substream_open(%p)\n", substream);
+	debug("%s(%p)\n", __func__, substream);
 	substream->runtime->hw = dev->pcm_info;
 	snd_pcm_limit_hw_rates(substream->runtime);
 	return 0;
@@ -152,7 +156,7 @@
 {
 	struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(substream);
 
-	debug("snd_usb_caiaq_substream_close(%p)\n", substream);
+	debug("%s(%p)\n", __func__, substream);
 	if (all_substreams_zero(dev->sub_playback) &&
 	    all_substreams_zero(dev->sub_capture)) {
 		/* when the last client has stopped streaming, 
@@ -160,24 +164,22 @@
 		stream_stop(dev);
 		dev->pcm_info.rates = dev->samplerates;
 	}
-	
+
 	return 0;
 }
 
 static int snd_usb_caiaq_pcm_hw_params(struct snd_pcm_substream *sub,
 			     		struct snd_pcm_hw_params *hw_params)
 {
-	debug("snd_usb_caiaq_pcm_hw_params(%p)\n", sub);
+	debug("%s(%p)\n", __func__, sub);
 	return snd_pcm_lib_malloc_pages(sub, params_buffer_bytes(hw_params));
 }
 
 static int snd_usb_caiaq_pcm_hw_free(struct snd_pcm_substream *sub)
 {
 	struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub);
-	debug("snd_usb_caiaq_pcm_hw_free(%p)\n", sub);
-	spin_lock_irq(&dev->spinlock);
+	debug("%s(%p)\n", __func__, sub);
 	deactivate_substream(dev, sub);
-	spin_unlock_irq(&dev->spinlock);
 	return snd_pcm_lib_free_pages(sub);
 }
 
@@ -196,12 +198,12 @@
 	struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 
-	debug("snd_usb_caiaq_pcm_prepare(%p)\n", substream);
+	debug("%s(%p)\n", __func__, substream);
 	
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		dev->audio_out_buf_pos[index] = BYTES_PER_SAMPLE + 1;
 	else
-		dev->audio_in_buf_pos[index] = 0;
+		dev->audio_in_buf_pos[index] = BYTES_PER_SAMPLE;
 	
 	if (dev->streaming)
 		return 0;
@@ -220,7 +222,10 @@
 	
 	bpp = ((runtime->rate / 8000) + CLOCK_DRIFT_TOLERANCE)
 		* bytes_per_sample * CHANNELS_PER_STREAM * dev->n_streams;
-	
+
+	if (bpp > MAX_ENDPOINT_SIZE)
+		bpp = MAX_ENDPOINT_SIZE;
+
 	ret = snd_usb_caiaq_set_audio_params(dev, runtime->rate,
 					     runtime->sample_bits, bpp);
 	if (ret)
@@ -247,15 +252,11 @@
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		spin_lock(&dev->spinlock);
 		activate_substream(dev, sub);
-		spin_unlock(&dev->spinlock);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		spin_lock(&dev->spinlock);
 		deactivate_substream(dev, sub);
-		spin_unlock(&dev->spinlock);
 		break;
 	default:
 		return -EINVAL;
@@ -328,8 +329,6 @@
 	if (all_substreams_zero(dev->sub_capture))
 		return;
 
-	spin_lock(&dev->spinlock);
-	
 	for (i = 0; i < iso->actual_length;) {
 		for (stream = 0; stream < dev->n_streams; stream++, i++) {
 			sub = dev->sub_capture[stream];
@@ -345,8 +344,6 @@
 			}
 		}
 	}
-	
-	spin_unlock(&dev->spinlock);
 }
 
 static void read_in_urb_mode2(struct snd_usb_caiaqdev *dev,
@@ -358,8 +355,6 @@
 	struct snd_pcm_substream *sub;
 	int stream, i;
 
-	spin_lock(&dev->spinlock);
-	
 	for (i = 0; i < iso->actual_length;) {
 		if (i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == 0) {
 			for (stream = 0; 
@@ -393,8 +388,6 @@
 			}
 		}
 	}
-
-	spin_unlock(&dev->spinlock);
 }
 
 static void read_in_urb(struct snd_usb_caiaqdev *dev,
@@ -418,8 +411,6 @@
 				dev->input_panic ? "(input)" : "",
 				dev->output_panic ? "(output)" : "");
 	}
-
-	check_for_elapsed_periods(dev, dev->sub_capture);
 }
 
 static void fill_out_urb(struct snd_usb_caiaqdev *dev, 
@@ -429,8 +420,6 @@
 	unsigned char *usb_buf = urb->transfer_buffer + iso->offset;
 	struct snd_pcm_substream *sub;
 	int stream, i;
-
-	spin_lock(&dev->spinlock);
 	
 	for (i = 0; i < iso->length;) {
 		for (stream = 0; stream < dev->n_streams; stream++, i++) {
@@ -456,9 +445,6 @@
 		    for (stream = 0; stream < dev->n_streams; stream++, i++)
 		    	usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i);
 	}
-
-	spin_unlock(&dev->spinlock);
-	check_for_elapsed_periods(dev, dev->sub_playback);
 }
 
 static void read_completed(struct urb *urb)
@@ -472,6 +458,7 @@
 		return;
 
 	dev = info->dev;
+
 	if (!dev->streaming)
 		return;
 
@@ -489,8 +476,12 @@
 		out->iso_frame_desc[outframe].offset = BYTES_PER_FRAME * frame;
 		
 		if (len > 0) {
+			spin_lock(&dev->spinlock);
 			fill_out_urb(dev, out, &out->iso_frame_desc[outframe]);
 			read_in_urb(dev, urb, &urb->iso_frame_desc[frame]);
+			spin_unlock(&dev->spinlock);
+			check_for_elapsed_periods(dev, dev->sub_playback);
+			check_for_elapsed_periods(dev, dev->sub_capture);
 			send_it = 1;
 		}
 
@@ -696,7 +687,7 @@
 
 void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *dev)
 {
-	debug("snd_usb_caiaq_audio_free (%p)\n", dev);
+	debug("%s(%p)\n", __func__, dev);
 	stream_stop(dev);
 	free_urbs(dev->data_urbs_in);
 	free_urbs(dev->data_urbs_out);
diff --git a/sound/usb/caiaq/caiaq-device.c b/sound/usb/caiaq/caiaq-device.c
index 7c44a2c..e97d8b2 100644
--- a/sound/usb/caiaq/caiaq-device.c
+++ b/sound/usb/caiaq/caiaq-device.c
@@ -42,7 +42,7 @@
 #endif
 
 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
-MODULE_DESCRIPTION("caiaq USB audio, version 1.3.2");
+MODULE_DESCRIPTION("caiaq USB audio, version 1.3.6");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
 			 "{Native Instruments, RigKontrol3},"
@@ -456,7 +456,7 @@
 	struct snd_usb_caiaqdev *dev;
 	struct snd_card *card = dev_get_drvdata(&intf->dev);
 
-	debug("snd_disconnect(%p)\n", intf);
+	debug("%s(%p)\n", __func__, intf);
 
 	if (!card)
 		return;
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index f48838a..410be4a 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -64,9 +64,10 @@
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
-static int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Vendor ID for this card */
-static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Product ID for this card */
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */
+/* Vendor/product IDs for this card */
+static int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 };
+static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 };
 static int nrpacks = 8;		/* max. number of packets per urb */
 static int async_unlink = 1;
 static int device_setup[SNDRV_CARDS]; /* device parameter for this card*/
@@ -687,7 +688,7 @@
 	int err = 0;
 
 	if ((subs->running && subs->ops.retire(subs, substream->runtime, urb)) ||
-	    ! subs->running || /* can be stopped during retire callback */
+	    !subs->running || /* can be stopped during retire callback */
 	    (err = subs->ops.prepare(subs, substream->runtime, urb)) < 0 ||
 	    (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
 		clear_bit(ctx->index, &subs->active_mask);
@@ -710,7 +711,7 @@
 	int err = 0;
 
 	if ((subs->running && subs->ops.retire_sync(subs, substream->runtime, urb)) ||
-	    ! subs->running || /* can be stopped during retire callback */
+	    !subs->running || /* can be stopped during retire callback */
 	    (err = subs->ops.prepare_sync(subs, substream->runtime, urb)) < 0 ||
 	    (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
 		clear_bit(ctx->index + 16, &subs->active_mask);
@@ -740,7 +741,7 @@
 		vfree(runtime->dma_area);
 	}
 	runtime->dma_area = vmalloc(size);
-	if (! runtime->dma_area)
+	if (!runtime->dma_area)
 		return -ENOMEM;
 	runtime->dma_bytes = size;
 	return 0;
@@ -772,12 +773,12 @@
 
 	async = !can_sleep && async_unlink;
 
-	if (! async && in_interrupt())
+	if (!async && in_interrupt())
 		return 0;
 
 	for (i = 0; i < subs->nurbs; i++) {
 		if (test_bit(i, &subs->active_mask)) {
-			if (! test_and_set_bit(i, &subs->unlink_mask)) {
+			if (!test_and_set_bit(i, &subs->unlink_mask)) {
 				struct urb *u = subs->dataurb[i].urb;
 				if (async)
 					usb_unlink_urb(u);
@@ -789,7 +790,7 @@
 	if (subs->syncpipe) {
 		for (i = 0; i < SYNC_URBS; i++) {
 			if (test_bit(i+16, &subs->active_mask)) {
- 				if (! test_and_set_bit(i+16, &subs->unlink_mask)) {
+				if (!test_and_set_bit(i+16, &subs->unlink_mask)) {
 					struct urb *u = subs->syncurb[i].urb;
 					if (async)
 						usb_unlink_urb(u);
@@ -1137,12 +1138,12 @@
 		if (subs->fmt_type == USB_FORMAT_TYPE_II)
 			u->packets++; /* for transfer delimiter */
 		u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);
-		if (! u->urb)
+		if (!u->urb)
 			goto out_of_memory;
 		u->urb->transfer_buffer =
 			usb_buffer_alloc(subs->dev, u->buffer_size, GFP_KERNEL,
 					 &u->urb->transfer_dma);
-		if (! u->urb->transfer_buffer)
+		if (!u->urb->transfer_buffer)
 			goto out_of_memory;
 		u->urb->pipe = subs->datapipe;
 		u->urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
@@ -1155,7 +1156,7 @@
 		/* allocate and initialize sync urbs */
 		subs->syncbuf = usb_buffer_alloc(subs->dev, SYNC_URBS * 4,
 						 GFP_KERNEL, &subs->sync_dma);
-		if (! subs->syncbuf)
+		if (!subs->syncbuf)
 			goto out_of_memory;
 		for (i = 0; i < SYNC_URBS; i++) {
 			struct snd_urb_ctx *u = &subs->syncurb[i];
@@ -1163,7 +1164,7 @@
 			u->subs = subs;
 			u->packets = 1;
 			u->urb = usb_alloc_urb(1, GFP_KERNEL);
-			if (! u->urb)
+			if (!u->urb)
 				goto out_of_memory;
 			u->urb->transfer_buffer = subs->syncbuf + i * 4;
 			u->urb->transfer_dma = subs->sync_dma + i * 4;
@@ -1427,8 +1428,8 @@
 	subs->cur_audiofmt = fmt;
 
 #if 0
-	printk("setting done: format = %d, rate = %d, channels = %d\n",
-	       fmt->format, fmt->rate, fmt->channels);
+	printk("setting done: format = %d, rate = %d..%d, channels = %d\n",
+	       fmt->format, fmt->rate_min, fmt->rate_max, fmt->channels);
 	printk("  datapipe = 0x%0x, syncpipe = 0x%0x\n",
 	       subs->datapipe, subs->syncpipe);
 #endif
@@ -1463,7 +1464,7 @@
 	rate = params_rate(hw_params);
 	channels = params_channels(hw_params);
 	fmt = find_format(subs, format, rate, channels);
-	if (! fmt) {
+	if (!fmt) {
 		snd_printd(KERN_DEBUG "cannot set format: format = 0x%x, rate = %d, channels = %d\n",
 			   format, rate, channels);
 		return -EINVAL;
@@ -1584,7 +1585,7 @@
 	struct snd_mask *fmts = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
 
 	/* check the format */
-	if (! snd_mask_test(fmts, fp->format)) {
+	if (!snd_mask_test(fmts, fp->format)) {
 		hwc_debug("   > check: no supported format %d\n", fp->format);
 		return 0;
 	}
@@ -1620,7 +1621,7 @@
 	list_for_each(p, &subs->fmt_list) {
 		struct audioformat *fp;
 		fp = list_entry(p, struct audioformat, list);
-		if (! hw_check_valid_format(params, fp))
+		if (!hw_check_valid_format(params, fp))
 			continue;
 		if (changed++) {
 			if (rmin > fp->rate_min)
@@ -1633,7 +1634,7 @@
 		}
 	}
 
-	if (! changed) {
+	if (!changed) {
 		hwc_debug("  --> get empty\n");
 		it->empty = 1;
 		return -EINVAL;
@@ -1674,7 +1675,7 @@
 	list_for_each(p, &subs->fmt_list) {
 		struct audioformat *fp;
 		fp = list_entry(p, struct audioformat, list);
-		if (! hw_check_valid_format(params, fp))
+		if (!hw_check_valid_format(params, fp))
 			continue;
 		if (changed++) {
 			if (rmin > fp->channels)
@@ -1687,7 +1688,7 @@
 		}
 	}
 
-	if (! changed) {
+	if (!changed) {
 		hwc_debug("  --> get empty\n");
 		it->empty = 1;
 		return -EINVAL;
@@ -1727,7 +1728,7 @@
 	list_for_each(p, &subs->fmt_list) {
 		struct audioformat *fp;
 		fp = list_entry(p, struct audioformat, list);
-		if (! hw_check_valid_format(params, fp))
+		if (!hw_check_valid_format(params, fp))
 			continue;
 		fbits |= (1ULL << fp->format);
 	}
@@ -1736,7 +1737,7 @@
 	oldbits[1] = fmt->bits[1];
 	fmt->bits[0] &= (u32)fbits;
 	fmt->bits[1] &= (u32)(fbits >> 32);
-	if (! fmt->bits[0] && ! fmt->bits[1]) {
+	if (!fmt->bits[0] && !fmt->bits[1]) {
 		hwc_debug("  --> get empty\n");
 		return -EINVAL;
 	}
@@ -1762,8 +1763,10 @@
 
 	channels = kcalloc(MAX_MASK, sizeof(u32), GFP_KERNEL);
 	rates = kcalloc(MAX_MASK, sizeof(u32), GFP_KERNEL);
-	if (!channels || !rates)
+	if (!channels || !rates) {
+		err = -ENOMEM;
 		goto __out;
+	}
 
 	list_for_each(p, &subs->fmt_list) {
 		struct audioformat *f;
@@ -1916,7 +1919,10 @@
 				     1000 * MIN_PACKS_URB,
 				     /*(nrpacks * MAX_URBS) * 1000*/ UINT_MAX);
 
-	if (check_hw_params_convention(subs)) {
+	err = check_hw_params_convention(subs);
+	if (err < 0)
+		return err;
+	else if (err) {
 		hwc_debug("setting extra hw constraints...\n");
 		if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
 					       hw_rule_rate, subs,
@@ -2222,7 +2228,7 @@
 	struct snd_card *card = stream->chip->card;
 
 	sprintf(name, "stream%d", stream->pcm_index);
-	if (! snd_card_proc_new(card, name, &entry))
+	if (!snd_card_proc_new(card, name, &entry))
 		snd_info_set_text_ops(entry, stream, proc_pcm_format_read);
 }
 
@@ -2278,7 +2284,7 @@
 {
 	struct list_head *p, *n;
 
-	if (! subs->num_formats)
+	if (!subs->num_formats)
 		return; /* not initialized */
 	list_for_each_safe(p, n, &subs->fmt_list) {
 		struct audioformat *fp = list_entry(p, struct audioformat, list);
@@ -2328,7 +2334,7 @@
 		if (as->fmt_type != fp->fmt_type)
 			continue;
 		subs = &as->substream[stream];
-		if (! subs->endpoint)
+		if (!subs->endpoint)
 			continue;
 		if (subs->endpoint == fp->endpoint) {
 			list_add_tail(&fp->list, &subs->fmt_list);
@@ -2354,7 +2360,7 @@
 
 	/* create a new pcm */
 	as = kzalloc(sizeof(*as), GFP_KERNEL);
-	if (! as)
+	if (!as)
 		return -ENOMEM;
 	as->pcm_index = chip->pcm_devs;
 	as->chip = chip;
@@ -2463,11 +2469,12 @@
 		}
 		break;
 	case USB_AUDIO_FORMAT_PCM8:
-		/* Dallas DS4201 workaround */
+		pcm_format = SNDRV_PCM_FORMAT_U8;
+
+		/* Dallas DS4201 workaround: it advertises U8 format, but really
+		   supports S8. */
 		if (chip->usb_id == USB_ID(0x04fa, 0x4201))
 			pcm_format = SNDRV_PCM_FORMAT_S8;
-		else
-			pcm_format = SNDRV_PCM_FORMAT_U8;
 		break;
 	case USB_AUDIO_FORMAT_IEEE_FLOAT:
 		pcm_format = SNDRV_PCM_FORMAT_FLOAT_LE;
@@ -2671,12 +2678,23 @@
 	int format;
 	struct audioformat *fp;
 	unsigned char *fmt, *csep;
+	int num;
 
 	dev = chip->dev;
 
 	/* parse the interface's altsettings */
 	iface = usb_ifnum_to_if(dev, iface_no);
-	for (i = 0; i < iface->num_altsetting; i++) {
+
+	num = iface->num_altsetting;
+
+	/*
+	 * Dallas DS4201 workaround: It presents 5 altsettings, but the last
+	 * one misses syncpipe, and does not produce any sound.
+	 */
+	if (chip->usb_id == USB_ID(0x04fa, 0x4201))
+		num = 4;
+
+	for (i = 0; i < num; i++) {
 		alts = &iface->altsetting[i];
 		altsd = get_iface_desc(alts);
 		/* skip invalid one */
@@ -3375,14 +3393,14 @@
 static void proc_audio_usbbus_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 {
 	struct snd_usb_audio *chip = entry->private_data;
-	if (! chip->shutdown)
+	if (!chip->shutdown)
 		snd_iprintf(buffer, "%03d/%03d\n", chip->dev->bus->busnum, chip->dev->devnum);
 }
 
 static void proc_audio_usbid_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 {
 	struct snd_usb_audio *chip = entry->private_data;
-	if (! chip->shutdown)
+	if (!chip->shutdown)
 		snd_iprintf(buffer, "%04x:%04x\n", 
 			    USB_ID_VENDOR(chip->usb_id),
 			    USB_ID_PRODUCT(chip->usb_id));
@@ -3391,9 +3409,9 @@
 static void snd_usb_audio_create_proc(struct snd_usb_audio *chip)
 {
 	struct snd_info_entry *entry;
-	if (! snd_card_proc_new(chip->card, "usbbus", &entry))
+	if (!snd_card_proc_new(chip->card, "usbbus", &entry))
 		snd_info_set_text_ops(entry, chip, proc_audio_usbbus_read);
-	if (! snd_card_proc_new(chip->card, "usbid", &entry))
+	if (!snd_card_proc_new(chip->card, "usbid", &entry))
 		snd_info_set_text_ops(entry, chip, proc_audio_usbid_read);
 }
 
@@ -3406,7 +3424,6 @@
 
 static int snd_usb_audio_free(struct snd_usb_audio *chip)
 {
-	usb_chip[chip->index] = NULL;
 	kfree(chip);
 	return 0;
 }
@@ -3600,8 +3617,8 @@
 				snd_card_set_dev(chip->card, &intf->dev);
 				break;
 			}
-		if (! chip) {
-			snd_printk(KERN_ERR "no available usb audio device\n");
+		if (!chip) {
+			printk(KERN_ERR "no available usb audio device\n");
 			goto __error;
 		}
 	}
@@ -3671,6 +3688,7 @@
 		list_for_each(p, &chip->mixer_list) {
 			snd_usb_mixer_disconnect(p);
 		}
+		usb_chip[chip->index] = NULL;
 		mutex_unlock(&register_mutex);
 		snd_card_free_when_closed(card);
 	} else {
diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h
index 938dff5..82a8d14 100644
--- a/sound/usb/usbquirks.h
+++ b/sound/usb/usbquirks.h
@@ -39,6 +39,30 @@
 	.idProduct = prod, \
 	.bInterfaceClass = USB_CLASS_VENDOR_SPEC
 
+/* Creative/E-Mu devices */
+{
+	USB_DEVICE(0x041e, 0x3010),
+	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+		.vendor_name = "Creative Labs",
+		.product_name = "Sound Blaster MP3+",
+		.ifnum = QUIRK_NO_INTERFACE
+	}
+},
+{
+	/* E-Mu 0202 USB */
+	.match_flags = USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor = 0x041e,
+	.idProduct = 0x3f02,
+	.bInterfaceClass = USB_CLASS_AUDIO,
+},
+{
+	/* E-Mu 0404 USB */
+	.match_flags = USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor = 0x041e,
+	.idProduct = 0x3f04,
+	.bInterfaceClass = USB_CLASS_AUDIO,
+},
+
 /*
  * Logitech QuickCam: bDeviceClass is vendor-specific, so generic interface
  * class matches do not take effect without an explicit ID match.
@@ -97,19 +121,7 @@
 	.bInterfaceClass = USB_CLASS_AUDIO,
 	.bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL
 },
-/* E-Mu devices */
-{
-	.match_flags = USB_DEVICE_ID_MATCH_DEVICE,
-	.idVendor = 0x041e,
-	.idProduct = 0x3f02,
-	.bInterfaceClass = USB_CLASS_AUDIO,
-},
-{
-	.match_flags = USB_DEVICE_ID_MATCH_DEVICE,
-	.idVendor = 0x041e,
-	.idProduct = 0x3f04,
-	.bInterfaceClass = USB_CLASS_AUDIO,
-},
+
 /*
  * Yamaha devices
  */
@@ -1165,19 +1177,6 @@
 		}
 	}
 },
-{
-	USB_DEVICE(0x582, 0x00a6),
-	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-		.vendor_name = "Roland",
-		.product_name = "Juno-G",
-		.ifnum = 0,
-		.type = QUIRK_MIDI_FIXED_ENDPOINT,
-		.data = & (const struct snd_usb_midi_endpoint_info) {
-			.out_cables = 0x0001,
-			.in_cables  = 0x0001
-		}
-	}
-},
 {	/*
 	 * This quirk is for the "Advanced" modes of the Edirol UA-25.
 	 * If the switch is not in an advanced setting, the UA-25 has
@@ -1336,6 +1335,19 @@
 },
 	/* TODO: add Edirol MD-P1 support */
 {
+	USB_DEVICE(0x582, 0x00a6),
+	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+		.vendor_name = "Roland",
+		.product_name = "Juno-G",
+		.ifnum = 0,
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const struct snd_usb_midi_endpoint_info) {
+			.out_cables = 0x0001,
+			.in_cables  = 0x0001
+		}
+	}
+},
+{
 	/* Roland SH-201 */
 	USB_DEVICE(0x0582, 0x00ad),
 	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
@@ -1719,17 +1731,6 @@
 	}
 },
 
-{
-	/* Creative Sound Blaster MP3+ */
-	USB_DEVICE(0x041e, 0x3010),
-	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-		.vendor_name = "Creative Labs",
-		.product_name = "Sound Blaster MP3+",
-		.ifnum = QUIRK_NO_INTERFACE
-	}
-	
-},
-
 /* Emagic devices */
 {
 	USB_DEVICE(0x086a, 0x0001),